Update audio_processing module
Corresponds to upstream commit 524e9b043e7e86fd72353b987c9d5f6a1ebf83e1 Update notes: * Pull in third party license file * Replace .gypi files with BUILD.gn to keep track of what changes upstream * Bunch of new filse pulled in as dependencies * Won't build yet due to changes needed on top of these
This commit is contained in:
@@ -1 +1 @@
|
||||
SUBDIRS = audio_processing
|
||||
SUBDIRS = audio_coding audio_processing
|
||||
|
||||
835
webrtc/modules/audio_coding/BUILD.gn
Normal file
835
webrtc/modules/audio_coding/BUILD.gn
Normal file
@@ -0,0 +1,835 @@
|
||||
# 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("audio_coding_config") {
|
||||
include_dirs = [
|
||||
"main/interface",
|
||||
"../interface",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("audio_coding") {
|
||||
sources = [
|
||||
"main/acm2/acm_codec_database.cc",
|
||||
"main/acm2/acm_codec_database.h",
|
||||
"main/acm2/acm_common_defs.h",
|
||||
"main/acm2/acm_receiver.cc",
|
||||
"main/acm2/acm_receiver.h",
|
||||
"main/acm2/acm_resampler.cc",
|
||||
"main/acm2/acm_resampler.h",
|
||||
"main/acm2/audio_coding_module.cc",
|
||||
"main/acm2/audio_coding_module_impl.cc",
|
||||
"main/acm2/audio_coding_module_impl.h",
|
||||
"main/acm2/call_statistics.cc",
|
||||
"main/acm2/call_statistics.h",
|
||||
"main/acm2/codec_manager.cc",
|
||||
"main/acm2/codec_manager.h",
|
||||
"main/acm2/codec_owner.cc",
|
||||
"main/acm2/codec_owner.h",
|
||||
"main/acm2/initial_delay_manager.cc",
|
||||
"main/acm2/initial_delay_manager.h",
|
||||
"main/acm2/nack.cc",
|
||||
"main/acm2/nack.h",
|
||||
"main/interface/audio_coding_module.h",
|
||||
"main/interface/audio_coding_module_typedefs.h",
|
||||
]
|
||||
|
||||
defines = []
|
||||
|
||||
configs += [ "../..:common_config" ]
|
||||
|
||||
public_configs = [
|
||||
"../..:common_inherited_config",
|
||||
":audio_coding_config",
|
||||
]
|
||||
|
||||
if (is_win) {
|
||||
cflags = [
|
||||
# TODO(kjellander): Bug 261: fix this warning.
|
||||
"/wd4373", # virtual function override.
|
||||
]
|
||||
}
|
||||
|
||||
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" ]
|
||||
}
|
||||
|
||||
deps = [
|
||||
":cng",
|
||||
":g711",
|
||||
":neteq",
|
||||
":pcm16b",
|
||||
"../..:rtc_event_log",
|
||||
"../..:webrtc_common",
|
||||
"../../common_audio",
|
||||
"../../system_wrappers",
|
||||
]
|
||||
|
||||
if (rtc_include_opus) {
|
||||
defines += [ "WEBRTC_CODEC_OPUS" ]
|
||||
deps += [ ":webrtc_opus" ]
|
||||
}
|
||||
if (!build_with_mozilla) {
|
||||
if (current_cpu == "arm") {
|
||||
defines += [ "WEBRTC_CODEC_ISACFX" ]
|
||||
deps += [ ":isac_fix" ]
|
||||
} else {
|
||||
defines += [ "WEBRTC_CODEC_ISAC" ]
|
||||
deps += [ ":isac" ]
|
||||
}
|
||||
defines += [ "WEBRTC_CODEC_G722" ]
|
||||
deps += [ ":g722" ]
|
||||
}
|
||||
if (!build_with_mozilla && !build_with_chromium) {
|
||||
defines += [
|
||||
"WEBRTC_CODEC_ILBC",
|
||||
"WEBRTC_CODEC_RED",
|
||||
]
|
||||
deps += [
|
||||
":ilbc",
|
||||
":red",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
source_set("audio_decoder_interface") {
|
||||
sources = [
|
||||
"codecs/audio_decoder.cc",
|
||||
"codecs/audio_decoder.h",
|
||||
]
|
||||
configs += [ "../..:common_config" ]
|
||||
public_configs = [ "../..:common_inherited_config" ]
|
||||
deps = [
|
||||
"../..:webrtc_common",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("audio_encoder_interface") {
|
||||
sources = [
|
||||
"codecs/audio_encoder.cc",
|
||||
"codecs/audio_encoder.h",
|
||||
]
|
||||
configs += [ "../..:common_config" ]
|
||||
public_configs = [ "../..:common_inherited_config" ]
|
||||
deps = [
|
||||
"../..:webrtc_common",
|
||||
]
|
||||
}
|
||||
|
||||
config("cng_config") {
|
||||
include_dirs = [
|
||||
"../../..",
|
||||
"codecs/cng/include",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("cng") {
|
||||
sources = [
|
||||
"codecs/cng/audio_encoder_cng.cc",
|
||||
"codecs/cng/cng_helpfuns.c",
|
||||
"codecs/cng/cng_helpfuns.h",
|
||||
"codecs/cng/include/audio_encoder_cng.h",
|
||||
"codecs/cng/include/webrtc_cng.h",
|
||||
"codecs/cng/webrtc_cng.c",
|
||||
]
|
||||
|
||||
configs += [ "../..:common_config" ]
|
||||
|
||||
public_configs = [
|
||||
"../..:common_inherited_config",
|
||||
":cng_config",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"../../common_audio",
|
||||
":audio_encoder_interface",
|
||||
]
|
||||
}
|
||||
|
||||
config("red_config") {
|
||||
include_dirs = [ "codecs/red" ]
|
||||
}
|
||||
|
||||
source_set("red") {
|
||||
sources = [
|
||||
"codecs/red/audio_encoder_copy_red.cc",
|
||||
"codecs/red/audio_encoder_copy_red.h",
|
||||
]
|
||||
|
||||
configs += [ "../..:common_config" ]
|
||||
|
||||
public_configs = [
|
||||
"../..:common_inherited_config",
|
||||
":red_config",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"../../common_audio",
|
||||
":audio_encoder_interface",
|
||||
]
|
||||
}
|
||||
|
||||
config("g711_config") {
|
||||
include_dirs = [
|
||||
"../../..",
|
||||
"codecs/g711/include",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("g711") {
|
||||
sources = [
|
||||
"codecs/g711/audio_decoder_pcm.cc",
|
||||
"codecs/g711/audio_encoder_pcm.cc",
|
||||
"codecs/g711/g711.c",
|
||||
"codecs/g711/g711.h",
|
||||
"codecs/g711/g711_interface.c",
|
||||
"codecs/g711/include/audio_decoder_pcm.h",
|
||||
"codecs/g711/include/audio_encoder_pcm.h",
|
||||
"codecs/g711/include/g711_interface.h",
|
||||
]
|
||||
|
||||
configs += [ "../..:common_config" ]
|
||||
|
||||
public_configs = [
|
||||
"../..:common_inherited_config",
|
||||
":g711_config",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":audio_encoder_interface",
|
||||
]
|
||||
}
|
||||
|
||||
config("g722_config") {
|
||||
include_dirs = [
|
||||
"../../..",
|
||||
"codecs/g722/include",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("g722") {
|
||||
sources = [
|
||||
"codecs/g722/audio_decoder_g722.cc",
|
||||
"codecs/g722/audio_encoder_g722.cc",
|
||||
"codecs/g722/g722_decode.c",
|
||||
"codecs/g722/g722_enc_dec.h",
|
||||
"codecs/g722/g722_encode.c",
|
||||
"codecs/g722/g722_interface.c",
|
||||
"codecs/g722/include/audio_decoder_g722.h",
|
||||
"codecs/g722/include/audio_encoder_g722.h",
|
||||
"codecs/g722/include/g722_interface.h",
|
||||
]
|
||||
|
||||
configs += [ "../..:common_config" ]
|
||||
|
||||
public_configs = [
|
||||
"../..:common_inherited_config",
|
||||
":g722_config",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":audio_encoder_interface",
|
||||
]
|
||||
}
|
||||
|
||||
config("ilbc_config") {
|
||||
include_dirs = [
|
||||
"../../..",
|
||||
"codecs/ilbc/interface",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("ilbc") {
|
||||
sources = [
|
||||
"codecs/ilbc/abs_quant.c",
|
||||
"codecs/ilbc/abs_quant.h",
|
||||
"codecs/ilbc/abs_quant_loop.c",
|
||||
"codecs/ilbc/abs_quant_loop.h",
|
||||
"codecs/ilbc/audio_decoder_ilbc.cc",
|
||||
"codecs/ilbc/audio_encoder_ilbc.cc",
|
||||
"codecs/ilbc/augmented_cb_corr.c",
|
||||
"codecs/ilbc/augmented_cb_corr.h",
|
||||
"codecs/ilbc/bw_expand.c",
|
||||
"codecs/ilbc/bw_expand.h",
|
||||
"codecs/ilbc/cb_construct.c",
|
||||
"codecs/ilbc/cb_construct.h",
|
||||
"codecs/ilbc/cb_mem_energy.c",
|
||||
"codecs/ilbc/cb_mem_energy.h",
|
||||
"codecs/ilbc/cb_mem_energy_augmentation.c",
|
||||
"codecs/ilbc/cb_mem_energy_augmentation.h",
|
||||
"codecs/ilbc/cb_mem_energy_calc.c",
|
||||
"codecs/ilbc/cb_mem_energy_calc.h",
|
||||
"codecs/ilbc/cb_search.c",
|
||||
"codecs/ilbc/cb_search.h",
|
||||
"codecs/ilbc/cb_search_core.c",
|
||||
"codecs/ilbc/cb_search_core.h",
|
||||
"codecs/ilbc/cb_update_best_index.c",
|
||||
"codecs/ilbc/cb_update_best_index.h",
|
||||
"codecs/ilbc/chebyshev.c",
|
||||
"codecs/ilbc/chebyshev.h",
|
||||
"codecs/ilbc/comp_corr.c",
|
||||
"codecs/ilbc/comp_corr.h",
|
||||
"codecs/ilbc/constants.c",
|
||||
"codecs/ilbc/constants.h",
|
||||
"codecs/ilbc/create_augmented_vec.c",
|
||||
"codecs/ilbc/create_augmented_vec.h",
|
||||
"codecs/ilbc/decode.c",
|
||||
"codecs/ilbc/decode.h",
|
||||
"codecs/ilbc/decode_residual.c",
|
||||
"codecs/ilbc/decode_residual.h",
|
||||
"codecs/ilbc/decoder_interpolate_lsf.c",
|
||||
"codecs/ilbc/decoder_interpolate_lsf.h",
|
||||
"codecs/ilbc/defines.h",
|
||||
"codecs/ilbc/do_plc.c",
|
||||
"codecs/ilbc/do_plc.h",
|
||||
"codecs/ilbc/encode.c",
|
||||
"codecs/ilbc/encode.h",
|
||||
"codecs/ilbc/energy_inverse.c",
|
||||
"codecs/ilbc/energy_inverse.h",
|
||||
"codecs/ilbc/enh_upsample.c",
|
||||
"codecs/ilbc/enh_upsample.h",
|
||||
"codecs/ilbc/enhancer.c",
|
||||
"codecs/ilbc/enhancer.h",
|
||||
"codecs/ilbc/enhancer_interface.c",
|
||||
"codecs/ilbc/enhancer_interface.h",
|
||||
"codecs/ilbc/filtered_cb_vecs.c",
|
||||
"codecs/ilbc/filtered_cb_vecs.h",
|
||||
"codecs/ilbc/frame_classify.c",
|
||||
"codecs/ilbc/frame_classify.h",
|
||||
"codecs/ilbc/gain_dequant.c",
|
||||
"codecs/ilbc/gain_dequant.h",
|
||||
"codecs/ilbc/gain_quant.c",
|
||||
"codecs/ilbc/gain_quant.h",
|
||||
"codecs/ilbc/get_cd_vec.c",
|
||||
"codecs/ilbc/get_cd_vec.h",
|
||||
"codecs/ilbc/get_lsp_poly.c",
|
||||
"codecs/ilbc/get_lsp_poly.h",
|
||||
"codecs/ilbc/get_sync_seq.c",
|
||||
"codecs/ilbc/get_sync_seq.h",
|
||||
"codecs/ilbc/hp_input.c",
|
||||
"codecs/ilbc/hp_input.h",
|
||||
"codecs/ilbc/hp_output.c",
|
||||
"codecs/ilbc/hp_output.h",
|
||||
"codecs/ilbc/ilbc.c",
|
||||
"codecs/ilbc/include/audio_decoder_ilbc.h",
|
||||
"codecs/ilbc/include/audio_encoder_ilbc.h",
|
||||
"codecs/ilbc/index_conv_dec.c",
|
||||
"codecs/ilbc/index_conv_dec.h",
|
||||
"codecs/ilbc/index_conv_enc.c",
|
||||
"codecs/ilbc/index_conv_enc.h",
|
||||
"codecs/ilbc/init_decode.c",
|
||||
"codecs/ilbc/init_decode.h",
|
||||
"codecs/ilbc/init_encode.c",
|
||||
"codecs/ilbc/init_encode.h",
|
||||
"codecs/ilbc/interface/ilbc.h",
|
||||
"codecs/ilbc/interpolate.c",
|
||||
"codecs/ilbc/interpolate.h",
|
||||
"codecs/ilbc/interpolate_samples.c",
|
||||
"codecs/ilbc/interpolate_samples.h",
|
||||
"codecs/ilbc/lpc_encode.c",
|
||||
"codecs/ilbc/lpc_encode.h",
|
||||
"codecs/ilbc/lsf_check.c",
|
||||
"codecs/ilbc/lsf_check.h",
|
||||
"codecs/ilbc/lsf_interpolate_to_poly_dec.c",
|
||||
"codecs/ilbc/lsf_interpolate_to_poly_dec.h",
|
||||
"codecs/ilbc/lsf_interpolate_to_poly_enc.c",
|
||||
"codecs/ilbc/lsf_interpolate_to_poly_enc.h",
|
||||
"codecs/ilbc/lsf_to_lsp.c",
|
||||
"codecs/ilbc/lsf_to_lsp.h",
|
||||
"codecs/ilbc/lsf_to_poly.c",
|
||||
"codecs/ilbc/lsf_to_poly.h",
|
||||
"codecs/ilbc/lsp_to_lsf.c",
|
||||
"codecs/ilbc/lsp_to_lsf.h",
|
||||
"codecs/ilbc/my_corr.c",
|
||||
"codecs/ilbc/my_corr.h",
|
||||
"codecs/ilbc/nearest_neighbor.c",
|
||||
"codecs/ilbc/nearest_neighbor.h",
|
||||
"codecs/ilbc/pack_bits.c",
|
||||
"codecs/ilbc/pack_bits.h",
|
||||
"codecs/ilbc/poly_to_lsf.c",
|
||||
"codecs/ilbc/poly_to_lsf.h",
|
||||
"codecs/ilbc/poly_to_lsp.c",
|
||||
"codecs/ilbc/poly_to_lsp.h",
|
||||
"codecs/ilbc/refiner.c",
|
||||
"codecs/ilbc/refiner.h",
|
||||
"codecs/ilbc/simple_interpolate_lsf.c",
|
||||
"codecs/ilbc/simple_interpolate_lsf.h",
|
||||
"codecs/ilbc/simple_lpc_analysis.c",
|
||||
"codecs/ilbc/simple_lpc_analysis.h",
|
||||
"codecs/ilbc/simple_lsf_dequant.c",
|
||||
"codecs/ilbc/simple_lsf_dequant.h",
|
||||
"codecs/ilbc/simple_lsf_quant.c",
|
||||
"codecs/ilbc/simple_lsf_quant.h",
|
||||
"codecs/ilbc/smooth.c",
|
||||
"codecs/ilbc/smooth.h",
|
||||
"codecs/ilbc/smooth_out_data.c",
|
||||
"codecs/ilbc/smooth_out_data.h",
|
||||
"codecs/ilbc/sort_sq.c",
|
||||
"codecs/ilbc/sort_sq.h",
|
||||
"codecs/ilbc/split_vq.c",
|
||||
"codecs/ilbc/split_vq.h",
|
||||
"codecs/ilbc/state_construct.c",
|
||||
"codecs/ilbc/state_construct.h",
|
||||
"codecs/ilbc/state_search.c",
|
||||
"codecs/ilbc/state_search.h",
|
||||
"codecs/ilbc/swap_bytes.c",
|
||||
"codecs/ilbc/swap_bytes.h",
|
||||
"codecs/ilbc/unpack_bits.c",
|
||||
"codecs/ilbc/unpack_bits.h",
|
||||
"codecs/ilbc/vq3.c",
|
||||
"codecs/ilbc/vq3.h",
|
||||
"codecs/ilbc/vq4.c",
|
||||
"codecs/ilbc/vq4.h",
|
||||
"codecs/ilbc/window32_w32.c",
|
||||
"codecs/ilbc/window32_w32.h",
|
||||
"codecs/ilbc/xcorr_coef.c",
|
||||
"codecs/ilbc/xcorr_coef.h",
|
||||
]
|
||||
|
||||
configs += [ "../..:common_config" ]
|
||||
|
||||
public_configs = [
|
||||
"../..:common_inherited_config",
|
||||
":ilbc_config",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"../../common_audio",
|
||||
":audio_encoder_interface",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("isac_common") {
|
||||
sources = [
|
||||
"codecs/isac/audio_encoder_isac_t.h",
|
||||
"codecs/isac/audio_encoder_isac_t_impl.h",
|
||||
"codecs/isac/locked_bandwidth_info.cc",
|
||||
"codecs/isac/locked_bandwidth_info.h",
|
||||
]
|
||||
public_configs = [ "../..:common_inherited_config" ]
|
||||
}
|
||||
|
||||
config("isac_config") {
|
||||
include_dirs = [
|
||||
"../../..",
|
||||
"codecs/isac/main/interface",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("isac") {
|
||||
sources = [
|
||||
"codecs/isac/main/interface/audio_decoder_isac.h",
|
||||
"codecs/isac/main/interface/audio_encoder_isac.h",
|
||||
"codecs/isac/main/interface/isac.h",
|
||||
"codecs/isac/main/source/arith_routines.c",
|
||||
"codecs/isac/main/source/arith_routines.h",
|
||||
"codecs/isac/main/source/arith_routines_hist.c",
|
||||
"codecs/isac/main/source/arith_routines_logist.c",
|
||||
"codecs/isac/main/source/audio_decoder_isac.cc",
|
||||
"codecs/isac/main/source/audio_encoder_isac.cc",
|
||||
"codecs/isac/main/source/bandwidth_estimator.c",
|
||||
"codecs/isac/main/source/bandwidth_estimator.h",
|
||||
"codecs/isac/main/source/codec.h",
|
||||
"codecs/isac/main/source/crc.c",
|
||||
"codecs/isac/main/source/crc.h",
|
||||
"codecs/isac/main/source/decode.c",
|
||||
"codecs/isac/main/source/decode_bwe.c",
|
||||
"codecs/isac/main/source/encode.c",
|
||||
"codecs/isac/main/source/encode_lpc_swb.c",
|
||||
"codecs/isac/main/source/encode_lpc_swb.h",
|
||||
"codecs/isac/main/source/entropy_coding.c",
|
||||
"codecs/isac/main/source/entropy_coding.h",
|
||||
"codecs/isac/main/source/fft.c",
|
||||
"codecs/isac/main/source/fft.h",
|
||||
"codecs/isac/main/source/filter_functions.c",
|
||||
"codecs/isac/main/source/filterbank_tables.c",
|
||||
"codecs/isac/main/source/filterbank_tables.h",
|
||||
"codecs/isac/main/source/filterbanks.c",
|
||||
"codecs/isac/main/source/intialize.c",
|
||||
"codecs/isac/main/source/isac.c",
|
||||
"codecs/isac/main/source/isac_float_type.h",
|
||||
"codecs/isac/main/source/lattice.c",
|
||||
"codecs/isac/main/source/lpc_analysis.c",
|
||||
"codecs/isac/main/source/lpc_analysis.h",
|
||||
"codecs/isac/main/source/lpc_gain_swb_tables.c",
|
||||
"codecs/isac/main/source/lpc_gain_swb_tables.h",
|
||||
"codecs/isac/main/source/lpc_shape_swb12_tables.c",
|
||||
"codecs/isac/main/source/lpc_shape_swb12_tables.h",
|
||||
"codecs/isac/main/source/lpc_shape_swb16_tables.c",
|
||||
"codecs/isac/main/source/lpc_shape_swb16_tables.h",
|
||||
"codecs/isac/main/source/lpc_tables.c",
|
||||
"codecs/isac/main/source/lpc_tables.h",
|
||||
"codecs/isac/main/source/os_specific_inline.h",
|
||||
"codecs/isac/main/source/pitch_estimator.c",
|
||||
"codecs/isac/main/source/pitch_estimator.h",
|
||||
"codecs/isac/main/source/pitch_filter.c",
|
||||
"codecs/isac/main/source/pitch_gain_tables.c",
|
||||
"codecs/isac/main/source/pitch_gain_tables.h",
|
||||
"codecs/isac/main/source/pitch_lag_tables.c",
|
||||
"codecs/isac/main/source/pitch_lag_tables.h",
|
||||
"codecs/isac/main/source/settings.h",
|
||||
"codecs/isac/main/source/spectrum_ar_model_tables.c",
|
||||
"codecs/isac/main/source/spectrum_ar_model_tables.h",
|
||||
"codecs/isac/main/source/structs.h",
|
||||
"codecs/isac/main/source/transform.c",
|
||||
]
|
||||
|
||||
if (is_linux) {
|
||||
libs = [ "m" ]
|
||||
}
|
||||
|
||||
configs += [ "../..:common_config" ]
|
||||
|
||||
public_configs = [
|
||||
"../..:common_inherited_config",
|
||||
":isac_config",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":audio_decoder_interface",
|
||||
":audio_encoder_interface",
|
||||
":isac_common",
|
||||
"../../common_audio",
|
||||
]
|
||||
}
|
||||
|
||||
config("isac_fix_config") {
|
||||
include_dirs = [
|
||||
"../../..",
|
||||
"codecs/isac/fix/interface",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("isac_fix") {
|
||||
sources = [
|
||||
"codecs/isac/fix/interface/audio_decoder_isacfix.h",
|
||||
"codecs/isac/fix/interface/audio_encoder_isacfix.h",
|
||||
"codecs/isac/fix/interface/isacfix.h",
|
||||
"codecs/isac/fix/source/arith_routines.c",
|
||||
"codecs/isac/fix/source/arith_routines_hist.c",
|
||||
"codecs/isac/fix/source/arith_routines_logist.c",
|
||||
"codecs/isac/fix/source/arith_routins.h",
|
||||
"codecs/isac/fix/source/audio_decoder_isacfix.cc",
|
||||
"codecs/isac/fix/source/audio_encoder_isacfix.cc",
|
||||
"codecs/isac/fix/source/bandwidth_estimator.c",
|
||||
"codecs/isac/fix/source/bandwidth_estimator.h",
|
||||
"codecs/isac/fix/source/codec.h",
|
||||
"codecs/isac/fix/source/decode.c",
|
||||
"codecs/isac/fix/source/decode_bwe.c",
|
||||
"codecs/isac/fix/source/decode_plc.c",
|
||||
"codecs/isac/fix/source/encode.c",
|
||||
"codecs/isac/fix/source/entropy_coding.c",
|
||||
"codecs/isac/fix/source/entropy_coding.h",
|
||||
"codecs/isac/fix/source/fft.c",
|
||||
"codecs/isac/fix/source/fft.h",
|
||||
"codecs/isac/fix/source/filterbank_tables.c",
|
||||
"codecs/isac/fix/source/filterbank_tables.h",
|
||||
"codecs/isac/fix/source/filterbanks.c",
|
||||
"codecs/isac/fix/source/filters.c",
|
||||
"codecs/isac/fix/source/initialize.c",
|
||||
"codecs/isac/fix/source/isac_fix_type.h",
|
||||
"codecs/isac/fix/source/isacfix.c",
|
||||
"codecs/isac/fix/source/lattice.c",
|
||||
"codecs/isac/fix/source/lattice_c.c",
|
||||
"codecs/isac/fix/source/lpc_masking_model.c",
|
||||
"codecs/isac/fix/source/lpc_masking_model.h",
|
||||
"codecs/isac/fix/source/lpc_tables.c",
|
||||
"codecs/isac/fix/source/lpc_tables.h",
|
||||
"codecs/isac/fix/source/pitch_estimator.c",
|
||||
"codecs/isac/fix/source/pitch_estimator.h",
|
||||
"codecs/isac/fix/source/pitch_estimator_c.c",
|
||||
"codecs/isac/fix/source/pitch_filter.c",
|
||||
"codecs/isac/fix/source/pitch_filter_c.c",
|
||||
"codecs/isac/fix/source/pitch_gain_tables.c",
|
||||
"codecs/isac/fix/source/pitch_gain_tables.h",
|
||||
"codecs/isac/fix/source/pitch_lag_tables.c",
|
||||
"codecs/isac/fix/source/pitch_lag_tables.h",
|
||||
"codecs/isac/fix/source/settings.h",
|
||||
"codecs/isac/fix/source/spectrum_ar_model_tables.c",
|
||||
"codecs/isac/fix/source/spectrum_ar_model_tables.h",
|
||||
"codecs/isac/fix/source/structs.h",
|
||||
"codecs/isac/fix/source/transform.c",
|
||||
"codecs/isac/fix/source/transform_tables.c",
|
||||
]
|
||||
|
||||
if (!is_win) {
|
||||
defines = [ "WEBRTC_LINUX" ]
|
||||
}
|
||||
|
||||
configs += [ "../..:common_config" ]
|
||||
|
||||
public_configs = [
|
||||
"../..:common_inherited_config",
|
||||
":isac_fix_config",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":audio_encoder_interface",
|
||||
":isac_common",
|
||||
"../../common_audio",
|
||||
"../../system_wrappers",
|
||||
]
|
||||
|
||||
if (rtc_build_with_neon) {
|
||||
deps += [ ":isac_neon" ]
|
||||
}
|
||||
|
||||
if (current_cpu == "arm" && arm_version >= 7) {
|
||||
sources += [
|
||||
"codecs/isac/fix/source/lattice_armv7.S",
|
||||
"codecs/isac/fix/source/pitch_filter_armv6.S",
|
||||
]
|
||||
sources -= [
|
||||
"codecs/isac/fix/source/lattice_c.c",
|
||||
"codecs/isac/fix/source/pitch_filter_c.c",
|
||||
]
|
||||
}
|
||||
|
||||
if (current_cpu == "mipsel") {
|
||||
sources += [
|
||||
"codecs/isac/fix/source/entropy_coding_mips.c",
|
||||
"codecs/isac/fix/source/filters_mips.c",
|
||||
"codecs/isac/fix/source/lattice_mips.c",
|
||||
"codecs/isac/fix/source/pitch_estimator_mips.c",
|
||||
"codecs/isac/fix/source/transform_mips.c",
|
||||
]
|
||||
sources -= [
|
||||
"codecs/isac/fix/source/lattice_c.c",
|
||||
"codecs/isac/fix/source/pitch_estimator_c.c",
|
||||
]
|
||||
if (mips_dsp_rev > 0) {
|
||||
sources += [ "codecs/isac/fix/source/filterbanks_mips.c" ]
|
||||
}
|
||||
if (mips_dsp_rev > 1) {
|
||||
sources += [
|
||||
"codecs/isac/fix/source/lpc_masking_model_mips.c",
|
||||
"codecs/isac/fix/source/pitch_filter_mips.c",
|
||||
]
|
||||
sources -= [ "codecs/isac/fix/source/pitch_filter_c.c" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rtc_build_with_neon) {
|
||||
source_set("isac_neon") {
|
||||
sources = [
|
||||
"codecs/isac/fix/source/entropy_coding_neon.c",
|
||||
"codecs/isac/fix/source/filterbanks_neon.c",
|
||||
"codecs/isac/fix/source/filters_neon.c",
|
||||
"codecs/isac/fix/source/lattice_neon.c",
|
||||
"codecs/isac/fix/source/transform_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" ]
|
||||
|
||||
deps = [
|
||||
"../../common_audio",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
config("pcm16b_config") {
|
||||
include_dirs = [
|
||||
"../../..",
|
||||
"codecs/pcm16b/include",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("pcm16b") {
|
||||
sources = [
|
||||
"codecs/pcm16b/audio_decoder_pcm16b.cc",
|
||||
"codecs/pcm16b/audio_encoder_pcm16b.cc",
|
||||
"codecs/pcm16b/include/audio_decoder_pcm16b.h",
|
||||
"codecs/pcm16b/include/audio_encoder_pcm16b.h",
|
||||
"codecs/pcm16b/include/pcm16b.h",
|
||||
"codecs/pcm16b/pcm16b.c",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":audio_encoder_interface",
|
||||
":g711",
|
||||
]
|
||||
|
||||
configs += [ "../..:common_config" ]
|
||||
|
||||
public_configs = [
|
||||
"../..:common_inherited_config",
|
||||
":pcm16b_config",
|
||||
]
|
||||
}
|
||||
|
||||
config("opus_config") {
|
||||
include_dirs = [ "../../.." ]
|
||||
}
|
||||
|
||||
source_set("webrtc_opus") {
|
||||
sources = [
|
||||
"codecs/opus/audio_decoder_opus.cc",
|
||||
"codecs/opus/audio_encoder_opus.cc",
|
||||
"codecs/opus/interface/audio_decoder_opus.h",
|
||||
"codecs/opus/interface/audio_encoder_opus.h",
|
||||
"codecs/opus/interface/opus_interface.h",
|
||||
"codecs/opus/opus_inst.h",
|
||||
"codecs/opus/opus_interface.c",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":audio_encoder_interface",
|
||||
]
|
||||
|
||||
if (rtc_build_opus) {
|
||||
configs += [ "../..:common_config" ]
|
||||
public_configs = [ "../..:common_inherited_config" ]
|
||||
|
||||
public_deps = [
|
||||
rtc_opus_dir,
|
||||
]
|
||||
} else if (build_with_mozilla) {
|
||||
include_dirs = [ getenv("DIST") + "/include/opus" ]
|
||||
}
|
||||
}
|
||||
|
||||
config("neteq_config") {
|
||||
include_dirs = [
|
||||
# Need Opus header files for the audio classifier.
|
||||
"//third_party/opus/src/celt",
|
||||
"//third_party/opus/src/src",
|
||||
]
|
||||
}
|
||||
|
||||
source_set("neteq") {
|
||||
sources = [
|
||||
"neteq/accelerate.cc",
|
||||
"neteq/accelerate.h",
|
||||
"neteq/audio_classifier.cc",
|
||||
"neteq/audio_classifier.h",
|
||||
"neteq/audio_decoder_impl.cc",
|
||||
"neteq/audio_decoder_impl.h",
|
||||
"neteq/audio_multi_vector.cc",
|
||||
"neteq/audio_multi_vector.h",
|
||||
"neteq/audio_vector.cc",
|
||||
"neteq/audio_vector.h",
|
||||
"neteq/background_noise.cc",
|
||||
"neteq/background_noise.h",
|
||||
"neteq/buffer_level_filter.cc",
|
||||
"neteq/buffer_level_filter.h",
|
||||
"neteq/comfort_noise.cc",
|
||||
"neteq/comfort_noise.h",
|
||||
"neteq/decision_logic.cc",
|
||||
"neteq/decision_logic.h",
|
||||
"neteq/decision_logic_fax.cc",
|
||||
"neteq/decision_logic_fax.h",
|
||||
"neteq/decision_logic_normal.cc",
|
||||
"neteq/decision_logic_normal.h",
|
||||
"neteq/decoder_database.cc",
|
||||
"neteq/decoder_database.h",
|
||||
"neteq/defines.h",
|
||||
"neteq/delay_manager.cc",
|
||||
"neteq/delay_manager.h",
|
||||
"neteq/delay_peak_detector.cc",
|
||||
"neteq/delay_peak_detector.h",
|
||||
"neteq/dsp_helper.cc",
|
||||
"neteq/dsp_helper.h",
|
||||
"neteq/dtmf_buffer.cc",
|
||||
"neteq/dtmf_buffer.h",
|
||||
"neteq/dtmf_tone_generator.cc",
|
||||
"neteq/dtmf_tone_generator.h",
|
||||
"neteq/expand.cc",
|
||||
"neteq/expand.h",
|
||||
"neteq/interface/neteq.h",
|
||||
"neteq/merge.cc",
|
||||
"neteq/merge.h",
|
||||
"neteq/neteq.cc",
|
||||
"neteq/neteq_impl.cc",
|
||||
"neteq/neteq_impl.h",
|
||||
"neteq/normal.cc",
|
||||
"neteq/normal.h",
|
||||
"neteq/packet_buffer.cc",
|
||||
"neteq/packet_buffer.h",
|
||||
"neteq/payload_splitter.cc",
|
||||
"neteq/payload_splitter.h",
|
||||
"neteq/post_decode_vad.cc",
|
||||
"neteq/post_decode_vad.h",
|
||||
"neteq/preemptive_expand.cc",
|
||||
"neteq/preemptive_expand.h",
|
||||
"neteq/random_vector.cc",
|
||||
"neteq/random_vector.h",
|
||||
"neteq/rtcp.cc",
|
||||
"neteq/rtcp.h",
|
||||
"neteq/statistics_calculator.cc",
|
||||
"neteq/statistics_calculator.h",
|
||||
"neteq/sync_buffer.cc",
|
||||
"neteq/sync_buffer.h",
|
||||
"neteq/time_stretch.cc",
|
||||
"neteq/time_stretch.h",
|
||||
"neteq/timestamp_scaler.cc",
|
||||
"neteq/timestamp_scaler.h",
|
||||
]
|
||||
|
||||
configs += [ "../..:common_config" ]
|
||||
|
||||
public_configs = [
|
||||
"../..:common_inherited_config",
|
||||
":neteq_config",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":audio_decoder_interface",
|
||||
":cng",
|
||||
":g711",
|
||||
":pcm16b",
|
||||
"../..:webrtc_common",
|
||||
"../../common_audio",
|
||||
"../../system_wrappers",
|
||||
]
|
||||
|
||||
defines = []
|
||||
|
||||
if (rtc_include_opus) {
|
||||
defines += [ "WEBRTC_CODEC_OPUS" ]
|
||||
deps += [ ":webrtc_opus" ]
|
||||
}
|
||||
if (!build_with_mozilla) {
|
||||
if (current_cpu == "arm") {
|
||||
defines += [ "WEBRTC_CODEC_ISACFX" ]
|
||||
deps += [ ":isac_fix" ]
|
||||
} else {
|
||||
defines += [ "WEBRTC_CODEC_ISAC" ]
|
||||
deps += [ ":isac" ]
|
||||
}
|
||||
defines += [ "WEBRTC_CODEC_G722" ]
|
||||
deps += [ ":g722" ]
|
||||
}
|
||||
if (!build_with_mozilla && !build_with_chromium) {
|
||||
defines += [ "WEBRTC_CODEC_ILBC" ]
|
||||
deps += [ ":ilbc" ]
|
||||
}
|
||||
}
|
||||
35
webrtc/modules/audio_coding/Makefile.am
Normal file
35
webrtc/modules/audio_coding/Makefile.am
Normal file
@@ -0,0 +1,35 @@
|
||||
noinst_LTLIBRARIES = libaudio_coding.la
|
||||
|
||||
libaudio_coding_la_SOURCES = codecs/isac/main/interface/isac.h \
|
||||
codecs/isac/main/source/arith_routines.c \
|
||||
codecs/isac/main/source/arith_routines.h \
|
||||
codecs/isac/main/source/codec.h \
|
||||
codecs/isac/main/source/encode_lpc_swb.c \
|
||||
codecs/isac/main/source/encode_lpc_swb.h \
|
||||
codecs/isac/main/source/entropy_coding.c \
|
||||
codecs/isac/main/source/entropy_coding.h \
|
||||
codecs/isac/main/source/lpc_analysis.c \
|
||||
codecs/isac/main/source/lpc_analysis.h \
|
||||
codecs/isac/main/source/lpc_gain_swb_tables.c \
|
||||
codecs/isac/main/source/lpc_gain_swb_tables.h \
|
||||
codecs/isac/main/source/lpc_shape_swb12_tables.c \
|
||||
codecs/isac/main/source/lpc_shape_swb12_tables.h \
|
||||
codecs/isac/main/source/lpc_shape_swb16_tables.c \
|
||||
codecs/isac/main/source/lpc_shape_swb16_tables.h \
|
||||
codecs/isac/main/source/lpc_tables.c \
|
||||
codecs/isac/main/source/lpc_tables.h \
|
||||
codecs/isac/main/source/os_specific_inline.h \
|
||||
codecs/isac/main/source/pitch_estimator.c \
|
||||
codecs/isac/main/source/pitch_estimator.h \
|
||||
codecs/isac/main/source/pitch_gain_tables.c \
|
||||
codecs/isac/main/source/pitch_gain_tables.h \
|
||||
codecs/isac/main/source/pitch_lag_tables.c \
|
||||
codecs/isac/main/source/pitch_lag_tables.h \
|
||||
codecs/isac/main/source/settings.h \
|
||||
codecs/isac/main/source/spectrum_ar_model_tables.c \
|
||||
codecs/isac/main/source/spectrum_ar_model_tables.h \
|
||||
codecs/isac/main/source/structs.h \
|
||||
codecs/isac/bandwidth_info.h
|
||||
|
||||
libaudio_coding_la_CFLAGS = $(AM_CFLAGS) $(COMMON_CFLAGS)
|
||||
libaudio_coding_la_CXXFLAGS = $(AM_CXXFLAGS) $(COMMON_CXXFLAGS)
|
||||
24
webrtc/modules/audio_coding/codecs/isac/bandwidth_info.h
Normal file
24
webrtc/modules/audio_coding/codecs/isac/bandwidth_info.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_BANDWIDTH_INFO_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_BANDWIDTH_INFO_H_
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
typedef struct {
|
||||
int in_use;
|
||||
int32_t send_bw_avg;
|
||||
int32_t send_max_delay_avg;
|
||||
int16_t bottleneck_idx;
|
||||
int16_t jitter_info;
|
||||
} IsacBandwidthInfo;
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_BANDWIDTH_INFO_H_
|
||||
724
webrtc/modules/audio_coding/codecs/isac/main/interface/isac.h
Normal file
724
webrtc/modules/audio_coding/codecs/isac/main/interface/isac.h
Normal file
@@ -0,0 +1,724 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INTERFACE_ISAC_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INTERFACE_ISAC_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/bandwidth_info.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
typedef struct WebRtcISACStruct ISACStruct;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_AssignSize(...)
|
||||
*
|
||||
* This function returns the size of the ISAC instance, so that the instance
|
||||
* can be created outside iSAC.
|
||||
*
|
||||
* Input:
|
||||
* - samplingRate : sampling rate of the input/output audio.
|
||||
*
|
||||
* Output:
|
||||
* - sizeinbytes : number of bytes needed to allocate for the
|
||||
* instance.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_AssignSize(
|
||||
int* sizeinbytes);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_Assign(...)
|
||||
*
|
||||
* This function assignes the memory already created to the ISAC instance.
|
||||
*
|
||||
* Input:
|
||||
* - *ISAC_main_inst : a pointer to the coder instance.
|
||||
* - samplingRate : sampling rate of the input/output audio.
|
||||
* - ISAC_inst_Addr : the already allocated memory, where we put the
|
||||
* iSAC structure.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_Assign(
|
||||
ISACStruct** ISAC_main_inst,
|
||||
void* ISAC_inst_Addr);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_Create(...)
|
||||
*
|
||||
* This function creates an ISAC instance, which will contain the state
|
||||
* information for one coding/decoding channel.
|
||||
*
|
||||
* Input:
|
||||
* - *ISAC_main_inst : a pointer to the coder instance.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_Create(
|
||||
ISACStruct** ISAC_main_inst);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_Free(...)
|
||||
*
|
||||
* This function frees the ISAC instance created at the beginning.
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : an ISAC instance.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_Free(
|
||||
ISACStruct* ISAC_main_inst);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncoderInit(...)
|
||||
*
|
||||
* This function initializes an ISAC instance prior to the encoder calls.
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : ISAC instance.
|
||||
* - CodingMode : 0 -> Bit rate and frame length are
|
||||
* automatically adjusted to available bandwidth
|
||||
* on transmission channel, just valid if codec
|
||||
* is created to work in wideband mode.
|
||||
* 1 -> User sets a frame length and a target bit
|
||||
* rate which is taken as the maximum
|
||||
* short-term average bit rate.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_EncoderInit(
|
||||
ISACStruct* ISAC_main_inst,
|
||||
int16_t CodingMode);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_Encode(...)
|
||||
*
|
||||
* This function encodes 10ms audio blocks and inserts it into a package.
|
||||
* Input speech length has 160 samples if operating at 16 kHz sampling
|
||||
* rate, or 320 if operating at 32 kHz sampling rate. The encoder buffers the
|
||||
* input audio until the whole frame is buffered then proceeds with encoding.
|
||||
*
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : ISAC instance.
|
||||
* - speechIn : input speech vector.
|
||||
*
|
||||
* Output:
|
||||
* - encoded : the encoded data vector
|
||||
*
|
||||
* Return value:
|
||||
* : >0 - Length (in bytes) of coded data
|
||||
* : 0 - The buffer didn't reach the chosen
|
||||
* frame-size so it keeps buffering speech
|
||||
* samples.
|
||||
* : -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcIsac_Encode(
|
||||
ISACStruct* ISAC_main_inst,
|
||||
const int16_t* speechIn,
|
||||
uint8_t* encoded);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecoderInit(...)
|
||||
*
|
||||
* This function initializes an ISAC instance prior to the decoder calls.
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : ISAC instance.
|
||||
*/
|
||||
|
||||
void WebRtcIsac_DecoderInit(ISACStruct* ISAC_main_inst);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_UpdateBwEstimate(...)
|
||||
*
|
||||
* This function updates the estimate of the bandwidth.
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : ISAC instance.
|
||||
* - encoded : encoded ISAC frame(s).
|
||||
* - packet_size : size of the packet.
|
||||
* - rtp_seq_number : the RTP number of the packet.
|
||||
* - send_ts : the RTP send timestamp, given in samples
|
||||
* - arr_ts : the arrival time of the packet (from NetEq)
|
||||
* in samples.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_UpdateBwEstimate(
|
||||
ISACStruct* ISAC_main_inst,
|
||||
const uint8_t* encoded,
|
||||
size_t packet_size,
|
||||
uint16_t rtp_seq_number,
|
||||
uint32_t send_ts,
|
||||
uint32_t arr_ts);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_Decode(...)
|
||||
*
|
||||
* This function decodes an ISAC frame. At 16 kHz sampling rate, the length
|
||||
* of the output audio could be either 480 or 960 samples, equivalent to
|
||||
* 30 or 60 ms respectively. At 32 kHz sampling rate, the length of the
|
||||
* output audio is 960 samples, which is 30 ms.
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : ISAC instance.
|
||||
* - encoded : encoded ISAC frame(s).
|
||||
* - len : bytes in encoded vector.
|
||||
*
|
||||
* Output:
|
||||
* - decoded : The decoded vector.
|
||||
*
|
||||
* Return value : >0 - number of samples in decoded vector.
|
||||
* -1 - Error.
|
||||
*/
|
||||
|
||||
int WebRtcIsac_Decode(
|
||||
ISACStruct* ISAC_main_inst,
|
||||
const uint8_t* encoded,
|
||||
size_t len,
|
||||
int16_t* decoded,
|
||||
int16_t* speechType);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodePlc(...)
|
||||
*
|
||||
* This function conducts PLC for ISAC frame(s). Output speech length
|
||||
* will be a multiple of frames, i.e. multiples of 30 ms audio. Therefore,
|
||||
* the output is multiple of 480 samples if operating at 16 kHz and multiple
|
||||
* of 960 if operating at 32 kHz.
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : ISAC instance.
|
||||
* - noOfLostFrames : Number of PLC frames to produce.
|
||||
*
|
||||
* Output:
|
||||
* - decoded : The decoded vector.
|
||||
*
|
||||
* Return value : Number of samples in decoded PLC vector
|
||||
*/
|
||||
|
||||
size_t WebRtcIsac_DecodePlc(
|
||||
ISACStruct* ISAC_main_inst,
|
||||
int16_t* decoded,
|
||||
size_t noOfLostFrames);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_Control(...)
|
||||
*
|
||||
* This function sets the limit on the short-term average bit-rate and the
|
||||
* frame length. Should be used only in Instantaneous mode. At 16 kHz sampling
|
||||
* rate, an average bit-rate between 10000 to 32000 bps is valid and a
|
||||
* frame-size of 30 or 60 ms is acceptable. At 32 kHz, an average bit-rate
|
||||
* between 10000 to 56000 is acceptable, and the valid frame-size is 30 ms.
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : ISAC instance.
|
||||
* - rate : limit on the short-term average bit rate,
|
||||
* in bits/second.
|
||||
* - framesize : frame-size in millisecond.
|
||||
*
|
||||
* Return value : 0 - ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_Control(
|
||||
ISACStruct* ISAC_main_inst,
|
||||
int32_t rate,
|
||||
int framesize);
|
||||
|
||||
void WebRtcIsac_SetInitialBweBottleneck(ISACStruct* ISAC_main_inst,
|
||||
int bottleneck_bits_per_second);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_ControlBwe(...)
|
||||
*
|
||||
* This function sets the initial values of bottleneck and frame-size if
|
||||
* iSAC is used in channel-adaptive mode. Therefore, this API is not
|
||||
* applicable if the codec is created to operate in super-wideband mode.
|
||||
*
|
||||
* Through this API, users can enforce a frame-size for all values of
|
||||
* bottleneck. Then iSAC will not automatically change the frame-size.
|
||||
*
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : ISAC instance.
|
||||
* - rateBPS : initial value of bottleneck in bits/second
|
||||
* 10000 <= rateBPS <= 56000 is accepted
|
||||
* For default bottleneck set rateBPS = 0
|
||||
* - frameSizeMs : number of milliseconds per frame (30 or 60)
|
||||
* - enforceFrameSize : 1 to enforce the given frame-size through
|
||||
* out the adaptation process, 0 to let iSAC
|
||||
* change the frame-size if required.
|
||||
*
|
||||
* Return value : 0 - ok
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_ControlBwe(
|
||||
ISACStruct* ISAC_main_inst,
|
||||
int32_t rateBPS,
|
||||
int frameSizeMs,
|
||||
int16_t enforceFrameSize);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_ReadFrameLen(...)
|
||||
*
|
||||
* This function returns the length of the frame represented in the packet.
|
||||
*
|
||||
* Input:
|
||||
* - encoded : Encoded bit-stream
|
||||
*
|
||||
* Output:
|
||||
* - frameLength : Length of frame in packet (in samples)
|
||||
*
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_ReadFrameLen(
|
||||
ISACStruct* ISAC_main_inst,
|
||||
const uint8_t* encoded,
|
||||
int16_t* frameLength);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_version(...)
|
||||
*
|
||||
* This function returns the version number.
|
||||
*
|
||||
* Output:
|
||||
* - version : Pointer to character string
|
||||
*
|
||||
*/
|
||||
|
||||
void WebRtcIsac_version(
|
||||
char *version);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_GetErrorCode(...)
|
||||
*
|
||||
* This function can be used to check the error code of an iSAC instance. When
|
||||
* a function returns -1 a error code will be set for that instance. The
|
||||
* function below extract the code of the last error that occurred in the
|
||||
* specified instance.
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : ISAC instance
|
||||
*
|
||||
* Return value : Error code
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_GetErrorCode(
|
||||
ISACStruct* ISAC_main_inst);
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcIsac_GetUplinkBw(...)
|
||||
*
|
||||
* This function outputs the target bottleneck of the codec. In
|
||||
* channel-adaptive mode, the target bottleneck is specified through in-band
|
||||
* signalling retreived by bandwidth estimator.
|
||||
* In channel-independent, also called instantaneous mode, the target
|
||||
* bottleneck is provided to the encoder by calling xxx_control(...). If
|
||||
* xxx_control is never called the default values is returned. The default
|
||||
* value for bottleneck at 16 kHz encoder sampling rate is 32000 bits/sec,
|
||||
* and it is 56000 bits/sec for 32 kHz sampling rate.
|
||||
* Note that the output is the iSAC internal operating bottleneck which might
|
||||
* differ slightly from the one provided through xxx_control().
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : iSAC instance
|
||||
*
|
||||
* Output:
|
||||
* - *bottleneck : bottleneck in bits/sec
|
||||
*
|
||||
* Return value : -1 if error happens
|
||||
* 0 bit-rates computed correctly.
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_GetUplinkBw(
|
||||
ISACStruct* ISAC_main_inst,
|
||||
int32_t* bottleneck);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_SetMaxPayloadSize(...)
|
||||
*
|
||||
* This function sets a limit for the maximum payload size of iSAC. The same
|
||||
* value is used both for 30 and 60 ms packets. If the encoder sampling rate
|
||||
* is 16 kHz the maximum payload size is between 120 and 400 bytes. If the
|
||||
* encoder sampling rate is 32 kHz the maximum payload size is between 120
|
||||
* and 600 bytes.
|
||||
*
|
||||
* If an out of range limit is used, the function returns -1, but the closest
|
||||
* valid value will be applied.
|
||||
*
|
||||
* ---------------
|
||||
* IMPORTANT NOTES
|
||||
* ---------------
|
||||
* The size of a packet is limited to the minimum of 'max-payload-size' and
|
||||
* 'max-rate.' For instance, let's assume the max-payload-size is set to
|
||||
* 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps
|
||||
* translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms
|
||||
* frame-size. Then a packet with a frame-size of 30 ms is limited to 150,
|
||||
* i.e. min(170, 150), and a packet with 60 ms frame-size is limited to
|
||||
* 170 bytes, i.e. min(170, 300).
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : iSAC instance
|
||||
* - maxPayloadBytes : maximum size of the payload in bytes
|
||||
* valid values are between 120 and 400 bytes
|
||||
* if encoder sampling rate is 16 kHz. For
|
||||
* 32 kHz encoder sampling rate valid values
|
||||
* are between 120 and 600 bytes.
|
||||
*
|
||||
* Return value : 0 if successful
|
||||
* -1 if error happens
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_SetMaxPayloadSize(
|
||||
ISACStruct* ISAC_main_inst,
|
||||
int16_t maxPayloadBytes);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_SetMaxRate(...)
|
||||
*
|
||||
* This function sets the maximum rate which the codec may not exceed for
|
||||
* any signal packet. The maximum rate is defined and payload-size per
|
||||
* frame-size in bits per second.
|
||||
*
|
||||
* The codec has a maximum rate of 53400 bits per second (200 bytes per 30
|
||||
* ms) if the encoder sampling rate is 16kHz, and 160 kbps (600 bytes/30 ms)
|
||||
* if the encoder sampling rate is 32 kHz.
|
||||
*
|
||||
* It is possible to set a maximum rate between 32000 and 53400 bits/sec
|
||||
* in wideband mode, and 32000 to 160000 bits/sec in super-wideband mode.
|
||||
*
|
||||
* If an out of range limit is used, the function returns -1, but the closest
|
||||
* valid value will be applied.
|
||||
*
|
||||
* ---------------
|
||||
* IMPORTANT NOTES
|
||||
* ---------------
|
||||
* The size of a packet is limited to the minimum of 'max-payload-size' and
|
||||
* 'max-rate.' For instance, let's assume the max-payload-size is set to
|
||||
* 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps
|
||||
* translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms
|
||||
* frame-size. Then a packet with a frame-size of 30 ms is limited to 150,
|
||||
* i.e. min(170, 150), and a packet with 60 ms frame-size is limited to
|
||||
* 170 bytes, min(170, 300).
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : iSAC instance
|
||||
* - maxRate : maximum rate in bits per second,
|
||||
* valid values are 32000 to 53400 bits/sec in
|
||||
* wideband mode, and 32000 to 160000 bits/sec in
|
||||
* super-wideband mode.
|
||||
*
|
||||
* Return value : 0 if successful
|
||||
* -1 if error happens
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_SetMaxRate(
|
||||
ISACStruct* ISAC_main_inst,
|
||||
int32_t maxRate);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecSampRate()
|
||||
* Return the sampling rate of the decoded audio.
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : iSAC instance
|
||||
*
|
||||
* Return value : sampling frequency in Hertz.
|
||||
*
|
||||
*/
|
||||
|
||||
uint16_t WebRtcIsac_DecSampRate(ISACStruct* ISAC_main_inst);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncSampRate()
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : iSAC instance
|
||||
*
|
||||
* Return value : sampling rate in Hertz.
|
||||
*
|
||||
*/
|
||||
|
||||
uint16_t WebRtcIsac_EncSampRate(ISACStruct* ISAC_main_inst);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_SetDecSampRate()
|
||||
* Set the sampling rate of the decoder. Initialization of the decoder WILL
|
||||
* NOT overwrite the sampling rate of the encoder. The default value is 16 kHz
|
||||
* which is set when the instance is created.
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : iSAC instance
|
||||
* - sampRate : sampling rate in Hertz.
|
||||
*
|
||||
* Return value : 0 if successful
|
||||
* -1 if failed.
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_SetDecSampRate(ISACStruct* ISAC_main_inst,
|
||||
uint16_t samp_rate_hz);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_SetEncSampRate()
|
||||
* Set the sampling rate of the encoder. Initialization of the encoder WILL
|
||||
* NOT overwrite the sampling rate of the encoder. The default value is 16 kHz
|
||||
* which is set when the instance is created. The encoding-mode and the
|
||||
* bottleneck remain unchanged by this call, however, the maximum rate and
|
||||
* maximum payload-size will reset to their default value.
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : iSAC instance
|
||||
* - sampRate : sampling rate in Hertz.
|
||||
*
|
||||
* Return value : 0 if successful
|
||||
* -1 if failed.
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_SetEncSampRate(ISACStruct* ISAC_main_inst,
|
||||
uint16_t sample_rate_hz);
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_GetNewBitStream(...)
|
||||
*
|
||||
* This function returns encoded data, with the recieved bwe-index in the
|
||||
* stream. If the rate is set to a value less than bottleneck of codec
|
||||
* the new bistream will be re-encoded with the given target rate.
|
||||
* It should always return a complete packet, i.e. only called once
|
||||
* even for 60 msec frames.
|
||||
*
|
||||
* NOTE 1! This function does not write in the ISACStruct, it is not allowed.
|
||||
* NOTE 2! Currently not implemented for SWB mode.
|
||||
* NOTE 3! Rates larger than the bottleneck of the codec will be limited
|
||||
* to the current bottleneck.
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : ISAC instance.
|
||||
* - bweIndex : Index of bandwidth estimate to put in new
|
||||
* bitstream
|
||||
* - rate : target rate of the transcoder is bits/sec.
|
||||
* Valid values are the accepted rate in iSAC,
|
||||
* i.e. 10000 to 56000.
|
||||
* - isRCU : if the new bit-stream is an RCU stream.
|
||||
* Note that the rate parameter always indicates
|
||||
* the target rate of the main payload, regardless
|
||||
* of 'isRCU' value.
|
||||
*
|
||||
* Output:
|
||||
* - encoded : The encoded data vector
|
||||
*
|
||||
* Return value : >0 - Length (in bytes) of coded data
|
||||
* -1 - Error or called in SWB mode
|
||||
* NOTE! No error code is written to
|
||||
* the struct since it is only allowed to read
|
||||
* the struct.
|
||||
*/
|
||||
int16_t WebRtcIsac_GetNewBitStream(
|
||||
ISACStruct* ISAC_main_inst,
|
||||
int16_t bweIndex,
|
||||
int16_t jitterInfo,
|
||||
int32_t rate,
|
||||
uint8_t* encoded,
|
||||
int16_t isRCU);
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcIsac_GetDownLinkBwIndex(...)
|
||||
*
|
||||
* This function returns index representing the Bandwidth estimate from
|
||||
* other side to this side.
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : iSAC struct
|
||||
*
|
||||
* Output:
|
||||
* - bweIndex : Bandwidth estimate to transmit to other side.
|
||||
*
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_GetDownLinkBwIndex(
|
||||
ISACStruct* ISAC_main_inst,
|
||||
int16_t* bweIndex,
|
||||
int16_t* jitterInfo);
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcIsac_UpdateUplinkBw(...)
|
||||
*
|
||||
* This function takes an index representing the Bandwidth estimate from
|
||||
* this side to other side and updates BWE.
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : iSAC struct
|
||||
* - bweIndex : Bandwidth estimate from other side.
|
||||
*
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_UpdateUplinkBw(
|
||||
ISACStruct* ISAC_main_inst,
|
||||
int16_t bweIndex);
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcIsac_ReadBwIndex(...)
|
||||
*
|
||||
* This function returns the index of the Bandwidth estimate from the bitstream.
|
||||
*
|
||||
* Input:
|
||||
* - encoded : Encoded bitstream
|
||||
*
|
||||
* Output:
|
||||
* - frameLength : Length of frame in packet (in samples)
|
||||
* - bweIndex : Bandwidth estimate in bitstream
|
||||
*
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_ReadBwIndex(
|
||||
const uint8_t* encoded,
|
||||
int16_t* bweIndex);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* WebRtcIsac_GetNewFrameLen(...)
|
||||
*
|
||||
* returns the frame lenght (in samples) of the next packet. In the case of channel-adaptive
|
||||
* mode, iSAC decides on its frame lenght based on the estimated bottleneck
|
||||
* this allows a user to prepare for the next packet (at the encoder)
|
||||
*
|
||||
* The primary usage is in CE to make the iSAC works in channel-adaptive mode
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : iSAC struct
|
||||
*
|
||||
* Return Value : frame lenght in samples
|
||||
*
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_GetNewFrameLen(
|
||||
ISACStruct* ISAC_main_inst);
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcIsac_GetRedPayload(...)
|
||||
*
|
||||
* Populates "encoded" with the redundant payload of the recently encoded
|
||||
* frame. This function has to be called once that WebRtcIsac_Encode(...)
|
||||
* returns a positive value. Regardless of the frame-size this function will
|
||||
* be called only once after encoding is completed.
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : iSAC struct
|
||||
*
|
||||
* Output:
|
||||
* - encoded : the encoded data vector
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
* : >0 - Length (in bytes) of coded data
|
||||
* : -1 - Error
|
||||
*
|
||||
*
|
||||
*/
|
||||
int16_t WebRtcIsac_GetRedPayload(
|
||||
ISACStruct* ISAC_main_inst,
|
||||
uint8_t* encoded);
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcIsac_DecodeRcu(...)
|
||||
*
|
||||
* This function decodes a redundant (RCU) iSAC frame. Function is called in
|
||||
* NetEq with a stored RCU payload i case of packet loss. Output speech length
|
||||
* will be a multiple of 480 samples: 480 or 960 samples,
|
||||
* depending on the framesize (30 or 60 ms).
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : ISAC instance.
|
||||
* - encoded : encoded ISAC RCU frame(s)
|
||||
* - len : bytes in encoded vector
|
||||
*
|
||||
* Output:
|
||||
* - decoded : The decoded vector
|
||||
*
|
||||
* Return value : >0 - number of samples in decoded vector
|
||||
* -1 - Error
|
||||
*/
|
||||
int WebRtcIsac_DecodeRcu(
|
||||
ISACStruct* ISAC_main_inst,
|
||||
const uint8_t* encoded,
|
||||
size_t len,
|
||||
int16_t* decoded,
|
||||
int16_t* speechType);
|
||||
|
||||
/* Fills in an IsacBandwidthInfo struct. |inst| should be a decoder. */
|
||||
void WebRtcIsac_GetBandwidthInfo(ISACStruct* inst, IsacBandwidthInfo* bwinfo);
|
||||
|
||||
/* Uses the values from an IsacBandwidthInfo struct. |inst| should be an
|
||||
encoder. */
|
||||
void WebRtcIsac_SetBandwidthInfo(ISACStruct* inst,
|
||||
const IsacBandwidthInfo* bwinfo);
|
||||
|
||||
/* If |inst| is a decoder but not an encoder: tell it what sample rate the
|
||||
encoder is using, for bandwidth estimation purposes. */
|
||||
void WebRtcIsac_SetEncSampRateInDecoder(ISACStruct* inst, int sample_rate_hz);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INTERFACE_ISAC_H_ */
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "arith_routines.h"
|
||||
#include "settings.h"
|
||||
|
||||
|
||||
/*
|
||||
* terminate and return byte stream;
|
||||
* returns the number of bytes in the stream
|
||||
*/
|
||||
int WebRtcIsac_EncTerminate(Bitstr *streamdata) /* in-/output struct containing bitstream */
|
||||
{
|
||||
uint8_t *stream_ptr;
|
||||
|
||||
|
||||
/* point to the right place in the stream buffer */
|
||||
stream_ptr = streamdata->stream + streamdata->stream_index;
|
||||
|
||||
/* find minimum length (determined by current interval width) */
|
||||
if ( streamdata->W_upper > 0x01FFFFFF )
|
||||
{
|
||||
streamdata->streamval += 0x01000000;
|
||||
/* add carry to buffer */
|
||||
if (streamdata->streamval < 0x01000000)
|
||||
{
|
||||
/* propagate carry */
|
||||
while ( !(++(*--stream_ptr)) );
|
||||
/* put pointer back to the old value */
|
||||
stream_ptr = streamdata->stream + streamdata->stream_index;
|
||||
}
|
||||
/* write remaining data to bitstream */
|
||||
*stream_ptr++ = (uint8_t) (streamdata->streamval >> 24);
|
||||
}
|
||||
else
|
||||
{
|
||||
streamdata->streamval += 0x00010000;
|
||||
/* add carry to buffer */
|
||||
if (streamdata->streamval < 0x00010000)
|
||||
{
|
||||
/* propagate carry */
|
||||
while ( !(++(*--stream_ptr)) );
|
||||
/* put pointer back to the old value */
|
||||
stream_ptr = streamdata->stream + streamdata->stream_index;
|
||||
}
|
||||
/* write remaining data to bitstream */
|
||||
*stream_ptr++ = (uint8_t) (streamdata->streamval >> 24);
|
||||
*stream_ptr++ = (uint8_t) ((streamdata->streamval >> 16) & 0x00FF);
|
||||
}
|
||||
|
||||
/* calculate stream length */
|
||||
return (int)(stream_ptr - streamdata->stream);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* arith_routines.h
|
||||
*
|
||||
* Functions for arithmetic coding.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_
|
||||
|
||||
#include "structs.h"
|
||||
|
||||
|
||||
int WebRtcIsac_EncLogisticMulti2(
|
||||
Bitstr *streamdata, /* in-/output struct containing bitstream */
|
||||
int16_t *dataQ7, /* input: data vector */
|
||||
const uint16_t *env, /* input: side info vector defining the width of the pdf */
|
||||
const int N, /* input: data vector length */
|
||||
const int16_t isSWB12kHz); /* if the codec is working in 12kHz bandwidth */
|
||||
|
||||
/* returns the number of bytes in the stream */
|
||||
int WebRtcIsac_EncTerminate(Bitstr *streamdata); /* in-/output struct containing bitstream */
|
||||
|
||||
/* returns the number of bytes in the stream so far */
|
||||
int WebRtcIsac_DecLogisticMulti2(
|
||||
int16_t *data, /* output: data vector */
|
||||
Bitstr *streamdata, /* in-/output struct containing bitstream */
|
||||
const uint16_t *env, /* input: side info vector defining the width of the pdf */
|
||||
const int16_t *dither, /* input: dither vector */
|
||||
const int N, /* input: data vector length */
|
||||
const int16_t isSWB12kHz); /* if the codec is working in 12kHz bandwidth */
|
||||
|
||||
void WebRtcIsac_EncHistMulti(
|
||||
Bitstr *streamdata, /* in-/output struct containing bitstream */
|
||||
const int *data, /* input: data vector */
|
||||
const uint16_t **cdf, /* input: array of cdf arrays */
|
||||
const int N); /* input: data vector length */
|
||||
|
||||
int WebRtcIsac_DecHistBisectMulti(
|
||||
int *data, /* output: data vector */
|
||||
Bitstr *streamdata, /* in-/output struct containing bitstream */
|
||||
const uint16_t **cdf, /* input: array of cdf arrays */
|
||||
const uint16_t *cdf_size, /* input: array of cdf table sizes+1 (power of two: 2^k) */
|
||||
const int N); /* input: data vector length */
|
||||
|
||||
int WebRtcIsac_DecHistOneStepMulti(
|
||||
int *data, /* output: data vector */
|
||||
Bitstr *streamdata, /* in-/output struct containing bitstream */
|
||||
const uint16_t **cdf, /* input: array of cdf arrays */
|
||||
const uint16_t *init_index,/* input: vector of initial cdf table search entries */
|
||||
const int N); /* input: data vector length */
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_ */
|
||||
233
webrtc/modules/audio_coding/codecs/isac/main/source/codec.h
Normal file
233
webrtc/modules/audio_coding/codecs/isac/main/source/codec.h
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* codec.h
|
||||
*
|
||||
* This header file contains the calls to the internal encoder
|
||||
* and decoder functions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_
|
||||
|
||||
#include "structs.h"
|
||||
|
||||
|
||||
void WebRtcIsac_ResetBitstream(Bitstr* bit_stream);
|
||||
|
||||
int WebRtcIsac_EstimateBandwidth(BwEstimatorstr* bwest_str, Bitstr* streamdata,
|
||||
size_t packet_size,
|
||||
uint16_t rtp_seq_number,
|
||||
uint32_t send_ts, uint32_t arr_ts,
|
||||
enum IsacSamplingRate encoderSampRate,
|
||||
enum IsacSamplingRate decoderSampRate);
|
||||
|
||||
int WebRtcIsac_DecodeLb(const TransformTables* transform_tables,
|
||||
float* signal_out,
|
||||
ISACLBDecStruct* ISACdec_obj,
|
||||
int16_t* current_framesamples,
|
||||
int16_t isRCUPayload);
|
||||
|
||||
int WebRtcIsac_DecodeRcuLb(float* signal_out, ISACLBDecStruct* ISACdec_obj,
|
||||
int16_t* current_framesamples);
|
||||
|
||||
int WebRtcIsac_EncodeLb(const TransformTables* transform_tables,
|
||||
float* in,
|
||||
ISACLBEncStruct* ISACencLB_obj,
|
||||
int16_t codingMode,
|
||||
int16_t bottleneckIndex);
|
||||
|
||||
int WebRtcIsac_EncodeStoredDataLb(const IsacSaveEncoderData* ISACSavedEnc_obj,
|
||||
Bitstr* ISACBitStr_obj, int BWnumber,
|
||||
float scale);
|
||||
|
||||
int WebRtcIsac_EncodeStoredDataUb(
|
||||
const ISACUBSaveEncDataStruct* ISACSavedEnc_obj, Bitstr* bitStream,
|
||||
int32_t jitterInfo, float scale, enum ISACBandwidth bandwidth);
|
||||
|
||||
int16_t WebRtcIsac_GetRedPayloadUb(
|
||||
const ISACUBSaveEncDataStruct* ISACSavedEncObj, Bitstr* bitStreamObj,
|
||||
enum ISACBandwidth bandwidth);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_RateAllocation()
|
||||
* Internal function to perform a rate-allocation for upper and lower-band,
|
||||
* given a total rate.
|
||||
*
|
||||
* Input:
|
||||
* - inRateBitPerSec : a total bit-rate in bits/sec.
|
||||
*
|
||||
* Output:
|
||||
* - rateLBBitPerSec : a bit-rate allocated to the lower-band
|
||||
* in bits/sec.
|
||||
* - rateUBBitPerSec : a bit-rate allocated to the upper-band
|
||||
* in bits/sec.
|
||||
*
|
||||
* Return value : 0 if rate allocation has been successful.
|
||||
* -1 if failed to allocate rates.
|
||||
*/
|
||||
|
||||
int16_t WebRtcIsac_RateAllocation(int32_t inRateBitPerSec,
|
||||
double* rateLBBitPerSec,
|
||||
double* rateUBBitPerSec,
|
||||
enum ISACBandwidth* bandwidthKHz);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeUb16()
|
||||
*
|
||||
* Decode the upper-band if the codec is in 0-16 kHz mode.
|
||||
*
|
||||
* Input/Output:
|
||||
* -ISACdec_obj : pointer to the upper-band decoder object. The
|
||||
* bit-stream is stored inside the decoder object.
|
||||
*
|
||||
* Output:
|
||||
* -signal_out : decoded audio, 480 samples 30 ms.
|
||||
*
|
||||
* Return value : >0 number of decoded bytes.
|
||||
* <0 if an error occurred.
|
||||
*/
|
||||
int WebRtcIsac_DecodeUb16(const TransformTables* transform_tables,
|
||||
float* signal_out,
|
||||
ISACUBDecStruct* ISACdec_obj,
|
||||
int16_t isRCUPayload);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeUb12()
|
||||
*
|
||||
* Decode the upper-band if the codec is in 0-12 kHz mode.
|
||||
*
|
||||
* Input/Output:
|
||||
* -ISACdec_obj : pointer to the upper-band decoder object. The
|
||||
* bit-stream is stored inside the decoder object.
|
||||
*
|
||||
* Output:
|
||||
* -signal_out : decoded audio, 480 samples 30 ms.
|
||||
*
|
||||
* Return value : >0 number of decoded bytes.
|
||||
* <0 if an error occurred.
|
||||
*/
|
||||
int WebRtcIsac_DecodeUb12(const TransformTables* transform_tables,
|
||||
float* signal_out,
|
||||
ISACUBDecStruct* ISACdec_obj,
|
||||
int16_t isRCUPayload);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeUb16()
|
||||
*
|
||||
* Encode the upper-band if the codec is in 0-16 kHz mode.
|
||||
*
|
||||
* Input:
|
||||
* -in : upper-band audio, 160 samples (10 ms).
|
||||
*
|
||||
* Input/Output:
|
||||
* -ISACdec_obj : pointer to the upper-band encoder object. The
|
||||
* bit-stream is stored inside the encoder object.
|
||||
*
|
||||
* Return value : >0 number of encoded bytes.
|
||||
* <0 if an error occurred.
|
||||
*/
|
||||
int WebRtcIsac_EncodeUb16(const TransformTables* transform_tables,
|
||||
float* in,
|
||||
ISACUBEncStruct* ISACenc_obj,
|
||||
int32_t jitterInfo);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeUb12()
|
||||
*
|
||||
* Encode the upper-band if the codec is in 0-12 kHz mode.
|
||||
*
|
||||
* Input:
|
||||
* -in : upper-band audio, 160 samples (10 ms).
|
||||
*
|
||||
* Input/Output:
|
||||
* -ISACdec_obj : pointer to the upper-band encoder object. The
|
||||
* bit-stream is stored inside the encoder object.
|
||||
*
|
||||
* Return value : >0 number of encoded bytes.
|
||||
* <0 if an error occurred.
|
||||
*/
|
||||
int WebRtcIsac_EncodeUb12(const TransformTables* transform_tables,
|
||||
float* in,
|
||||
ISACUBEncStruct* ISACenc_obj,
|
||||
int32_t jitterInfo);
|
||||
|
||||
/************************** initialization functions *************************/
|
||||
|
||||
void WebRtcIsac_InitMasking(MaskFiltstr* maskdata);
|
||||
|
||||
void WebRtcIsac_InitPreFilterbank(PreFiltBankstr* prefiltdata);
|
||||
|
||||
void WebRtcIsac_InitPostFilterbank(PostFiltBankstr* postfiltdata);
|
||||
|
||||
void WebRtcIsac_InitPitchFilter(PitchFiltstr* pitchfiltdata);
|
||||
|
||||
void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct* State);
|
||||
|
||||
|
||||
/**************************** transform functions ****************************/
|
||||
|
||||
void WebRtcIsac_InitTransform(TransformTables* tables);
|
||||
|
||||
void WebRtcIsac_Time2Spec(const TransformTables* tables,
|
||||
double* inre1,
|
||||
double* inre2,
|
||||
int16_t* outre,
|
||||
int16_t* outim,
|
||||
FFTstr* fftstr_obj);
|
||||
|
||||
void WebRtcIsac_Spec2time(const TransformTables* tables,
|
||||
double* inre,
|
||||
double* inim,
|
||||
double* outre1,
|
||||
double* outre2,
|
||||
FFTstr* fftstr_obj);
|
||||
|
||||
/******************************* filter functions ****************************/
|
||||
|
||||
void WebRtcIsac_AllPoleFilter(double* InOut, double* Coef, size_t lengthInOut,
|
||||
int orderCoef);
|
||||
|
||||
void WebRtcIsac_AllZeroFilter(double* In, double* Coef, size_t lengthInOut,
|
||||
int orderCoef, double* Out);
|
||||
|
||||
void WebRtcIsac_ZeroPoleFilter(double* In, double* ZeroCoef, double* PoleCoef,
|
||||
size_t lengthInOut, int orderCoef, double* Out);
|
||||
|
||||
|
||||
/***************************** filterbank functions **************************/
|
||||
|
||||
void WebRtcIsac_SplitAndFilterFloat(float* in, float* LP, float* HP,
|
||||
double* LP_la, double* HP_la,
|
||||
PreFiltBankstr* prefiltdata);
|
||||
|
||||
|
||||
void WebRtcIsac_FilterAndCombineFloat(float* InLP, float* InHP, float* Out,
|
||||
PostFiltBankstr* postfiltdata);
|
||||
|
||||
|
||||
/************************* normalized lattice filters ************************/
|
||||
|
||||
void WebRtcIsac_NormLatticeFilterMa(int orderCoef, float* stateF, float* stateG,
|
||||
float* lat_in, double* filtcoeflo,
|
||||
double* lat_out);
|
||||
|
||||
void WebRtcIsac_NormLatticeFilterAr(int orderCoef, float* stateF, float* stateG,
|
||||
double* lat_in, double* lo_filt_coef,
|
||||
float* lat_out);
|
||||
|
||||
void WebRtcIsac_Dir2Lat(double* a, int orderCoef, float* sth, float* cth);
|
||||
|
||||
void WebRtcIsac_AutoCorr(double* r, const double* x, size_t N, size_t order);
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_ */
|
||||
@@ -0,0 +1,708 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* code_LPC_UB.c
|
||||
*
|
||||
* This file contains definition of functions used to
|
||||
* encode LPC parameters (Shape & gain) of the upper band.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "encode_lpc_swb.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lpc_gain_swb_tables.h"
|
||||
#include "lpc_shape_swb12_tables.h"
|
||||
#include "lpc_shape_swb16_tables.h"
|
||||
#include "settings.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_RemoveLarMean()
|
||||
*
|
||||
* Remove the means from LAR coefficients.
|
||||
*
|
||||
* Input:
|
||||
* -lar : pointer to lar vectors. LAR vectors are
|
||||
* concatenated.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -lar : pointer to mean-removed LAR:s.
|
||||
*
|
||||
*
|
||||
*/
|
||||
int16_t
|
||||
WebRtcIsac_RemoveLarMean(
|
||||
double* lar,
|
||||
int16_t bandwidth)
|
||||
{
|
||||
int16_t coeffCntr;
|
||||
int16_t vecCntr;
|
||||
int16_t numVec;
|
||||
const double* meanLAR;
|
||||
switch(bandwidth)
|
||||
{
|
||||
case isac12kHz:
|
||||
{
|
||||
numVec = UB_LPC_VEC_PER_FRAME;
|
||||
meanLAR = WebRtcIsac_kMeanLarUb12;
|
||||
break;
|
||||
}
|
||||
case isac16kHz:
|
||||
{
|
||||
numVec = UB16_LPC_VEC_PER_FRAME;
|
||||
meanLAR = WebRtcIsac_kMeanLarUb16;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(vecCntr = 0; vecCntr < numVec; vecCntr++)
|
||||
{
|
||||
for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++)
|
||||
{
|
||||
// REMOVE MEAN
|
||||
*lar++ -= meanLAR[coeffCntr];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecorrelateIntraVec()
|
||||
*
|
||||
* Remove the correlation amonge the components of LAR vectors. If LAR vectors
|
||||
* of one frame are put in a matrix where each column is a LAR vector of a
|
||||
* sub-frame, then this is equivalent to multiplying the LAR matrix with
|
||||
* a decorrelting mtrix from left.
|
||||
*
|
||||
* Input:
|
||||
* -inLar : pointer to mean-removed LAR vecrtors.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : decorrelated LAR vectors.
|
||||
*/
|
||||
int16_t
|
||||
WebRtcIsac_DecorrelateIntraVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
int16_t bandwidth)
|
||||
{
|
||||
const double* ptrData;
|
||||
const double* ptrRow;
|
||||
int16_t rowCntr;
|
||||
int16_t colCntr;
|
||||
int16_t larVecCntr;
|
||||
int16_t numVec;
|
||||
const double* decorrMat;
|
||||
switch(bandwidth)
|
||||
{
|
||||
case isac12kHz:
|
||||
{
|
||||
decorrMat = &WebRtcIsac_kIntraVecDecorrMatUb12[0][0];
|
||||
numVec = UB_LPC_VEC_PER_FRAME;
|
||||
break;
|
||||
}
|
||||
case isac16kHz:
|
||||
{
|
||||
decorrMat = &WebRtcIsac_kIintraVecDecorrMatUb16[0][0];
|
||||
numVec = UB16_LPC_VEC_PER_FRAME;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// decorrMat * data
|
||||
//
|
||||
// data is assumed to contain 'numVec' of LAR
|
||||
// vectors (mean removed) each of dimension 'UB_LPC_ORDER'
|
||||
// concatenated one after the other.
|
||||
//
|
||||
|
||||
ptrData = data;
|
||||
for(larVecCntr = 0; larVecCntr < numVec; larVecCntr++)
|
||||
{
|
||||
for(rowCntr = 0; rowCntr < UB_LPC_ORDER; rowCntr++)
|
||||
{
|
||||
ptrRow = &decorrMat[rowCntr * UB_LPC_ORDER];
|
||||
*out = 0;
|
||||
for(colCntr = 0; colCntr < UB_LPC_ORDER; colCntr++)
|
||||
{
|
||||
*out += ptrData[colCntr] * ptrRow[colCntr];
|
||||
}
|
||||
out++;
|
||||
}
|
||||
ptrData += UB_LPC_ORDER;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecorrelateInterVec()
|
||||
*
|
||||
* Remover the correlation among mean-removed LAR vectors. If LAR vectors
|
||||
* of one frame are put in a matrix where each column is a LAR vector of a
|
||||
* sub-frame, then this is equivalent to multiplying the LAR matrix with
|
||||
* a decorrelting mtrix from right.
|
||||
*
|
||||
* Input:
|
||||
* -data : pointer to matrix of LAR vectors. The matrix
|
||||
* is stored column-wise.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : decorrelated LAR vectors.
|
||||
*/
|
||||
int16_t
|
||||
WebRtcIsac_DecorrelateInterVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
int16_t bandwidth)
|
||||
{
|
||||
int16_t coeffCntr;
|
||||
int16_t rowCntr;
|
||||
int16_t colCntr;
|
||||
const double* decorrMat;
|
||||
int16_t interVecDim;
|
||||
|
||||
switch(bandwidth)
|
||||
{
|
||||
case isac12kHz:
|
||||
{
|
||||
decorrMat = &WebRtcIsac_kInterVecDecorrMatUb12[0][0];
|
||||
interVecDim = UB_LPC_VEC_PER_FRAME;
|
||||
break;
|
||||
}
|
||||
case isac16kHz:
|
||||
{
|
||||
decorrMat = &WebRtcIsac_kInterVecDecorrMatUb16[0][0];
|
||||
interVecDim = UB16_LPC_VEC_PER_FRAME;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// data * decorrMat
|
||||
//
|
||||
// data is of size 'interVecDim' * 'UB_LPC_ORDER'
|
||||
// That is 'interVecDim' of LAR vectors (mean removed)
|
||||
// in columns each of dimension 'UB_LPC_ORDER'.
|
||||
// matrix is stored column-wise.
|
||||
//
|
||||
|
||||
for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++)
|
||||
{
|
||||
for(colCntr = 0; colCntr < interVecDim; colCntr++)
|
||||
{
|
||||
out[coeffCntr + colCntr * UB_LPC_ORDER] = 0;
|
||||
for(rowCntr = 0; rowCntr < interVecDim; rowCntr++)
|
||||
{
|
||||
out[coeffCntr + colCntr * UB_LPC_ORDER] +=
|
||||
data[coeffCntr + rowCntr * UB_LPC_ORDER] *
|
||||
decorrMat[rowCntr * interVecDim + colCntr];
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_QuantizeUncorrLar()
|
||||
*
|
||||
* Quantize the uncorrelated parameters.
|
||||
*
|
||||
* Input:
|
||||
* -data : uncorrelated LAR vectors.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -data : quantized version of the input.
|
||||
* -idx : pointer to quantization indices.
|
||||
*/
|
||||
double
|
||||
WebRtcIsac_QuantizeUncorrLar(
|
||||
double* data,
|
||||
int* recIdx,
|
||||
int16_t bandwidth)
|
||||
{
|
||||
int16_t cntr;
|
||||
int32_t idx;
|
||||
int16_t interVecDim;
|
||||
const double* leftRecPoint;
|
||||
double quantizationStepSize;
|
||||
const int16_t* numQuantCell;
|
||||
switch(bandwidth)
|
||||
{
|
||||
case isac12kHz:
|
||||
{
|
||||
leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb12;
|
||||
quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb12;
|
||||
numQuantCell = WebRtcIsac_kLpcShapeNumRecPointUb12;
|
||||
interVecDim = UB_LPC_VEC_PER_FRAME;
|
||||
break;
|
||||
}
|
||||
case isac16kHz:
|
||||
{
|
||||
leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb16;
|
||||
quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb16;
|
||||
numQuantCell = WebRtcIsac_kLpcShapeNumRecPointUb16;
|
||||
interVecDim = UB16_LPC_VEC_PER_FRAME;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// Quantize the parametrs.
|
||||
//
|
||||
for(cntr = 0; cntr < UB_LPC_ORDER * interVecDim; cntr++)
|
||||
{
|
||||
idx = (int32_t)floor((*data - leftRecPoint[cntr]) /
|
||||
quantizationStepSize + 0.5);
|
||||
if(idx < 0)
|
||||
{
|
||||
idx = 0;
|
||||
}
|
||||
else if(idx >= numQuantCell[cntr])
|
||||
{
|
||||
idx = numQuantCell[cntr] - 1;
|
||||
}
|
||||
|
||||
*data++ = leftRecPoint[cntr] + idx * quantizationStepSize;
|
||||
*recIdx++ = idx;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DequantizeLpcParam()
|
||||
*
|
||||
* Get the quantized value of uncorrelated LARs given the quantization indices.
|
||||
*
|
||||
* Input:
|
||||
* -idx : pointer to quantiztion indices.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : pointer to quantized values.
|
||||
*/
|
||||
int16_t
|
||||
WebRtcIsac_DequantizeLpcParam(
|
||||
const int* idx,
|
||||
double* out,
|
||||
int16_t bandwidth)
|
||||
{
|
||||
int16_t cntr;
|
||||
int16_t interVecDim;
|
||||
const double* leftRecPoint;
|
||||
double quantizationStepSize;
|
||||
|
||||
switch(bandwidth)
|
||||
{
|
||||
case isac12kHz:
|
||||
{
|
||||
leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb12;
|
||||
quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb12;
|
||||
interVecDim = UB_LPC_VEC_PER_FRAME;
|
||||
break;
|
||||
}
|
||||
case isac16kHz:
|
||||
{
|
||||
leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb16;
|
||||
quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb16;
|
||||
interVecDim = UB16_LPC_VEC_PER_FRAME;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
//
|
||||
// Dequantize given the quantization indices
|
||||
//
|
||||
|
||||
for(cntr = 0; cntr < UB_LPC_ORDER * interVecDim; cntr++)
|
||||
{
|
||||
*out++ = leftRecPoint[cntr] + *idx++ * quantizationStepSize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_CorrelateIntraVec()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_DecorrelateIntraVec().
|
||||
*
|
||||
* Input:
|
||||
* -data : uncorrelated parameters.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : correlated parametrs.
|
||||
*/
|
||||
int16_t
|
||||
WebRtcIsac_CorrelateIntraVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
int16_t bandwidth)
|
||||
{
|
||||
int16_t vecCntr;
|
||||
int16_t rowCntr;
|
||||
int16_t colCntr;
|
||||
int16_t numVec;
|
||||
const double* ptrData;
|
||||
const double* intraVecDecorrMat;
|
||||
|
||||
switch(bandwidth)
|
||||
{
|
||||
case isac12kHz:
|
||||
{
|
||||
numVec = UB_LPC_VEC_PER_FRAME;
|
||||
intraVecDecorrMat = &WebRtcIsac_kIntraVecDecorrMatUb12[0][0];
|
||||
break;
|
||||
}
|
||||
case isac16kHz:
|
||||
{
|
||||
numVec = UB16_LPC_VEC_PER_FRAME;
|
||||
intraVecDecorrMat = &WebRtcIsac_kIintraVecDecorrMatUb16[0][0];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
ptrData = data;
|
||||
for(vecCntr = 0; vecCntr < numVec; vecCntr++)
|
||||
{
|
||||
for(colCntr = 0; colCntr < UB_LPC_ORDER; colCntr++)
|
||||
{
|
||||
*out = 0;
|
||||
for(rowCntr = 0; rowCntr < UB_LPC_ORDER; rowCntr++)
|
||||
{
|
||||
*out += ptrData[rowCntr] *
|
||||
intraVecDecorrMat[rowCntr * UB_LPC_ORDER + colCntr];
|
||||
}
|
||||
out++;
|
||||
}
|
||||
ptrData += UB_LPC_ORDER;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_CorrelateInterVec()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_DecorrelateInterVec().
|
||||
*
|
||||
* Input:
|
||||
* -data
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : correlated parametrs.
|
||||
*/
|
||||
int16_t
|
||||
WebRtcIsac_CorrelateInterVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
int16_t bandwidth)
|
||||
{
|
||||
int16_t coeffCntr;
|
||||
int16_t rowCntr;
|
||||
int16_t colCntr;
|
||||
int16_t interVecDim;
|
||||
double myVec[UB16_LPC_VEC_PER_FRAME];
|
||||
const double* interVecDecorrMat;
|
||||
|
||||
switch(bandwidth)
|
||||
{
|
||||
case isac12kHz:
|
||||
{
|
||||
interVecDim = UB_LPC_VEC_PER_FRAME;
|
||||
interVecDecorrMat = &WebRtcIsac_kInterVecDecorrMatUb12[0][0];
|
||||
break;
|
||||
}
|
||||
case isac16kHz:
|
||||
{
|
||||
interVecDim = UB16_LPC_VEC_PER_FRAME;
|
||||
interVecDecorrMat = &WebRtcIsac_kInterVecDecorrMatUb16[0][0];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++)
|
||||
{
|
||||
for(rowCntr = 0; rowCntr < interVecDim; rowCntr++)
|
||||
{
|
||||
myVec[rowCntr] = 0;
|
||||
for(colCntr = 0; colCntr < interVecDim; colCntr++)
|
||||
{
|
||||
myVec[rowCntr] += data[coeffCntr + colCntr * UB_LPC_ORDER] * //*ptrData *
|
||||
interVecDecorrMat[rowCntr * interVecDim + colCntr];
|
||||
//ptrData += UB_LPC_ORDER;
|
||||
}
|
||||
}
|
||||
|
||||
for(rowCntr = 0; rowCntr < interVecDim; rowCntr++)
|
||||
{
|
||||
out[coeffCntr + rowCntr * UB_LPC_ORDER] = myVec[rowCntr];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_AddLarMean()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_RemoveLarMean()
|
||||
*
|
||||
* Input:
|
||||
* -data : pointer to mean-removed LAR:s.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -data : pointer to LARs.
|
||||
*/
|
||||
int16_t
|
||||
WebRtcIsac_AddLarMean(
|
||||
double* data,
|
||||
int16_t bandwidth)
|
||||
{
|
||||
int16_t coeffCntr;
|
||||
int16_t vecCntr;
|
||||
int16_t numVec;
|
||||
const double* meanLAR;
|
||||
|
||||
switch(bandwidth)
|
||||
{
|
||||
case isac12kHz:
|
||||
{
|
||||
numVec = UB_LPC_VEC_PER_FRAME;
|
||||
meanLAR = WebRtcIsac_kMeanLarUb12;
|
||||
break;
|
||||
}
|
||||
case isac16kHz:
|
||||
{
|
||||
numVec = UB16_LPC_VEC_PER_FRAME;
|
||||
meanLAR = WebRtcIsac_kMeanLarUb16;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(vecCntr = 0; vecCntr < numVec; vecCntr++)
|
||||
{
|
||||
for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++)
|
||||
{
|
||||
*data++ += meanLAR[coeffCntr];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_ToLogDomainRemoveMean()
|
||||
*
|
||||
* Transform the LPC gain to log domain then remove the mean value.
|
||||
*
|
||||
* Input:
|
||||
* -lpcGain : pointer to LPC Gain, expecting 6 LPC gains
|
||||
*
|
||||
* Output:
|
||||
* -lpcGain : mean-removed in log domain.
|
||||
*/
|
||||
int16_t
|
||||
WebRtcIsac_ToLogDomainRemoveMean(
|
||||
double* data)
|
||||
{
|
||||
int16_t coeffCntr;
|
||||
for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++)
|
||||
{
|
||||
data[coeffCntr] = log(data[coeffCntr]) - WebRtcIsac_kMeanLpcGain;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecorrelateLPGain()
|
||||
*
|
||||
* Decorrelate LPC gains. There are 6 LPC Gains per frame. This is like
|
||||
* multiplying gain vector with decorrelating matrix.
|
||||
*
|
||||
* Input:
|
||||
* -data : LPC gain in log-domain with mean removed.
|
||||
*
|
||||
* Output:
|
||||
* -out : decorrelated parameters.
|
||||
*/
|
||||
int16_t WebRtcIsac_DecorrelateLPGain(
|
||||
const double* data,
|
||||
double* out)
|
||||
{
|
||||
int16_t rowCntr;
|
||||
int16_t colCntr;
|
||||
|
||||
for(colCntr = 0; colCntr < UB_LPC_GAIN_DIM; colCntr++)
|
||||
{
|
||||
*out = 0;
|
||||
for(rowCntr = 0; rowCntr < UB_LPC_GAIN_DIM; rowCntr++)
|
||||
{
|
||||
*out += data[rowCntr] * WebRtcIsac_kLpcGainDecorrMat[rowCntr][colCntr];
|
||||
}
|
||||
out++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_QuantizeLpcGain()
|
||||
*
|
||||
* Quantize the decorrelated log-domain gains.
|
||||
*
|
||||
* Input:
|
||||
* -lpcGain : uncorrelated LPC gains.
|
||||
*
|
||||
* Output:
|
||||
* -idx : quantization indices
|
||||
* -lpcGain : quantized value of the inpt.
|
||||
*/
|
||||
double WebRtcIsac_QuantizeLpcGain(
|
||||
double* data,
|
||||
int* idx)
|
||||
{
|
||||
int16_t coeffCntr;
|
||||
for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++)
|
||||
{
|
||||
*idx = (int)floor((*data - WebRtcIsac_kLeftRecPointLpcGain[coeffCntr]) /
|
||||
WebRtcIsac_kQSizeLpcGain + 0.5);
|
||||
|
||||
if(*idx < 0)
|
||||
{
|
||||
*idx = 0;
|
||||
}
|
||||
else if(*idx >= WebRtcIsac_kNumQCellLpcGain[coeffCntr])
|
||||
{
|
||||
*idx = WebRtcIsac_kNumQCellLpcGain[coeffCntr] - 1;
|
||||
}
|
||||
*data = WebRtcIsac_kLeftRecPointLpcGain[coeffCntr] + *idx *
|
||||
WebRtcIsac_kQSizeLpcGain;
|
||||
|
||||
data++;
|
||||
idx++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DequantizeLpcGain()
|
||||
*
|
||||
* Get the quantized values given the quantization indices.
|
||||
*
|
||||
* Input:
|
||||
* -idx : pointer to quantization indices.
|
||||
*
|
||||
* Output:
|
||||
* -lpcGains : quantized values of the given parametes.
|
||||
*/
|
||||
int16_t WebRtcIsac_DequantizeLpcGain(
|
||||
const int* idx,
|
||||
double* out)
|
||||
{
|
||||
int16_t coeffCntr;
|
||||
for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++)
|
||||
{
|
||||
*out = WebRtcIsac_kLeftRecPointLpcGain[coeffCntr] + *idx *
|
||||
WebRtcIsac_kQSizeLpcGain;
|
||||
out++;
|
||||
idx++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_CorrelateLpcGain()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_DecorrelateLPGain().
|
||||
*
|
||||
* Input:
|
||||
* -data : decorrelated parameters.
|
||||
*
|
||||
* Output:
|
||||
* -out : correlated parameters.
|
||||
*/
|
||||
int16_t WebRtcIsac_CorrelateLpcGain(
|
||||
const double* data,
|
||||
double* out)
|
||||
{
|
||||
int16_t rowCntr;
|
||||
int16_t colCntr;
|
||||
|
||||
for(rowCntr = 0; rowCntr < UB_LPC_GAIN_DIM; rowCntr++)
|
||||
{
|
||||
*out = 0;
|
||||
for(colCntr = 0; colCntr < UB_LPC_GAIN_DIM; colCntr++)
|
||||
{
|
||||
*out += WebRtcIsac_kLpcGainDecorrMat[rowCntr][colCntr] * data[colCntr];
|
||||
}
|
||||
out++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_AddMeanToLinearDomain()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_ToLogDomainRemoveMean().
|
||||
*
|
||||
* Input:
|
||||
* -lpcGain : LPC gain in log-domain & mean removed
|
||||
*
|
||||
* Output:
|
||||
* -lpcGain : LPC gain in normal domain.
|
||||
*/
|
||||
int16_t WebRtcIsac_AddMeanToLinearDomain(
|
||||
double* lpcGains)
|
||||
{
|
||||
int16_t coeffCntr;
|
||||
for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++)
|
||||
{
|
||||
lpcGains[coeffCntr] = exp(lpcGains[coeffCntr] + WebRtcIsac_kMeanLpcGain);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* encode_lpc_swb.h
|
||||
*
|
||||
* This file contains declaration of functions used to
|
||||
* encode LPC parameters (Shape & gain) of the upper band.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
|
||||
|
||||
#include "settings.h"
|
||||
#include "structs.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_RemoveLarMean()
|
||||
*
|
||||
* Remove the means from LAR coefficients.
|
||||
*
|
||||
* Input:
|
||||
* -lar : pointer to lar vectors. LAR vectors are
|
||||
* concatenated.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -lar : pointer to mean-removed LAR:s.
|
||||
*
|
||||
*
|
||||
*/
|
||||
int16_t WebRtcIsac_RemoveLarMean(
|
||||
double* lar,
|
||||
int16_t bandwidth);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecorrelateIntraVec()
|
||||
*
|
||||
* Remove the correlation amonge the components of LAR vectors. If LAR vectors
|
||||
* of one frame are put in a matrix where each column is a LAR vector of a
|
||||
* sub-frame, then this is equivalent to multiplying the LAR matrix with
|
||||
* a decorrelting mtrix from left.
|
||||
*
|
||||
* Input:
|
||||
* -inLar : pointer to mean-removed LAR vecrtors.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : decorrelated LAR vectors.
|
||||
*/
|
||||
int16_t WebRtcIsac_DecorrelateIntraVec(
|
||||
const double* inLAR,
|
||||
double* out,
|
||||
int16_t bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecorrelateInterVec()
|
||||
*
|
||||
* Remover the correlation among mean-removed LAR vectors. If LAR vectors
|
||||
* of one frame are put in a matrix where each column is a LAR vector of a
|
||||
* sub-frame, then this is equivalent to multiplying the LAR matrix with
|
||||
* a decorrelting mtrix from right.
|
||||
*
|
||||
* Input:
|
||||
* -data : pointer to matrix of LAR vectors. The matrix
|
||||
* is stored column-wise.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : decorrelated LAR vectors.
|
||||
*/
|
||||
int16_t WebRtcIsac_DecorrelateInterVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
int16_t bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_QuantizeUncorrLar()
|
||||
*
|
||||
* Quantize the uncorrelated parameters.
|
||||
*
|
||||
* Input:
|
||||
* -data : uncorrelated LAR vectors.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -data : quantized version of the input.
|
||||
* -idx : pointer to quantization indices.
|
||||
*/
|
||||
double WebRtcIsac_QuantizeUncorrLar(
|
||||
double* data,
|
||||
int* idx,
|
||||
int16_t bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_CorrelateIntraVec()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_DecorrelateIntraVec().
|
||||
*
|
||||
* Input:
|
||||
* -data : uncorrelated parameters.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : correlated parametrs.
|
||||
*/
|
||||
int16_t WebRtcIsac_CorrelateIntraVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
int16_t bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_CorrelateInterVec()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_DecorrelateInterVec().
|
||||
*
|
||||
* Input:
|
||||
* -data
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : correlated parametrs.
|
||||
*/
|
||||
int16_t WebRtcIsac_CorrelateInterVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
int16_t bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_AddLarMean()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_RemoveLarMean()
|
||||
*
|
||||
* Input:
|
||||
* -data : pointer to mean-removed LAR:s.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -data : pointer to LARs.
|
||||
*/
|
||||
int16_t WebRtcIsac_AddLarMean(
|
||||
double* data,
|
||||
int16_t bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DequantizeLpcParam()
|
||||
*
|
||||
* Get the quantized value of uncorrelated LARs given the quantization indices.
|
||||
*
|
||||
* Input:
|
||||
* -idx : pointer to quantiztion indices.
|
||||
* -bandwidth : indicates if the given LAR vectors belong
|
||||
* to SWB-12kHz or SWB-16kHz.
|
||||
*
|
||||
* Output:
|
||||
* -out : pointer to quantized values.
|
||||
*/
|
||||
int16_t WebRtcIsac_DequantizeLpcParam(
|
||||
const int* idx,
|
||||
double* out,
|
||||
int16_t bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_ToLogDomainRemoveMean()
|
||||
*
|
||||
* Transform the LPC gain to log domain then remove the mean value.
|
||||
*
|
||||
* Input:
|
||||
* -lpcGain : pointer to LPC Gain, expecting 6 LPC gains
|
||||
*
|
||||
* Output:
|
||||
* -lpcGain : mean-removed in log domain.
|
||||
*/
|
||||
int16_t WebRtcIsac_ToLogDomainRemoveMean(
|
||||
double* lpGains);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecorrelateLPGain()
|
||||
*
|
||||
* Decorrelate LPC gains. There are 6 LPC Gains per frame. This is like
|
||||
* multiplying gain vector with decorrelating matrix.
|
||||
*
|
||||
* Input:
|
||||
* -data : LPC gain in log-domain with mean removed.
|
||||
*
|
||||
* Output:
|
||||
* -out : decorrelated parameters.
|
||||
*/
|
||||
int16_t WebRtcIsac_DecorrelateLPGain(
|
||||
const double* data,
|
||||
double* out);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_QuantizeLpcGain()
|
||||
*
|
||||
* Quantize the decorrelated log-domain gains.
|
||||
*
|
||||
* Input:
|
||||
* -lpcGain : uncorrelated LPC gains.
|
||||
*
|
||||
* Output:
|
||||
* -idx : quantization indices
|
||||
* -lpcGain : quantized value of the inpt.
|
||||
*/
|
||||
double WebRtcIsac_QuantizeLpcGain(
|
||||
double* lpGains,
|
||||
int* idx);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DequantizeLpcGain()
|
||||
*
|
||||
* Get the quantized values given the quantization indices.
|
||||
*
|
||||
* Input:
|
||||
* -idx : pointer to quantization indices.
|
||||
*
|
||||
* Output:
|
||||
* -lpcGains : quantized values of the given parametes.
|
||||
*/
|
||||
int16_t WebRtcIsac_DequantizeLpcGain(
|
||||
const int* idx,
|
||||
double* lpGains);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_CorrelateLpcGain()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_DecorrelateLPGain().
|
||||
*
|
||||
* Input:
|
||||
* -data : decorrelated parameters.
|
||||
*
|
||||
* Output:
|
||||
* -out : correlated parameters.
|
||||
*/
|
||||
int16_t WebRtcIsac_CorrelateLpcGain(
|
||||
const double* data,
|
||||
double* out);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_AddMeanToLinearDomain()
|
||||
*
|
||||
* This is the inverse of WebRtcIsac_ToLogDomainRemoveMean().
|
||||
*
|
||||
* Input:
|
||||
* -lpcGain : LPC gain in log-domain & mean removed
|
||||
*
|
||||
* Output:
|
||||
* -lpcGain : LPC gain in normal domain.
|
||||
*/
|
||||
int16_t WebRtcIsac_AddMeanToLinearDomain(
|
||||
double* lpcGains);
|
||||
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
|
||||
2066
webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.c
Normal file
2066
webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* entropy_coding.h
|
||||
*
|
||||
* This header file declares all of the functions used to arithmetically
|
||||
* encode the iSAC bistream
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_
|
||||
|
||||
#include "settings.h"
|
||||
#include "structs.h"
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeSpec()
|
||||
* Decode real and imaginary part of the DFT coefficients, given a bit-stream.
|
||||
* The decoded DFT coefficient can be transformed to time domain by
|
||||
* WebRtcIsac_Time2Spec().
|
||||
*
|
||||
* Input:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
* - AvgPitchGain_Q12 : average pitch-gain of the frame. This is only
|
||||
* relevant for 0-4 kHz band, and the input value is
|
||||
* not used in other bands.
|
||||
* - band : specifies which band's DFT should be decoded.
|
||||
*
|
||||
* Output:
|
||||
* - *fr : pointer to a buffer where the real part of DFT
|
||||
* coefficients are written to.
|
||||
* - *fi : pointer to a buffer where the imaginary part
|
||||
* of DFT coefficients are written to.
|
||||
*
|
||||
* Return value : < 0 if an error occures
|
||||
* 0 if succeeded.
|
||||
*/
|
||||
int WebRtcIsac_DecodeSpec(Bitstr* streamdata, int16_t AvgPitchGain_Q12,
|
||||
enum ISACBand band, double* fr, double* fi);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeSpec()
|
||||
* Encode real and imaginary part of the DFT coefficients into the given
|
||||
* bit-stream.
|
||||
*
|
||||
* Input:
|
||||
* - *fr : pointer to a buffer where the real part of DFT
|
||||
* coefficients are written to.
|
||||
* - *fi : pointer to a buffer where the imaginary part
|
||||
* of DFT coefficients are written to.
|
||||
* - AvgPitchGain_Q12 : average pitch-gain of the frame. This is only
|
||||
* relevant for 0-4 kHz band, and the input value is
|
||||
* not used in other bands.
|
||||
* - band : specifies which band's DFT should be decoded.
|
||||
*
|
||||
* Output:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Return value : < 0 if an error occures
|
||||
* 0 if succeeded.
|
||||
*/
|
||||
int WebRtcIsac_EncodeSpec(const int16_t* fr, const int16_t* fi,
|
||||
int16_t AvgPitchGain_Q12, enum ISACBand band,
|
||||
Bitstr* streamdata);
|
||||
|
||||
/* decode & dequantize LPC Coef */
|
||||
int WebRtcIsac_DecodeLpcCoef(Bitstr* streamdata, double* LPCCoef);
|
||||
int WebRtcIsac_DecodeLpcCoefUB(Bitstr* streamdata, double* lpcVecs,
|
||||
double* percepFilterGains,
|
||||
int16_t bandwidth);
|
||||
|
||||
int WebRtcIsac_DecodeLpc(Bitstr* streamdata, double* LPCCoef_lo,
|
||||
double* LPCCoef_hi);
|
||||
|
||||
/* quantize & code LPC Coef */
|
||||
void WebRtcIsac_EncodeLpcLb(double* LPCCoef_lo, double* LPCCoef_hi,
|
||||
Bitstr* streamdata, IsacSaveEncoderData* encData);
|
||||
|
||||
void WebRtcIsac_EncodeLpcGainLb(double* LPCCoef_lo, double* LPCCoef_hi,
|
||||
Bitstr* streamdata,
|
||||
IsacSaveEncoderData* encData);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeLpcUB()
|
||||
* Encode LPC parameters, given as A-polynomial, of upper-band. The encoding
|
||||
* is performed in LAR domain.
|
||||
* For the upper-band, we compute and encode LPC of some sub-frames, LPC of
|
||||
* other sub-frames are computed by linear interpolation, in LAR domain. This
|
||||
* function performs the interpolation and returns the LPC of all sub-frames.
|
||||
*
|
||||
* Inputs:
|
||||
* - lpcCoef : a buffer containing A-polynomials of sub-frames
|
||||
* (excluding first coefficient that is 1).
|
||||
* - bandwidth : specifies if the codec is operating at 0-12 kHz
|
||||
* or 0-16 kHz mode.
|
||||
*
|
||||
* Input/output:
|
||||
* - streamdata : pointer to a structure containing the encoded
|
||||
* data and the parameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Output:
|
||||
* - interpolLPCCoeff : Decoded and interpolated LPC (A-polynomial)
|
||||
* of all sub-frames.
|
||||
* If LP analysis is of order K, and there are N
|
||||
* sub-frames then this is a buffer of size
|
||||
* (k + 1) * N, each vector starts with the LPC gain
|
||||
* of the corresponding sub-frame. The LPC gains
|
||||
* are encoded and inserted after this function is
|
||||
* called. The first A-coefficient which is 1 is not
|
||||
* included.
|
||||
*
|
||||
* Return value : 0 if encoding is successful,
|
||||
* <0 if failed to encode.
|
||||
*/
|
||||
int16_t WebRtcIsac_EncodeLpcUB(double* lpcCoeff, Bitstr* streamdata,
|
||||
double* interpolLPCCoeff,
|
||||
int16_t bandwidth,
|
||||
ISACUBSaveEncDataStruct* encData);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeInterpolLpcUb()
|
||||
* Decode LPC coefficients and interpolate to get the coefficients fo all
|
||||
* sub-frmaes.
|
||||
*
|
||||
* Inputs:
|
||||
* - bandwidth : spepecifies if the codec is in 0-12 kHz or
|
||||
* 0-16 kHz mode.
|
||||
*
|
||||
* Input/output:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Output:
|
||||
* - percepFilterParam : Decoded and interpolated LPC (A-polynomial) of
|
||||
* all sub-frames.
|
||||
* If LP analysis is of order K, and there are N
|
||||
* sub-frames then this is a buffer of size
|
||||
* (k + 1) * N, each vector starts with the LPC gain
|
||||
* of the corresponding sub-frame. The LPC gains
|
||||
* are encoded and inserted after this function is
|
||||
* called. The first A-coefficient which is 1 is not
|
||||
* included.
|
||||
*
|
||||
* Return value : 0 if encoding is successful,
|
||||
* <0 if failed to encode.
|
||||
*/
|
||||
int16_t WebRtcIsac_DecodeInterpolLpcUb(Bitstr* streamdata,
|
||||
double* percepFilterParam,
|
||||
int16_t bandwidth);
|
||||
|
||||
/* Decode & dequantize RC */
|
||||
int WebRtcIsac_DecodeRc(Bitstr* streamdata, int16_t* RCQ15);
|
||||
|
||||
/* Quantize & code RC */
|
||||
void WebRtcIsac_EncodeRc(int16_t* RCQ15, Bitstr* streamdata);
|
||||
|
||||
/* Decode & dequantize squared Gain */
|
||||
int WebRtcIsac_DecodeGain2(Bitstr* streamdata, int32_t* Gain2);
|
||||
|
||||
/* Quantize & code squared Gain (input is squared gain) */
|
||||
int WebRtcIsac_EncodeGain2(int32_t* gain2, Bitstr* streamdata);
|
||||
|
||||
void WebRtcIsac_EncodePitchGain(int16_t* PitchGains_Q12,
|
||||
Bitstr* streamdata,
|
||||
IsacSaveEncoderData* encData);
|
||||
|
||||
void WebRtcIsac_EncodePitchLag(double* PitchLags,
|
||||
int16_t* PitchGain_Q12,
|
||||
Bitstr* streamdata,
|
||||
IsacSaveEncoderData* encData);
|
||||
|
||||
int WebRtcIsac_DecodePitchGain(Bitstr* streamdata,
|
||||
int16_t* PitchGain_Q12);
|
||||
int WebRtcIsac_DecodePitchLag(Bitstr* streamdata, int16_t* PitchGain_Q12,
|
||||
double* PitchLag);
|
||||
|
||||
int WebRtcIsac_DecodeFrameLen(Bitstr* streamdata, int16_t* framelength);
|
||||
int WebRtcIsac_EncodeFrameLen(int16_t framelength, Bitstr* streamdata);
|
||||
int WebRtcIsac_DecodeSendBW(Bitstr* streamdata, int16_t* BWno);
|
||||
void WebRtcIsac_EncodeReceiveBw(int* BWno, Bitstr* streamdata);
|
||||
|
||||
/* Step-down */
|
||||
void WebRtcIsac_Poly2Rc(double* a, int N, double* RC);
|
||||
|
||||
/* Step-up */
|
||||
void WebRtcIsac_Rc2Poly(double* RC, int N, double* a);
|
||||
|
||||
void WebRtcIsac_TranscodeLPCCoef(double* LPCCoef_lo, double* LPCCoef_hi,
|
||||
int* index_g);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeLpcGainUb()
|
||||
* Encode LPC gains of sub-Frames.
|
||||
*
|
||||
* Input/outputs:
|
||||
* - lpGains : a buffer which contains 'SUBFRAME' number of
|
||||
* LP gains to be encoded. The input values are
|
||||
* overwritten by the quantized values.
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Output:
|
||||
* - lpcGainIndex : quantization indices for lpc gains, these will
|
||||
* be stored to be used for FEC.
|
||||
*/
|
||||
void WebRtcIsac_EncodeLpcGainUb(double* lpGains, Bitstr* streamdata,
|
||||
int* lpcGainIndex);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeLpcGainUb()
|
||||
* Store LPC gains of sub-Frames in 'streamdata'.
|
||||
*
|
||||
* Input:
|
||||
* - lpGains : a buffer which contains 'SUBFRAME' number of
|
||||
* LP gains to be encoded.
|
||||
* Input/outputs:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
*/
|
||||
void WebRtcIsac_StoreLpcGainUb(double* lpGains, Bitstr* streamdata);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeLpcGainUb()
|
||||
* Decode the LPC gain of sub-frames.
|
||||
*
|
||||
* Input/output:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Output:
|
||||
* - lpGains : a buffer where decoded LPC gians will be stored.
|
||||
*
|
||||
* Return value : 0 if succeeded.
|
||||
* <0 if failed.
|
||||
*/
|
||||
int16_t WebRtcIsac_DecodeLpcGainUb(double* lpGains, Bitstr* streamdata);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeBandwidth()
|
||||
* Encode if the bandwidth of encoded audio is 0-12 kHz or 0-16 kHz.
|
||||
*
|
||||
* Input:
|
||||
* - bandwidth : an enumerator specifying if the codec in is
|
||||
* 0-12 kHz or 0-16 kHz mode.
|
||||
*
|
||||
* Input/output:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Return value : 0 if succeeded.
|
||||
* <0 if failed.
|
||||
*/
|
||||
int16_t WebRtcIsac_EncodeBandwidth(enum ISACBandwidth bandwidth,
|
||||
Bitstr* streamData);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeBandwidth()
|
||||
* Decode the bandwidth of the encoded audio, i.e. if the bandwidth is 0-12 kHz
|
||||
* or 0-16 kHz.
|
||||
*
|
||||
* Input/output:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Output:
|
||||
* - bandwidth : an enumerator specifying if the codec is in
|
||||
* 0-12 kHz or 0-16 kHz mode.
|
||||
*
|
||||
* Return value : 0 if succeeded.
|
||||
* <0 if failed.
|
||||
*/
|
||||
int16_t WebRtcIsac_DecodeBandwidth(Bitstr* streamData,
|
||||
enum ISACBandwidth* bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeJitterInfo()
|
||||
* Decode the jitter information.
|
||||
*
|
||||
* Input/output:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Input:
|
||||
* - jitterInfo : one bit of info specifying if the channel is
|
||||
* in high/low jitter. Zero indicates low jitter
|
||||
* and one indicates high jitter.
|
||||
*
|
||||
* Return value : 0 if succeeded.
|
||||
* <0 if failed.
|
||||
*/
|
||||
int16_t WebRtcIsac_EncodeJitterInfo(int32_t jitterIndex,
|
||||
Bitstr* streamData);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeJitterInfo()
|
||||
* Decode the jitter information.
|
||||
*
|
||||
* Input/output:
|
||||
* - streamdata : pointer to a stucture containg the encoded
|
||||
* data and theparameters needed for entropy
|
||||
* coding.
|
||||
*
|
||||
* Output:
|
||||
* - jitterInfo : one bit of info specifying if the channel is
|
||||
* in high/low jitter. Zero indicates low jitter
|
||||
* and one indicates high jitter.
|
||||
*
|
||||
* Return value : 0 if succeeded.
|
||||
* <0 if failed.
|
||||
*/
|
||||
int16_t WebRtcIsac_DecodeJitterInfo(Bitstr* streamData,
|
||||
int32_t* jitterInfo);
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_ */
|
||||
@@ -0,0 +1,535 @@
|
||||
/*
|
||||
* 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 "lpc_analysis.h"
|
||||
#include "settings.h"
|
||||
#include "codec.h"
|
||||
#include "entropy_coding.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LEVINSON_EPS 1.0e-10
|
||||
|
||||
|
||||
/* window */
|
||||
/* Matlab generation code:
|
||||
* t = (1:256)/257; r = 1-(1-t).^.45; w = sin(r*pi).^3; w = w/sum(w); plot((1:256)/8, w); grid;
|
||||
* for k=1:16, fprintf(1, '%.8f, ', w(k*16 + (-15:0))); fprintf(1, '\n'); end
|
||||
*/
|
||||
static const double kLpcCorrWindow[WINLEN] = {
|
||||
0.00000000, 0.00000001, 0.00000004, 0.00000010, 0.00000020,
|
||||
0.00000035, 0.00000055, 0.00000083, 0.00000118, 0.00000163,
|
||||
0.00000218, 0.00000283, 0.00000361, 0.00000453, 0.00000558, 0.00000679,
|
||||
0.00000817, 0.00000973, 0.00001147, 0.00001342, 0.00001558,
|
||||
0.00001796, 0.00002058, 0.00002344, 0.00002657, 0.00002997,
|
||||
0.00003365, 0.00003762, 0.00004190, 0.00004651, 0.00005144, 0.00005673,
|
||||
0.00006236, 0.00006837, 0.00007476, 0.00008155, 0.00008875,
|
||||
0.00009636, 0.00010441, 0.00011290, 0.00012186, 0.00013128,
|
||||
0.00014119, 0.00015160, 0.00016252, 0.00017396, 0.00018594, 0.00019846,
|
||||
0.00021155, 0.00022521, 0.00023946, 0.00025432, 0.00026978,
|
||||
0.00028587, 0.00030260, 0.00031998, 0.00033802, 0.00035674,
|
||||
0.00037615, 0.00039626, 0.00041708, 0.00043863, 0.00046092, 0.00048396,
|
||||
0.00050775, 0.00053233, 0.00055768, 0.00058384, 0.00061080,
|
||||
0.00063858, 0.00066720, 0.00069665, 0.00072696, 0.00075813,
|
||||
0.00079017, 0.00082310, 0.00085692, 0.00089164, 0.00092728, 0.00096384,
|
||||
0.00100133, 0.00103976, 0.00107914, 0.00111947, 0.00116077,
|
||||
0.00120304, 0.00124630, 0.00129053, 0.00133577, 0.00138200,
|
||||
0.00142924, 0.00147749, 0.00152676, 0.00157705, 0.00162836, 0.00168070,
|
||||
0.00173408, 0.00178850, 0.00184395, 0.00190045, 0.00195799,
|
||||
0.00201658, 0.00207621, 0.00213688, 0.00219860, 0.00226137,
|
||||
0.00232518, 0.00239003, 0.00245591, 0.00252284, 0.00259079, 0.00265977,
|
||||
0.00272977, 0.00280078, 0.00287280, 0.00294582, 0.00301984,
|
||||
0.00309484, 0.00317081, 0.00324774, 0.00332563, 0.00340446,
|
||||
0.00348421, 0.00356488, 0.00364644, 0.00372889, 0.00381220, 0.00389636,
|
||||
0.00398135, 0.00406715, 0.00415374, 0.00424109, 0.00432920,
|
||||
0.00441802, 0.00450754, 0.00459773, 0.00468857, 0.00478001,
|
||||
0.00487205, 0.00496464, 0.00505775, 0.00515136, 0.00524542, 0.00533990,
|
||||
0.00543476, 0.00552997, 0.00562548, 0.00572125, 0.00581725,
|
||||
0.00591342, 0.00600973, 0.00610612, 0.00620254, 0.00629895,
|
||||
0.00639530, 0.00649153, 0.00658758, 0.00668341, 0.00677894, 0.00687413,
|
||||
0.00696891, 0.00706322, 0.00715699, 0.00725016, 0.00734266,
|
||||
0.00743441, 0.00752535, 0.00761540, 0.00770449, 0.00779254,
|
||||
0.00787947, 0.00796519, 0.00804963, 0.00813270, 0.00821431, 0.00829437,
|
||||
0.00837280, 0.00844949, 0.00852436, 0.00859730, 0.00866822,
|
||||
0.00873701, 0.00880358, 0.00886781, 0.00892960, 0.00898884,
|
||||
0.00904542, 0.00909923, 0.00915014, 0.00919805, 0.00924283, 0.00928436,
|
||||
0.00932252, 0.00935718, 0.00938821, 0.00941550, 0.00943890,
|
||||
0.00945828, 0.00947351, 0.00948446, 0.00949098, 0.00949294,
|
||||
0.00949020, 0.00948262, 0.00947005, 0.00945235, 0.00942938, 0.00940099,
|
||||
0.00936704, 0.00932738, 0.00928186, 0.00923034, 0.00917268,
|
||||
0.00910872, 0.00903832, 0.00896134, 0.00887763, 0.00878706,
|
||||
0.00868949, 0.00858478, 0.00847280, 0.00835343, 0.00822653, 0.00809199,
|
||||
0.00794970, 0.00779956, 0.00764145, 0.00747530, 0.00730103,
|
||||
0.00711857, 0.00692787, 0.00672888, 0.00652158, 0.00630597,
|
||||
0.00608208, 0.00584994, 0.00560962, 0.00536124, 0.00510493, 0.00484089,
|
||||
0.00456935, 0.00429062, 0.00400505, 0.00371310, 0.00341532,
|
||||
0.00311238, 0.00280511, 0.00249452, 0.00218184, 0.00186864,
|
||||
0.00155690, 0.00124918, 0.00094895, 0.00066112, 0.00039320, 0.00015881
|
||||
};
|
||||
|
||||
double WebRtcIsac_LevDurb(double *a, double *k, double *r, size_t order)
|
||||
{
|
||||
|
||||
double sum, alpha;
|
||||
size_t m, m_h, i;
|
||||
alpha = 0; //warning -DH
|
||||
a[0] = 1.0;
|
||||
if (r[0] < LEVINSON_EPS) { /* if r[0] <= 0, set LPC coeff. to zero */
|
||||
for (i = 0; i < order; i++) {
|
||||
k[i] = 0;
|
||||
a[i+1] = 0;
|
||||
}
|
||||
} else {
|
||||
a[1] = k[0] = -r[1]/r[0];
|
||||
alpha = r[0] + r[1] * k[0];
|
||||
for (m = 1; m < order; m++){
|
||||
sum = r[m + 1];
|
||||
for (i = 0; i < m; i++){
|
||||
sum += a[i+1] * r[m - i];
|
||||
}
|
||||
k[m] = -sum / alpha;
|
||||
alpha += k[m] * sum;
|
||||
m_h = (m + 1) >> 1;
|
||||
for (i = 0; i < m_h; i++){
|
||||
sum = a[i+1] + k[m] * a[m - i];
|
||||
a[m - i] += k[m] * a[i+1];
|
||||
a[i+1] = sum;
|
||||
}
|
||||
a[m+1] = k[m];
|
||||
}
|
||||
}
|
||||
return alpha;
|
||||
}
|
||||
|
||||
|
||||
//was static before, but didn't work with MEX file
|
||||
void WebRtcIsac_GetVars(const double *input, const int16_t *pitchGains_Q12,
|
||||
double *oldEnergy, double *varscale)
|
||||
{
|
||||
double nrg[4], chng, pg;
|
||||
int k;
|
||||
|
||||
double pitchGains[4]={0,0,0,0};;
|
||||
|
||||
/* Calculate energies of first and second frame halfs */
|
||||
nrg[0] = 0.0001;
|
||||
for (k = QLOOKAHEAD/2; k < (FRAMESAMPLES_QUARTER + QLOOKAHEAD) / 2; k++) {
|
||||
nrg[0] += input[k]*input[k];
|
||||
}
|
||||
nrg[1] = 0.0001;
|
||||
for ( ; k < (FRAMESAMPLES_HALF + QLOOKAHEAD) / 2; k++) {
|
||||
nrg[1] += input[k]*input[k];
|
||||
}
|
||||
nrg[2] = 0.0001;
|
||||
for ( ; k < (FRAMESAMPLES*3/4 + QLOOKAHEAD) / 2; k++) {
|
||||
nrg[2] += input[k]*input[k];
|
||||
}
|
||||
nrg[3] = 0.0001;
|
||||
for ( ; k < (FRAMESAMPLES + QLOOKAHEAD) / 2; k++) {
|
||||
nrg[3] += input[k]*input[k];
|
||||
}
|
||||
|
||||
/* Calculate average level change */
|
||||
chng = 0.25 * (fabs(10.0 * log10(nrg[3] / nrg[2])) +
|
||||
fabs(10.0 * log10(nrg[2] / nrg[1])) +
|
||||
fabs(10.0 * log10(nrg[1] / nrg[0])) +
|
||||
fabs(10.0 * log10(nrg[0] / *oldEnergy)));
|
||||
|
||||
|
||||
/* Find average pitch gain */
|
||||
pg = 0.0;
|
||||
for (k=0; k<4; k++)
|
||||
{
|
||||
pitchGains[k] = ((float)pitchGains_Q12[k])/4096;
|
||||
pg += pitchGains[k];
|
||||
}
|
||||
pg *= 0.25;
|
||||
|
||||
/* If pitch gain is low and energy constant - increase noise level*/
|
||||
/* Matlab code:
|
||||
pg = 0:.01:.45; plot(pg, 0.0 + 1.0 * exp( -1.0 * exp(-200.0 * pg.*pg.*pg) / (1.0 + 0.4 * 0) ))
|
||||
*/
|
||||
*varscale = 0.0 + 1.0 * exp( -1.4 * exp(-200.0 * pg*pg*pg) / (1.0 + 0.4 * chng) );
|
||||
|
||||
*oldEnergy = nrg[3];
|
||||
}
|
||||
|
||||
void
|
||||
WebRtcIsac_GetVarsUB(
|
||||
const double* input,
|
||||
double* oldEnergy,
|
||||
double* varscale)
|
||||
{
|
||||
double nrg[4], chng;
|
||||
int k;
|
||||
|
||||
/* Calculate energies of first and second frame halfs */
|
||||
nrg[0] = 0.0001;
|
||||
for (k = 0; k < (FRAMESAMPLES_QUARTER) / 2; k++) {
|
||||
nrg[0] += input[k]*input[k];
|
||||
}
|
||||
nrg[1] = 0.0001;
|
||||
for ( ; k < (FRAMESAMPLES_HALF) / 2; k++) {
|
||||
nrg[1] += input[k]*input[k];
|
||||
}
|
||||
nrg[2] = 0.0001;
|
||||
for ( ; k < (FRAMESAMPLES*3/4) / 2; k++) {
|
||||
nrg[2] += input[k]*input[k];
|
||||
}
|
||||
nrg[3] = 0.0001;
|
||||
for ( ; k < (FRAMESAMPLES) / 2; k++) {
|
||||
nrg[3] += input[k]*input[k];
|
||||
}
|
||||
|
||||
/* Calculate average level change */
|
||||
chng = 0.25 * (fabs(10.0 * log10(nrg[3] / nrg[2])) +
|
||||
fabs(10.0 * log10(nrg[2] / nrg[1])) +
|
||||
fabs(10.0 * log10(nrg[1] / nrg[0])) +
|
||||
fabs(10.0 * log10(nrg[0] / *oldEnergy)));
|
||||
|
||||
|
||||
/* If pitch gain is low and energy constant - increase noise level*/
|
||||
/* Matlab code:
|
||||
pg = 0:.01:.45; plot(pg, 0.0 + 1.0 * exp( -1.0 * exp(-200.0 * pg.*pg.*pg) / (1.0 + 0.4 * 0) ))
|
||||
*/
|
||||
*varscale = exp( -1.4 / (1.0 + 0.4 * chng) );
|
||||
|
||||
*oldEnergy = nrg[3];
|
||||
}
|
||||
|
||||
void WebRtcIsac_GetLpcCoefLb(double *inLo, double *inHi, MaskFiltstr *maskdata,
|
||||
double signal_noise_ratio, const int16_t *pitchGains_Q12,
|
||||
double *lo_coeff, double *hi_coeff)
|
||||
{
|
||||
int k, n, j, pos1, pos2;
|
||||
double varscale;
|
||||
|
||||
double DataLo[WINLEN], DataHi[WINLEN];
|
||||
double corrlo[ORDERLO+2], corrlo2[ORDERLO+1];
|
||||
double corrhi[ORDERHI+1];
|
||||
double k_veclo[ORDERLO], k_vechi[ORDERHI];
|
||||
|
||||
double a_LO[ORDERLO+1], a_HI[ORDERHI+1];
|
||||
double tmp, res_nrg;
|
||||
|
||||
double FwdA, FwdB;
|
||||
|
||||
/* hearing threshold level in dB; higher value gives more noise */
|
||||
const double HearThresOffset = -28.0;
|
||||
|
||||
/* bandwdith expansion factors for low- and high band */
|
||||
const double gammaLo = 0.9;
|
||||
const double gammaHi = 0.8;
|
||||
|
||||
/* less-noise-at-low-frequencies factor */
|
||||
double aa;
|
||||
|
||||
|
||||
/* convert from dB to signal level */
|
||||
const double H_T_H = pow(10.0, 0.05 * HearThresOffset);
|
||||
double S_N_R = pow(10.0, 0.05 * signal_noise_ratio) / 3.46; /* divide by sqrt(12) */
|
||||
|
||||
/* change quallevel depending on pitch gains and level fluctuations */
|
||||
WebRtcIsac_GetVars(inLo, pitchGains_Q12, &(maskdata->OldEnergy), &varscale);
|
||||
|
||||
/* less-noise-at-low-frequencies factor */
|
||||
aa = 0.35 * (0.5 + 0.5 * varscale);
|
||||
|
||||
/* replace data in buffer by new look-ahead data */
|
||||
for (pos1 = 0; pos1 < QLOOKAHEAD; pos1++)
|
||||
maskdata->DataBufferLo[pos1 + WINLEN - QLOOKAHEAD] = inLo[pos1];
|
||||
|
||||
for (k = 0; k < SUBFRAMES; k++) {
|
||||
|
||||
/* Update input buffer and multiply signal with window */
|
||||
for (pos1 = 0; pos1 < WINLEN - UPDATE/2; pos1++) {
|
||||
maskdata->DataBufferLo[pos1] = maskdata->DataBufferLo[pos1 + UPDATE/2];
|
||||
maskdata->DataBufferHi[pos1] = maskdata->DataBufferHi[pos1 + UPDATE/2];
|
||||
DataLo[pos1] = maskdata->DataBufferLo[pos1] * kLpcCorrWindow[pos1];
|
||||
DataHi[pos1] = maskdata->DataBufferHi[pos1] * kLpcCorrWindow[pos1];
|
||||
}
|
||||
pos2 = k * UPDATE/2;
|
||||
for (n = 0; n < UPDATE/2; n++, pos1++) {
|
||||
maskdata->DataBufferLo[pos1] = inLo[QLOOKAHEAD + pos2];
|
||||
maskdata->DataBufferHi[pos1] = inHi[pos2++];
|
||||
DataLo[pos1] = maskdata->DataBufferLo[pos1] * kLpcCorrWindow[pos1];
|
||||
DataHi[pos1] = maskdata->DataBufferHi[pos1] * kLpcCorrWindow[pos1];
|
||||
}
|
||||
|
||||
/* Get correlation coefficients */
|
||||
WebRtcIsac_AutoCorr(corrlo, DataLo, WINLEN, ORDERLO+1); /* computing autocorrelation */
|
||||
WebRtcIsac_AutoCorr(corrhi, DataHi, WINLEN, ORDERHI);
|
||||
|
||||
|
||||
/* less noise for lower frequencies, by filtering/scaling autocorrelation sequences */
|
||||
corrlo2[0] = (1.0+aa*aa) * corrlo[0] - 2.0*aa * corrlo[1];
|
||||
tmp = (1.0 + aa*aa);
|
||||
for (n = 1; n <= ORDERLO; n++) {
|
||||
corrlo2[n] = tmp * corrlo[n] - aa * (corrlo[n-1] + corrlo[n+1]);
|
||||
}
|
||||
tmp = (1.0+aa) * (1.0+aa);
|
||||
for (n = 0; n <= ORDERHI; n++) {
|
||||
corrhi[n] = tmp * corrhi[n];
|
||||
}
|
||||
|
||||
/* add white noise floor */
|
||||
corrlo2[0] += 1e-6;
|
||||
corrhi[0] += 1e-6;
|
||||
|
||||
|
||||
FwdA = 0.01;
|
||||
FwdB = 0.01;
|
||||
|
||||
/* recursive filtering of correlation over subframes */
|
||||
for (n = 0; n <= ORDERLO; n++) {
|
||||
maskdata->CorrBufLo[n] = FwdA * maskdata->CorrBufLo[n] + corrlo2[n];
|
||||
corrlo2[n] = ((1.0-FwdA)*FwdB) * maskdata->CorrBufLo[n] + (1.0-FwdB) * corrlo2[n];
|
||||
}
|
||||
for (n = 0; n <= ORDERHI; n++) {
|
||||
maskdata->CorrBufHi[n] = FwdA * maskdata->CorrBufHi[n] + corrhi[n];
|
||||
corrhi[n] = ((1.0-FwdA)*FwdB) * maskdata->CorrBufHi[n] + (1.0-FwdB) * corrhi[n];
|
||||
}
|
||||
|
||||
/* compute prediction coefficients */
|
||||
WebRtcIsac_LevDurb(a_LO, k_veclo, corrlo2, ORDERLO);
|
||||
WebRtcIsac_LevDurb(a_HI, k_vechi, corrhi, ORDERHI);
|
||||
|
||||
/* bandwidth expansion */
|
||||
tmp = gammaLo;
|
||||
for (n = 1; n <= ORDERLO; n++) {
|
||||
a_LO[n] *= tmp;
|
||||
tmp *= gammaLo;
|
||||
}
|
||||
|
||||
/* residual energy */
|
||||
res_nrg = 0.0;
|
||||
for (j = 0; j <= ORDERLO; j++) {
|
||||
for (n = 0; n <= j; n++) {
|
||||
res_nrg += a_LO[j] * corrlo2[j-n] * a_LO[n];
|
||||
}
|
||||
for (n = j+1; n <= ORDERLO; n++) {
|
||||
res_nrg += a_LO[j] * corrlo2[n-j] * a_LO[n];
|
||||
}
|
||||
}
|
||||
|
||||
/* add hearing threshold and compute the gain */
|
||||
*lo_coeff++ = S_N_R / (sqrt(res_nrg) / varscale + H_T_H);
|
||||
|
||||
/* copy coefficients to output array */
|
||||
for (n = 1; n <= ORDERLO; n++) {
|
||||
*lo_coeff++ = a_LO[n];
|
||||
}
|
||||
|
||||
|
||||
/* bandwidth expansion */
|
||||
tmp = gammaHi;
|
||||
for (n = 1; n <= ORDERHI; n++) {
|
||||
a_HI[n] *= tmp;
|
||||
tmp *= gammaHi;
|
||||
}
|
||||
|
||||
/* residual energy */
|
||||
res_nrg = 0.0;
|
||||
for (j = 0; j <= ORDERHI; j++) {
|
||||
for (n = 0; n <= j; n++) {
|
||||
res_nrg += a_HI[j] * corrhi[j-n] * a_HI[n];
|
||||
}
|
||||
for (n = j+1; n <= ORDERHI; n++) {
|
||||
res_nrg += a_HI[j] * corrhi[n-j] * a_HI[n];
|
||||
}
|
||||
}
|
||||
|
||||
/* add hearing threshold and compute of the gain */
|
||||
*hi_coeff++ = S_N_R / (sqrt(res_nrg) / varscale + H_T_H);
|
||||
|
||||
/* copy coefficients to output array */
|
||||
for (n = 1; n <= ORDERHI; n++) {
|
||||
*hi_coeff++ = a_HI[n];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_GetLpcCoefUb()
|
||||
*
|
||||
* Compute LP coefficients and correlation coefficients. At 12 kHz LP
|
||||
* coefficients of the first and the last sub-frame is computed. At 16 kHz
|
||||
* LP coefficients of 4th, 8th and 12th sub-frames are computed. We always
|
||||
* compute correlation coefficients of all sub-frames.
|
||||
*
|
||||
* Inputs:
|
||||
* -inSignal : Input signal
|
||||
* -maskdata : a structure keeping signal from previous frame.
|
||||
* -bandwidth : specifies if the codec is in 0-16 kHz mode or
|
||||
* 0-12 kHz mode.
|
||||
*
|
||||
* Outputs:
|
||||
* -lpCoeff : pointer to a buffer where A-polynomials are
|
||||
* written to (first coeff is 1 and it is not
|
||||
* written)
|
||||
* -corrMat : a matrix where correlation coefficients of each
|
||||
* sub-frame are written to one row.
|
||||
* -varscale : a scale used to compute LPC gains.
|
||||
*/
|
||||
void
|
||||
WebRtcIsac_GetLpcCoefUb(
|
||||
double* inSignal,
|
||||
MaskFiltstr* maskdata,
|
||||
double* lpCoeff,
|
||||
double corrMat[][UB_LPC_ORDER + 1],
|
||||
double* varscale,
|
||||
int16_t bandwidth)
|
||||
{
|
||||
int frameCntr, activeFrameCntr, n, pos1, pos2;
|
||||
int16_t criterion1;
|
||||
int16_t criterion2;
|
||||
int16_t numSubFrames = SUBFRAMES * (1 + (bandwidth == isac16kHz));
|
||||
double data[WINLEN];
|
||||
double corrSubFrame[UB_LPC_ORDER+2];
|
||||
double reflecCoeff[UB_LPC_ORDER];
|
||||
|
||||
double aPolynom[UB_LPC_ORDER+1];
|
||||
double tmp;
|
||||
|
||||
/* bandwdith expansion factors */
|
||||
const double gamma = 0.9;
|
||||
|
||||
/* change quallevel depending on pitch gains and level fluctuations */
|
||||
WebRtcIsac_GetVarsUB(inSignal, &(maskdata->OldEnergy), varscale);
|
||||
|
||||
/* replace data in buffer by new look-ahead data */
|
||||
for(frameCntr = 0, activeFrameCntr = 0; frameCntr < numSubFrames;
|
||||
frameCntr++)
|
||||
{
|
||||
if(frameCntr == SUBFRAMES)
|
||||
{
|
||||
// we are in 16 kHz
|
||||
varscale++;
|
||||
WebRtcIsac_GetVarsUB(&inSignal[FRAMESAMPLES_HALF],
|
||||
&(maskdata->OldEnergy), varscale);
|
||||
}
|
||||
/* Update input buffer and multiply signal with window */
|
||||
for(pos1 = 0; pos1 < WINLEN - UPDATE/2; pos1++)
|
||||
{
|
||||
maskdata->DataBufferLo[pos1] = maskdata->DataBufferLo[pos1 +
|
||||
UPDATE/2];
|
||||
data[pos1] = maskdata->DataBufferLo[pos1] * kLpcCorrWindow[pos1];
|
||||
}
|
||||
pos2 = frameCntr * UPDATE/2;
|
||||
for(n = 0; n < UPDATE/2; n++, pos1++, pos2++)
|
||||
{
|
||||
maskdata->DataBufferLo[pos1] = inSignal[pos2];
|
||||
data[pos1] = maskdata->DataBufferLo[pos1] * kLpcCorrWindow[pos1];
|
||||
}
|
||||
|
||||
/* Get correlation coefficients */
|
||||
/* computing autocorrelation */
|
||||
WebRtcIsac_AutoCorr(corrSubFrame, data, WINLEN, UB_LPC_ORDER+1);
|
||||
memcpy(corrMat[frameCntr], corrSubFrame,
|
||||
(UB_LPC_ORDER+1)*sizeof(double));
|
||||
|
||||
criterion1 = ((frameCntr == 0) || (frameCntr == (SUBFRAMES - 1))) &&
|
||||
(bandwidth == isac12kHz);
|
||||
criterion2 = (((frameCntr+1) % 4) == 0) &&
|
||||
(bandwidth == isac16kHz);
|
||||
if(criterion1 || criterion2)
|
||||
{
|
||||
/* add noise */
|
||||
corrSubFrame[0] += 1e-6;
|
||||
/* compute prediction coefficients */
|
||||
WebRtcIsac_LevDurb(aPolynom, reflecCoeff, corrSubFrame,
|
||||
UB_LPC_ORDER);
|
||||
|
||||
/* bandwidth expansion */
|
||||
tmp = gamma;
|
||||
for (n = 1; n <= UB_LPC_ORDER; n++)
|
||||
{
|
||||
*lpCoeff++ = aPolynom[n] * tmp;
|
||||
tmp *= gamma;
|
||||
}
|
||||
activeFrameCntr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_GetLpcGain()
|
||||
*
|
||||
* Compute the LPC gains for each sub-frame, given the LPC of each sub-frame
|
||||
* and the corresponding correlation coefficients.
|
||||
*
|
||||
* Inputs:
|
||||
* -signal_noise_ratio : the desired SNR in dB.
|
||||
* -numVecs : number of sub-frames
|
||||
* -corrMat : a matrix of correlation coefficients where
|
||||
* each row is a set of correlation coefficients of
|
||||
* one sub-frame.
|
||||
* -varscale : a scale computed when WebRtcIsac_GetLpcCoefUb()
|
||||
* is called.
|
||||
*
|
||||
* Outputs:
|
||||
* -gain : pointer to a buffer where LP gains are written.
|
||||
*
|
||||
*/
|
||||
void
|
||||
WebRtcIsac_GetLpcGain(
|
||||
double signal_noise_ratio,
|
||||
const double* filtCoeffVecs,
|
||||
int numVecs,
|
||||
double* gain,
|
||||
double corrMat[][UB_LPC_ORDER + 1],
|
||||
const double* varscale)
|
||||
{
|
||||
int16_t j, n;
|
||||
int16_t subFrameCntr;
|
||||
double aPolynom[ORDERLO + 1];
|
||||
double res_nrg;
|
||||
|
||||
const double HearThresOffset = -28.0;
|
||||
const double H_T_H = pow(10.0, 0.05 * HearThresOffset);
|
||||
/* divide by sqrt(12) = 3.46 */
|
||||
const double S_N_R = pow(10.0, 0.05 * signal_noise_ratio) / 3.46;
|
||||
|
||||
aPolynom[0] = 1;
|
||||
for(subFrameCntr = 0; subFrameCntr < numVecs; subFrameCntr++)
|
||||
{
|
||||
if(subFrameCntr == SUBFRAMES)
|
||||
{
|
||||
// we are in second half of a SWB frame. use new varscale
|
||||
varscale++;
|
||||
}
|
||||
memcpy(&aPolynom[1], &filtCoeffVecs[(subFrameCntr * (UB_LPC_ORDER + 1)) +
|
||||
1], sizeof(double) * UB_LPC_ORDER);
|
||||
|
||||
/* residual energy */
|
||||
res_nrg = 0.0;
|
||||
for(j = 0; j <= UB_LPC_ORDER; j++)
|
||||
{
|
||||
for(n = 0; n <= j; n++)
|
||||
{
|
||||
res_nrg += aPolynom[j] * corrMat[subFrameCntr][j-n] *
|
||||
aPolynom[n];
|
||||
}
|
||||
for(n = j+1; n <= UB_LPC_ORDER; n++)
|
||||
{
|
||||
res_nrg += aPolynom[j] * corrMat[subFrameCntr][n-j] *
|
||||
aPolynom[n];
|
||||
}
|
||||
}
|
||||
|
||||
/* add hearing threshold and compute the gain */
|
||||
gain[subFrameCntr] = S_N_R / (sqrt(res_nrg) / *varscale + H_T_H);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* lpc_analysis.h
|
||||
*
|
||||
* LPC functions
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYSIS_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYSIS_H_
|
||||
|
||||
#include "settings.h"
|
||||
#include "structs.h"
|
||||
|
||||
double WebRtcIsac_LevDurb(double *a, double *k, double *r, size_t order);
|
||||
|
||||
void WebRtcIsac_GetVars(const double *input, const int16_t *pitchGains_Q12,
|
||||
double *oldEnergy, double *varscale);
|
||||
|
||||
void WebRtcIsac_GetLpcCoefLb(double *inLo, double *inHi, MaskFiltstr *maskdata,
|
||||
double signal_noise_ratio, const int16_t *pitchGains_Q12,
|
||||
double *lo_coeff, double *hi_coeff);
|
||||
|
||||
|
||||
void WebRtcIsac_GetLpcGain(
|
||||
double signal_noise_ratio,
|
||||
const double* filtCoeffVecs,
|
||||
int numVecs,
|
||||
double* gain,
|
||||
double corrLo[][UB_LPC_ORDER + 1],
|
||||
const double* varscale);
|
||||
|
||||
void WebRtcIsac_GetLpcCoefUb(
|
||||
double* inSignal,
|
||||
MaskFiltstr* maskdata,
|
||||
double* lpCoeff,
|
||||
double corr[][UB_LPC_ORDER + 1],
|
||||
double* varscale,
|
||||
int16_t bandwidth);
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYIS_H_ */
|
||||
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SWB_KLT_Tables_LPCGain.c
|
||||
*
|
||||
* This file defines tables used for entropy coding of LPC Gain
|
||||
* of upper-band.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lpc_gain_swb_tables.h"
|
||||
#include "settings.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
const double WebRtcIsac_kQSizeLpcGain = 0.100000;
|
||||
|
||||
const double WebRtcIsac_kMeanLpcGain = -3.3822;
|
||||
|
||||
/*
|
||||
* The smallest reconstruction points for quantiztion of
|
||||
* LPC gains.
|
||||
*/
|
||||
const double WebRtcIsac_kLeftRecPointLpcGain[SUBFRAMES] =
|
||||
{
|
||||
-0.800000, -1.000000, -1.200000, -2.200000, -3.000000, -12.700000
|
||||
};
|
||||
|
||||
/*
|
||||
* Number of reconstruction points of quantizers for LPC Gains.
|
||||
*/
|
||||
const int16_t WebRtcIsac_kNumQCellLpcGain[SUBFRAMES] =
|
||||
{
|
||||
17, 20, 25, 45, 77, 170
|
||||
};
|
||||
/*
|
||||
* Starting index for entropy decoder to search for the right interval,
|
||||
* one entry per LAR coefficient
|
||||
*/
|
||||
const uint16_t WebRtcIsac_kLpcGainEntropySearch[SUBFRAMES] =
|
||||
{
|
||||
8, 10, 12, 22, 38, 85
|
||||
};
|
||||
|
||||
/*
|
||||
* The following 6 vectors define CDF of 6 decorrelated LPC
|
||||
* gains.
|
||||
*/
|
||||
const uint16_t WebRtcIsac_kLpcGainCdfVec0[18] =
|
||||
{
|
||||
0, 10, 27, 83, 234, 568, 1601, 4683, 16830, 57534, 63437,
|
||||
64767, 65229, 65408, 65483, 65514, 65527, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcGainCdfVec1[21] =
|
||||
{
|
||||
0, 15, 33, 84, 185, 385, 807, 1619, 3529, 7850, 19488,
|
||||
51365, 62437, 64548, 65088, 65304, 65409, 65484, 65507, 65522, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcGainCdfVec2[26] =
|
||||
{
|
||||
0, 15, 29, 54, 89, 145, 228, 380, 652, 1493, 4260,
|
||||
12359, 34133, 50749, 57224, 60814, 62927, 64078, 64742, 65103, 65311, 65418,
|
||||
65473, 65509, 65521, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcGainCdfVec3[46] =
|
||||
{
|
||||
0, 8, 12, 16, 26, 42, 56, 76, 111, 164, 247,
|
||||
366, 508, 693, 1000, 1442, 2155, 3188, 4854, 7387, 11249, 17617,
|
||||
30079, 46711, 56291, 60127, 62140, 63258, 63954, 64384, 64690, 64891, 65031,
|
||||
65139, 65227, 65293, 65351, 65399, 65438, 65467, 65492, 65504, 65510, 65518,
|
||||
65523, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcGainCdfVec4[78] =
|
||||
{
|
||||
0, 17, 29, 39, 51, 70, 104, 154, 234, 324, 443,
|
||||
590, 760, 971, 1202, 1494, 1845, 2274, 2797, 3366, 4088, 4905,
|
||||
5899, 7142, 8683, 10625, 12983, 16095, 20637, 28216, 38859, 47237, 51537,
|
||||
54150, 56066, 57583, 58756, 59685, 60458, 61103, 61659, 62144, 62550, 62886,
|
||||
63186, 63480, 63743, 63954, 64148, 64320, 64467, 64600, 64719, 64837, 64939,
|
||||
65014, 65098, 65160, 65211, 65250, 65290, 65325, 65344, 65366, 65391, 65410,
|
||||
65430, 65447, 65460, 65474, 65487, 65494, 65501, 65509, 65513, 65518, 65520,
|
||||
65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcGainCdfVec5[171] =
|
||||
{
|
||||
0, 10, 12, 14, 16, 18, 23, 29, 35, 42, 51,
|
||||
58, 65, 72, 78, 87, 96, 103, 111, 122, 134, 150,
|
||||
167, 184, 202, 223, 244, 265, 289, 315, 346, 379, 414,
|
||||
450, 491, 532, 572, 613, 656, 700, 751, 802, 853, 905,
|
||||
957, 1021, 1098, 1174, 1250, 1331, 1413, 1490, 1565, 1647, 1730,
|
||||
1821, 1913, 2004, 2100, 2207, 2314, 2420, 2532, 2652, 2783, 2921,
|
||||
3056, 3189, 3327, 3468, 3640, 3817, 3993, 4171, 4362, 4554, 4751,
|
||||
4948, 5142, 5346, 5566, 5799, 6044, 6301, 6565, 6852, 7150, 7470,
|
||||
7797, 8143, 8492, 8835, 9181, 9547, 9919, 10315, 10718, 11136, 11566,
|
||||
12015, 12482, 12967, 13458, 13953, 14432, 14903, 15416, 15936, 16452, 16967,
|
||||
17492, 18024, 18600, 19173, 19736, 20311, 20911, 21490, 22041, 22597, 23157,
|
||||
23768, 24405, 25034, 25660, 26280, 26899, 27614, 28331, 29015, 29702, 30403,
|
||||
31107, 31817, 32566, 33381, 34224, 35099, 36112, 37222, 38375, 39549, 40801,
|
||||
42074, 43350, 44626, 45982, 47354, 48860, 50361, 51845, 53312, 54739, 56026,
|
||||
57116, 58104, 58996, 59842, 60658, 61488, 62324, 63057, 63769, 64285, 64779,
|
||||
65076, 65344, 65430, 65500, 65517, 65535
|
||||
};
|
||||
|
||||
/*
|
||||
* An array of pointers to CDFs of decorrelated LPC Gains
|
||||
*/
|
||||
const uint16_t* WebRtcIsac_kLpcGainCdfMat[SUBFRAMES] =
|
||||
{
|
||||
WebRtcIsac_kLpcGainCdfVec0, WebRtcIsac_kLpcGainCdfVec1,
|
||||
WebRtcIsac_kLpcGainCdfVec2, WebRtcIsac_kLpcGainCdfVec3,
|
||||
WebRtcIsac_kLpcGainCdfVec4, WebRtcIsac_kLpcGainCdfVec5
|
||||
};
|
||||
|
||||
/*
|
||||
* A matrix to decorrellate LPC gains of subframes.
|
||||
*/
|
||||
const double WebRtcIsac_kLpcGainDecorrMat[SUBFRAMES][SUBFRAMES] =
|
||||
{
|
||||
{-0.150860, 0.327872, 0.367220, 0.504613, 0.559270, 0.409234},
|
||||
{ 0.457128, -0.613591, -0.289283, -0.029734, 0.393760, 0.418240},
|
||||
{-0.626043, 0.136489, -0.439118, -0.448323, 0.135987, 0.420869},
|
||||
{ 0.526617, 0.480187, 0.242552, -0.488754, -0.158713, 0.411331},
|
||||
{-0.302587, -0.494953, 0.588112, -0.063035, -0.404290, 0.387510},
|
||||
{ 0.086378, 0.147714, -0.428875, 0.548300, -0.570121, 0.401391}
|
||||
};
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SWB_KLT_Tables_LPCGain.h
|
||||
*
|
||||
* This file declares tables used for entropy coding of LPC Gain
|
||||
* of upper-band.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_
|
||||
|
||||
#include "settings.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
extern const double WebRtcIsac_kQSizeLpcGain;
|
||||
|
||||
extern const double WebRtcIsac_kLeftRecPointLpcGain[SUBFRAMES];
|
||||
|
||||
extern const int16_t WebRtcIsac_kNumQCellLpcGain[SUBFRAMES];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcGainEntropySearch[SUBFRAMES];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcGainCdfVec0[18];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcGainCdfVec1[21];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcGainCdfVec2[26];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcGainCdfVec3[46];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcGainCdfVec4[78];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcGainCdfVec5[171];
|
||||
|
||||
extern const uint16_t* WebRtcIsac_kLpcGainCdfMat[SUBFRAMES];
|
||||
|
||||
extern const double WebRtcIsac_kLpcGainDecorrMat[SUBFRAMES][SUBFRAMES];
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SWB_KLT_Tables.c
|
||||
*
|
||||
* This file defines tables used for entropy coding of LPC shape of
|
||||
* upper-band signal if the bandwidth is 12 kHz.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lpc_shape_swb12_tables.h"
|
||||
#include "settings.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
/*
|
||||
* Mean value of LAR
|
||||
*/
|
||||
const double WebRtcIsac_kMeanLarUb12[UB_LPC_ORDER] =
|
||||
{
|
||||
0.03748928306641, 0.09453441192543, -0.01112522344398, 0.03800237516842
|
||||
};
|
||||
|
||||
/*
|
||||
* A rotation matrix to decorrelate intra-vector correlation,
|
||||
* i.e. correlation among components of LAR vector.
|
||||
*/
|
||||
const double WebRtcIsac_kIntraVecDecorrMatUb12[UB_LPC_ORDER][UB_LPC_ORDER] =
|
||||
{
|
||||
{-0.00075365493856, -0.05809964887743, -0.23397966154116, 0.97050367376411},
|
||||
{ 0.00625021257734, -0.17299965610679, 0.95977735920651, 0.22104179375008},
|
||||
{ 0.20543384258374, -0.96202143495696, -0.15301870801552, -0.09432375099565},
|
||||
{-0.97865075648479, -0.20300322280841, -0.02581111653779, -0.01913568980258}
|
||||
};
|
||||
|
||||
/*
|
||||
* A rotation matrix to remove correlation among LAR coefficients
|
||||
* of different LAR vectors. One might guess that decorrelation matrix
|
||||
* for the first component should differ from the second component
|
||||
* but we haven't observed a significant benefit of having different
|
||||
* decorrelation matrices for different components.
|
||||
*/
|
||||
const double WebRtcIsac_kInterVecDecorrMatUb12
|
||||
[UB_LPC_VEC_PER_FRAME][UB_LPC_VEC_PER_FRAME] =
|
||||
{
|
||||
{ 0.70650597970460, -0.70770707262373},
|
||||
{-0.70770707262373, -0.70650597970460}
|
||||
};
|
||||
|
||||
/*
|
||||
* LAR quantization step-size.
|
||||
*/
|
||||
const double WebRtcIsac_kLpcShapeQStepSizeUb12 = 0.150000;
|
||||
|
||||
/*
|
||||
* The smallest reconstruction points for quantiztion of LAR coefficients.
|
||||
*/
|
||||
const double WebRtcIsac_kLpcShapeLeftRecPointUb12
|
||||
[UB_LPC_ORDER*UB_LPC_VEC_PER_FRAME] =
|
||||
{
|
||||
-0.900000, -1.050000, -1.350000, -1.800000, -1.350000, -1.650000,
|
||||
-2.250000, -3.450000
|
||||
};
|
||||
|
||||
/*
|
||||
* Number of reconstruction points of quantizers for LAR coefficients.
|
||||
*/
|
||||
const int16_t WebRtcIsac_kLpcShapeNumRecPointUb12
|
||||
[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME] =
|
||||
{
|
||||
13, 15, 19, 27, 19, 24, 32, 48
|
||||
};
|
||||
|
||||
/*
|
||||
* Starting index for entropy decoder to search for the right interval,
|
||||
* one entry per LAR coefficient
|
||||
*/
|
||||
const uint16_t WebRtcIsac_kLpcShapeEntropySearchUb12
|
||||
[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME] =
|
||||
{
|
||||
6, 7, 9, 13, 9, 12, 16, 24
|
||||
};
|
||||
|
||||
/*
|
||||
* The following 8 vectors define CDF of 8 decorrelated LAR
|
||||
* coefficients.
|
||||
*/
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec0Ub12[14] =
|
||||
{
|
||||
0, 13, 95, 418, 1687, 6498, 21317, 44200, 59029, 63849, 65147,
|
||||
65449, 65525, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec1Ub12[16] =
|
||||
{
|
||||
0, 10, 59, 255, 858, 2667, 8200, 22609, 42988, 57202, 62947,
|
||||
64743, 65308, 65476, 65522, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec2Ub12[20] =
|
||||
{
|
||||
0, 18, 40, 118, 332, 857, 2017, 4822, 11321, 24330, 41279,
|
||||
54342, 60637, 63394, 64659, 65184, 65398, 65482, 65518, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec3Ub12[28] =
|
||||
{
|
||||
0, 21, 38, 90, 196, 398, 770, 1400, 2589, 4650, 8211,
|
||||
14933, 26044, 39592, 50814, 57452, 60971, 62884, 63995, 64621, 65019, 65273,
|
||||
65410, 65480, 65514, 65522, 65531, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec4Ub12[20] =
|
||||
{
|
||||
0, 7, 46, 141, 403, 969, 2132, 4649, 10633, 24902, 43254,
|
||||
54665, 59928, 62674, 64173, 64938, 65293, 65464, 65523, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec5Ub12[25] =
|
||||
{
|
||||
0, 7, 22, 72, 174, 411, 854, 1737, 3545, 6774, 13165,
|
||||
25221, 40980, 52821, 58714, 61706, 63472, 64437, 64989, 65287, 65430, 65503,
|
||||
65525, 65529, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec6Ub12[33] =
|
||||
{
|
||||
0, 11, 21, 36, 65, 128, 228, 401, 707, 1241, 2126,
|
||||
3589, 6060, 10517, 18853, 31114, 42477, 49770, 54271, 57467, 59838, 61569,
|
||||
62831, 63772, 64433, 64833, 65123, 65306, 65419, 65466, 65499, 65519, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec7Ub12[49] =
|
||||
{
|
||||
0, 14, 34, 67, 107, 167, 245, 326, 449, 645, 861,
|
||||
1155, 1508, 2003, 2669, 3544, 4592, 5961, 7583, 9887, 13256, 18765,
|
||||
26519, 34077, 40034, 44349, 47795, 50663, 53262, 55473, 57458, 59122, 60592,
|
||||
61742, 62690, 63391, 63997, 64463, 64794, 65045, 65207, 65309, 65394, 65443,
|
||||
65478, 65504, 65514, 65523, 65535
|
||||
};
|
||||
|
||||
/*
|
||||
* An array of pointers to CDFs of decorrelated LARs
|
||||
*/
|
||||
const uint16_t* WebRtcIsac_kLpcShapeCdfMatUb12
|
||||
[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME] =
|
||||
{
|
||||
WebRtcIsac_kLpcShapeCdfVec0Ub12, WebRtcIsac_kLpcShapeCdfVec1Ub12,
|
||||
WebRtcIsac_kLpcShapeCdfVec2Ub12, WebRtcIsac_kLpcShapeCdfVec3Ub12,
|
||||
WebRtcIsac_kLpcShapeCdfVec4Ub12, WebRtcIsac_kLpcShapeCdfVec5Ub12,
|
||||
WebRtcIsac_kLpcShapeCdfVec6Ub12, WebRtcIsac_kLpcShapeCdfVec7Ub12
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* lpc_shape_swb12_tables.h
|
||||
*
|
||||
* This file declares tables used for entropy coding of LPC shape of
|
||||
* upper-band signal if the bandwidth is 12 kHz.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_
|
||||
|
||||
#include "settings.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
extern const double WebRtcIsac_kMeanLarUb12[UB_LPC_ORDER];
|
||||
|
||||
extern const double WebRtcIsac_kMeanLpcGain;
|
||||
|
||||
extern const double WebRtcIsac_kIntraVecDecorrMatUb12[UB_LPC_ORDER][UB_LPC_ORDER];
|
||||
|
||||
extern const double WebRtcIsac_kInterVecDecorrMatUb12
|
||||
[UB_LPC_VEC_PER_FRAME][UB_LPC_VEC_PER_FRAME];
|
||||
|
||||
extern const double WebRtcIsac_kLpcShapeQStepSizeUb12;
|
||||
|
||||
extern const double WebRtcIsac_kLpcShapeLeftRecPointUb12
|
||||
[UB_LPC_ORDER*UB_LPC_VEC_PER_FRAME];
|
||||
|
||||
|
||||
extern const int16_t WebRtcIsac_kLpcShapeNumRecPointUb12
|
||||
[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeEntropySearchUb12
|
||||
[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec0Ub12[14];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec1Ub12[16];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec2Ub12[20];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec3Ub12[28];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec4Ub12[20];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec5Ub12[25];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec6Ub12[33];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec7Ub12[49];
|
||||
|
||||
extern const uint16_t* WebRtcIsac_kLpcShapeCdfMatUb12
|
||||
[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_
|
||||
@@ -0,0 +1,248 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SWB16_KLT_Tables.c
|
||||
*
|
||||
* This file defines tables used for entropy coding of LPC shape of
|
||||
* upper-band signal if the bandwidth is 16 kHz.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lpc_shape_swb16_tables.h"
|
||||
#include "settings.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
/*
|
||||
* Mean value of LAR
|
||||
*/
|
||||
const double WebRtcIsac_kMeanLarUb16[UB_LPC_ORDER] =
|
||||
{
|
||||
0.454978, 0.364747, 0.102999, 0.104523
|
||||
};
|
||||
|
||||
/*
|
||||
* A rotation matrix to decorrelate intra-vector correlation,
|
||||
* i.e. correlation among components of LAR vector.
|
||||
*/
|
||||
const double WebRtcIsac_kIintraVecDecorrMatUb16[UB_LPC_ORDER][UB_LPC_ORDER] =
|
||||
{
|
||||
{-0.020528, -0.085858, -0.002431, 0.996093},
|
||||
{-0.033155, 0.036102, 0.998786, 0.004866},
|
||||
{ 0.202627, 0.974853, -0.028940, 0.088132},
|
||||
{-0.978479, 0.202454, -0.039785, -0.002811}
|
||||
};
|
||||
|
||||
/*
|
||||
* A rotation matrix to remove correlation among LAR coefficients
|
||||
* of different LAR vectors. One might guess that decorrelation matrix
|
||||
* for the first component should differ from the second component
|
||||
* but we haven't observed a significant benefit of having different
|
||||
* decorrelation matrices for different components.
|
||||
*/
|
||||
const double WebRtcIsac_kInterVecDecorrMatUb16
|
||||
[UB16_LPC_VEC_PER_FRAME][UB16_LPC_VEC_PER_FRAME] =
|
||||
{
|
||||
{ 0.291675, -0.515786, 0.644927, 0.482658},
|
||||
{-0.647220, 0.479712, 0.289556, 0.516856},
|
||||
{ 0.643084, 0.485489, -0.289307, 0.516763},
|
||||
{-0.287185, -0.517823, -0.645389, 0.482553}
|
||||
};
|
||||
|
||||
/*
|
||||
* The following 16 vectors define CDF of 16 decorrelated LAR
|
||||
* coefficients.
|
||||
*/
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub16[14] =
|
||||
{
|
||||
0, 2, 20, 159, 1034, 5688, 20892, 44653,
|
||||
59849, 64485, 65383, 65518, 65534, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec1Ub16[16] =
|
||||
{
|
||||
0, 1, 7, 43, 276, 1496, 6681, 21653,
|
||||
43891, 58859, 64022, 65248, 65489, 65529, 65534, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec2Ub16[18] =
|
||||
{
|
||||
0, 1, 9, 54, 238, 933, 3192, 9461,
|
||||
23226, 42146, 56138, 62413, 64623, 65300, 65473, 65521,
|
||||
65533, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec3Ub16[30] =
|
||||
{
|
||||
0, 2, 4, 8, 17, 36, 75, 155,
|
||||
329, 683, 1376, 2662, 5047, 9508, 17526, 29027,
|
||||
40363, 48997, 55096, 59180, 61789, 63407, 64400, 64967,
|
||||
65273, 65429, 65497, 65526, 65534, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec4Ub16[16] =
|
||||
{
|
||||
0, 1, 10, 63, 361, 1785, 7407, 22242,
|
||||
43337, 58125, 63729, 65181, 65472, 65527, 65534, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec5Ub16[17] =
|
||||
{
|
||||
0, 1, 7, 29, 134, 599, 2443, 8590,
|
||||
22962, 42635, 56911, 63060, 64940, 65408, 65513, 65531,
|
||||
65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec6Ub16[21] =
|
||||
{
|
||||
0, 1, 5, 16, 57, 191, 611, 1808,
|
||||
4847, 11755, 24612, 40910, 53789, 60698, 63729, 64924,
|
||||
65346, 65486, 65523, 65532, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec7Ub16[36] =
|
||||
{
|
||||
0, 1, 4, 12, 25, 55, 104, 184,
|
||||
314, 539, 926, 1550, 2479, 3861, 5892, 8845,
|
||||
13281, 20018, 29019, 38029, 45581, 51557, 56057, 59284,
|
||||
61517, 63047, 64030, 64648, 65031, 65261, 65402, 65480,
|
||||
65518, 65530, 65534, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec8Ub16[21] =
|
||||
{
|
||||
0, 1, 2, 7, 26, 103, 351, 1149,
|
||||
3583, 10204, 23846, 41711, 55361, 61917, 64382, 65186,
|
||||
65433, 65506, 65528, 65534, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub160[21] =
|
||||
{
|
||||
0, 6, 19, 63, 205, 638, 1799, 4784,
|
||||
11721, 24494, 40803, 53805, 60886, 63822, 64931, 65333,
|
||||
65472, 65517, 65530, 65533, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub161[28] =
|
||||
{
|
||||
0, 1, 3, 11, 31, 86, 221, 506,
|
||||
1101, 2296, 4486, 8477, 15356, 26079, 38941, 49952,
|
||||
57165, 61257, 63426, 64549, 65097, 65351, 65463, 65510,
|
||||
65526, 65532, 65534, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub162[55] =
|
||||
{
|
||||
0, 3, 12, 23, 42, 65, 89, 115,
|
||||
150, 195, 248, 327, 430, 580, 784, 1099,
|
||||
1586, 2358, 3651, 5899, 9568, 14312, 19158, 23776,
|
||||
28267, 32663, 36991, 41153, 45098, 48680, 51870, 54729,
|
||||
57141, 59158, 60772, 62029, 63000, 63761, 64322, 64728,
|
||||
65000, 65192, 65321, 65411, 65463, 65496, 65514, 65523,
|
||||
65527, 65529, 65531, 65532, 65533, 65534, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub163[26] =
|
||||
{
|
||||
0, 2, 4, 10, 21, 48, 114, 280,
|
||||
701, 1765, 4555, 11270, 24267, 41213, 54285, 61003,
|
||||
63767, 64840, 65254, 65421, 65489, 65514, 65526, 65532,
|
||||
65534, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub164[28] =
|
||||
{
|
||||
0, 1, 3, 6, 15, 36, 82, 196,
|
||||
453, 1087, 2557, 5923, 13016, 25366, 40449, 52582,
|
||||
59539, 62896, 64389, 65033, 65316, 65442, 65494, 65519,
|
||||
65529, 65533, 65534, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub165[34] =
|
||||
{
|
||||
0, 2, 4, 8, 18, 35, 73, 146,
|
||||
279, 524, 980, 1789, 3235, 5784, 10040, 16998,
|
||||
27070, 38543, 48499, 55421, 59712, 62257, 63748, 64591,
|
||||
65041, 65278, 65410, 65474, 65508, 65522, 65530, 65533,
|
||||
65534, 65535
|
||||
};
|
||||
|
||||
const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub166[71] =
|
||||
{
|
||||
0, 1, 2, 6, 13, 26, 55, 92,
|
||||
141, 191, 242, 296, 355, 429, 522, 636,
|
||||
777, 947, 1162, 1428, 1753, 2137, 2605, 3140,
|
||||
3743, 4409, 5164, 6016, 6982, 8118, 9451, 10993,
|
||||
12754, 14810, 17130, 19780, 22864, 26424, 30547, 35222,
|
||||
40140, 44716, 48698, 52056, 54850, 57162, 59068, 60643,
|
||||
61877, 62827, 63561, 64113, 64519, 64807, 65019, 65167,
|
||||
65272, 65343, 65399, 65440, 65471, 65487, 65500, 65509,
|
||||
65518, 65524, 65527, 65531, 65533, 65534, 65535
|
||||
};
|
||||
|
||||
/*
|
||||
* An array of pointers to CDFs of decorrelated LARs
|
||||
*/
|
||||
const uint16_t* WebRtcIsac_kLpcShapeCdfMatUb16
|
||||
[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME] = {
|
||||
WebRtcIsac_kLpcShapeCdfVec01Ub16,
|
||||
WebRtcIsac_kLpcShapeCdfVec1Ub16,
|
||||
WebRtcIsac_kLpcShapeCdfVec2Ub16,
|
||||
WebRtcIsac_kLpcShapeCdfVec3Ub16,
|
||||
WebRtcIsac_kLpcShapeCdfVec4Ub16,
|
||||
WebRtcIsac_kLpcShapeCdfVec5Ub16,
|
||||
WebRtcIsac_kLpcShapeCdfVec6Ub16,
|
||||
WebRtcIsac_kLpcShapeCdfVec7Ub16,
|
||||
WebRtcIsac_kLpcShapeCdfVec8Ub16,
|
||||
WebRtcIsac_kLpcShapeCdfVec01Ub160,
|
||||
WebRtcIsac_kLpcShapeCdfVec01Ub161,
|
||||
WebRtcIsac_kLpcShapeCdfVec01Ub162,
|
||||
WebRtcIsac_kLpcShapeCdfVec01Ub163,
|
||||
WebRtcIsac_kLpcShapeCdfVec01Ub164,
|
||||
WebRtcIsac_kLpcShapeCdfVec01Ub165,
|
||||
WebRtcIsac_kLpcShapeCdfVec01Ub166
|
||||
};
|
||||
|
||||
/*
|
||||
* The smallest reconstruction points for quantiztion of LAR coefficients.
|
||||
*/
|
||||
const double WebRtcIsac_kLpcShapeLeftRecPointUb16
|
||||
[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME] =
|
||||
{
|
||||
-0.8250, -0.9750, -1.1250, -2.1750, -0.9750, -1.1250, -1.4250,
|
||||
-2.6250, -1.4250, -1.2750, -1.8750, -3.6750, -1.7250, -1.8750,
|
||||
-2.3250, -5.4750
|
||||
};
|
||||
|
||||
/*
|
||||
* Number of reconstruction points of quantizers for LAR coefficients.
|
||||
*/
|
||||
const int16_t WebRtcIsac_kLpcShapeNumRecPointUb16
|
||||
[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME] =
|
||||
{
|
||||
13, 15, 17, 29, 15, 16, 20, 35, 20,
|
||||
20, 27, 54, 25, 27, 33, 70
|
||||
};
|
||||
|
||||
/*
|
||||
* Starting index for entropy decoder to search for the right interval,
|
||||
* one entry per LAR coefficient
|
||||
*/
|
||||
const uint16_t WebRtcIsac_kLpcShapeEntropySearchUb16
|
||||
[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME] =
|
||||
{
|
||||
6, 7, 8, 14, 7, 8, 10, 17, 10,
|
||||
10, 13, 27, 12, 13, 16, 35
|
||||
};
|
||||
|
||||
/*
|
||||
* LAR quantization step-size.
|
||||
*/
|
||||
const double WebRtcIsac_kLpcShapeQStepSizeUb16 = 0.150000;
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* lpc_shape_swb16_tables.h
|
||||
*
|
||||
* This file declares tables used for entropy coding of LPC shape of
|
||||
* upper-band signal if the bandwidth is 16 kHz.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_
|
||||
|
||||
#include "settings.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
extern const double WebRtcIsac_kMeanLarUb16[UB_LPC_ORDER];
|
||||
|
||||
extern const double WebRtcIsac_kIintraVecDecorrMatUb16[UB_LPC_ORDER][UB_LPC_ORDER];
|
||||
|
||||
extern const double WebRtcIsac_kInterVecDecorrMatUb16
|
||||
[UB16_LPC_VEC_PER_FRAME][UB16_LPC_VEC_PER_FRAME];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub16[14];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec1Ub16[16];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec2Ub16[18];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec3Ub16[30];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec4Ub16[16];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec5Ub16[17];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec6Ub16[21];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec7Ub16[36];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec8Ub16[21];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub160[21];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub161[28];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub162[55];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub163[26];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub164[28];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub165[34];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub166[71];
|
||||
|
||||
extern const uint16_t* WebRtcIsac_kLpcShapeCdfMatUb16
|
||||
[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
|
||||
|
||||
extern const double WebRtcIsac_kLpcShapeLeftRecPointUb16
|
||||
[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
|
||||
|
||||
extern const int16_t WebRtcIsac_kLpcShapeNumRecPointUb16
|
||||
[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeEntropySearchUb16
|
||||
[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
|
||||
|
||||
extern const double WebRtcIsac_kLpcShapeQStepSizeUb16;
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_
|
||||
601
webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.c
Normal file
601
webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.c
Normal file
@@ -0,0 +1,601 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* coding tables for the KLT coefficients */
|
||||
|
||||
#include "lpc_tables.h"
|
||||
#include "settings.h"
|
||||
|
||||
/* cdf array for model indicator */
|
||||
const uint16_t WebRtcIsac_kQKltModelCdf[4] = {
|
||||
0, 15434, 37548, 65535 };
|
||||
|
||||
/* pointer to cdf array for model indicator */
|
||||
const uint16_t *WebRtcIsac_kQKltModelCdfPtr[1] = {
|
||||
WebRtcIsac_kQKltModelCdf };
|
||||
|
||||
/* initial cdf index for decoder of model indicator */
|
||||
const uint16_t WebRtcIsac_kQKltModelInitIndex[1] = { 1 };
|
||||
|
||||
/* offset to go from rounded value to quantization index */
|
||||
const short WebRtcIsac_kQKltQuantMinGain[12] = {
|
||||
3, 6, 4, 6, 6, 9, 5, 16, 11, 34, 32, 47 };
|
||||
|
||||
|
||||
const short WebRtcIsac_kQKltQuantMinShape[108] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 2, 2, 2, 3, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 1, 1,
|
||||
1, 1, 1, 2, 2, 3, 0, 0, 0, 0,
|
||||
1, 0, 1, 1, 1, 1, 1, 1, 1, 2,
|
||||
2, 4, 3, 5, 0, 0, 0, 0, 1, 1,
|
||||
1, 1, 1, 1, 2, 1, 2, 2, 3, 4,
|
||||
4, 7, 0, 0, 1, 1, 1, 1, 1, 1,
|
||||
1, 2, 3, 2, 3, 4, 4, 5, 7, 13,
|
||||
0, 1, 1, 2, 3, 2, 2, 2, 4, 4,
|
||||
5, 6, 7, 11, 9, 13, 12, 26 };
|
||||
|
||||
/* maximum quantization index */
|
||||
const uint16_t WebRtcIsac_kQKltMaxIndGain[12] = {
|
||||
6, 12, 8, 14, 10, 19, 12, 31, 22, 56, 52, 138 };
|
||||
|
||||
const uint16_t WebRtcIsac_kQKltMaxIndShape[108] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
2, 2, 2, 2, 4, 4, 5, 6, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 2, 2,
|
||||
2, 2, 3, 4, 5, 7, 0, 0, 0, 0,
|
||||
2, 0, 2, 2, 2, 2, 3, 2, 2, 4,
|
||||
4, 6, 6, 9, 0, 0, 0, 0, 2, 2,
|
||||
2, 2, 2, 2, 3, 2, 4, 4, 7, 7,
|
||||
9, 13, 0, 0, 2, 2, 2, 2, 2, 2,
|
||||
3, 4, 5, 4, 6, 8, 8, 10, 16, 25,
|
||||
0, 2, 2, 4, 5, 4, 4, 4, 7, 8,
|
||||
9, 10, 13, 19, 17, 23, 25, 49 };
|
||||
|
||||
/* index offset */
|
||||
const uint16_t WebRtcIsac_kQKltOffsetGain[12] = {
|
||||
0, 7, 20, 29, 44, 55, 75, 88, 120, 143, 200, 253 };
|
||||
|
||||
const uint16_t WebRtcIsac_kQKltOffsetShape[108] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
11, 14, 17, 20, 23, 28, 33, 39, 46, 47,
|
||||
48, 49, 50, 52, 53, 54, 55, 56, 58, 61,
|
||||
64, 67, 70, 74, 79, 85, 93, 94, 95, 96,
|
||||
97, 100, 101, 104, 107, 110, 113, 117, 120, 123,
|
||||
128, 133, 140, 147, 157, 158, 159, 160, 161, 164,
|
||||
167, 170, 173, 176, 179, 183, 186, 191, 196, 204,
|
||||
212, 222, 236, 237, 238, 241, 244, 247, 250, 253,
|
||||
256, 260, 265, 271, 276, 283, 292, 301, 312, 329,
|
||||
355, 356, 359, 362, 367, 373, 378, 383, 388, 396,
|
||||
405, 415, 426, 440, 460, 478, 502, 528 };
|
||||
|
||||
/* initial cdf index for KLT coefficients */
|
||||
const uint16_t WebRtcIsac_kQKltInitIndexGain[12] = {
|
||||
3, 6, 4, 7, 5, 10, 6, 16, 11, 28, 26, 69};
|
||||
|
||||
const uint16_t WebRtcIsac_kQKltInitIndexShape[108] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 2, 2, 3, 3, 0, 0,
|
||||
0, 0, 1, 0, 0, 0, 0, 1, 1, 1,
|
||||
1, 1, 2, 2, 3, 4, 0, 0, 0, 0,
|
||||
1, 0, 1, 1, 1, 1, 2, 1, 1, 2,
|
||||
2, 3, 3, 5, 0, 0, 0, 0, 1, 1,
|
||||
1, 1, 1, 1, 2, 1, 2, 2, 4, 4,
|
||||
5, 7, 0, 0, 1, 1, 1, 1, 1, 1,
|
||||
2, 2, 3, 2, 3, 4, 4, 5, 8, 13,
|
||||
0, 1, 1, 2, 3, 2, 2, 2, 4, 4,
|
||||
5, 5, 7, 10, 9, 12, 13, 25 };
|
||||
|
||||
|
||||
/* quantizer representation levels */
|
||||
const double WebRtcIsac_kQKltLevelsGain[392] = {
|
||||
-2.78127126, -1.76745590, -0.77913790, -0.00437329, 0.79961206,
|
||||
1.81775776, 2.81389782, -5.78753143, -4.88384084, -3.89320940,
|
||||
-2.88133610, -1.92859977, -0.86347396, 0.02003888, 0.86140400,
|
||||
1.89667156, 2.97134967, 3.98781964, 4.91727277, 5.82865898,
|
||||
-4.11195874, -2.80898424, -1.87547977, -0.80943825, -0.00679084,
|
||||
0.79573851, 1.83953397, 2.67586037, 3.76274082, -6.10933968,
|
||||
-4.93034581, -3.89281296, -2.91530625, -1.89684163, -0.85319130,
|
||||
-0.02275767, 0.86862017, 1.91578276, 2.96107339, 3.96543056,
|
||||
4.91369908, 5.91058154, 6.83848343, 8.07136925, -5.87470395,
|
||||
-4.84703049, -3.84284597, -2.86168446, -1.89290192, -0.82798145,
|
||||
-0.00080013, 0.82594974, 1.85754329, 2.88351798, 3.96172628,
|
||||
-8.85684885, -7.87387461, -6.97811862, -5.93256270, -4.94301439,
|
||||
-3.95513701, -2.96041544, -1.94031192, -0.87961478, -0.00456201,
|
||||
0.89911505, 1.91723376, 2.94011511, 3.93302540, 4.97990967,
|
||||
5.93133404, 7.02181199, 7.92407762, 8.80155440, 10.04665814,
|
||||
-4.82396678, -3.85612158, -2.89482244, -1.89558408, -0.90036978,
|
||||
-0.00677823, 0.90607989, 1.90937981, 2.91175777, 3.91637730,
|
||||
4.97565723, 5.84771228, 7.11145863, -16.07879840, -15.03776309,
|
||||
-13.93905670, -12.95671800, -11.89171202, -10.95820934, -9.95923714,
|
||||
-8.94357334, -7.99068299, -6.97481009, -5.94826231, -4.96673988,
|
||||
-3.97490466, -2.97846970, -1.95130435, -0.94215262, -0.01444043,
|
||||
0.96770704, 1.95848598, 2.94107862, 3.95666119, 4.97253085,
|
||||
5.97191122, 6.93277360, 7.96608727, 8.87958779, 10.00264269,
|
||||
10.86560820, 12.07449071, 13.04491775, 13.97507061, 14.91845261,
|
||||
-10.85696295, -9.83365357, -9.01245635, -7.95915145, -6.95625003,
|
||||
-5.95362618, -4.93468444, -3.98760978, -2.95044407, -1.97041277,
|
||||
-0.97701799, -0.00840234, 0.97834289, 1.98361415, 2.97802439,
|
||||
3.96415871, 4.95369042, 5.94101770, 6.92756798, 7.94063998,
|
||||
8.85951828, 9.97077022, 11.00068503, -33.92030406, -32.81426422,
|
||||
-32.00000000, -31.13243639, -30.11886909, -29.06017570, -28.12598824,
|
||||
-27.22045482, -25.81215858, -25.07849962, -23.93018013, -23.02097643,
|
||||
-21.89529725, -20.99091085, -19.98889048, -18.94327044, -17.96562071,
|
||||
-16.96126218, -15.95054062, -14.98516200, -13.97101012, -13.02106500,
|
||||
-11.98438006, -11.03216748, -9.95930286, -8.97043946, -7.98085082,
|
||||
-6.98360995, -5.98998802, -4.98668173, -4.00032906, -3.00420619,
|
||||
-1.98701132, -0.99324682, -0.00609324, 0.98297834, 1.99483076,
|
||||
3.00305044, 3.97142097, 4.97525759, 5.98612258, 6.97448236,
|
||||
7.97575900, 9.01086211, 9.98665542, 11.00541438, 11.98078628,
|
||||
12.92352471, 14.06849675, 14.99949430, 15.94904834, 16.97440321,
|
||||
18.04040916, 18.88987609, 20.05312391, 21.00000000, 21.79443341,
|
||||
-31.98578825, -31.00000000, -29.89060567, -28.98555686, -27.97114102,
|
||||
-26.84935410, -26.02402230, -24.94195278, -23.92336849, -22.95552382,
|
||||
-21.97932836, -20.96055470, -19.99649553, -19.03436122, -17.96706525,
|
||||
-17.01139515, -16.01363516, -14.99154248, -14.00298333, -12.99630613,
|
||||
-11.99955519, -10.99000421, -10.00819092, -8.99763648, -7.98431793,
|
||||
-7.01769025, -5.99604690, -4.99980697, -3.99334671, -3.01748192,
|
||||
-2.02051217, -1.00848371, -0.01942358, 1.00477757, 1.95477872,
|
||||
2.98593031, 3.98779079, 4.96862849, 6.02694771, 6.93983733,
|
||||
7.89874717, 8.99615862, 10.02367921, 10.96293452, 11.84351528,
|
||||
12.92207187, 13.85122329, 15.05146877, 15.99371264, 17.00000000,
|
||||
18.00000000, 19.00000000, 19.82763573, -47.00000000, -46.00000000,
|
||||
-44.87138498, -44.00000000, -43.00000000, -42.00000000, -41.00000000,
|
||||
-39.88966612, -38.98913239, -37.80306486, -37.23584325, -35.94200288,
|
||||
-34.99881301, -34.11361858, -33.06507360, -32.13129135, -30.90891364,
|
||||
-29.81511907, -28.99250380, -28.04535391, -26.99767800, -26.04418164,
|
||||
-24.95687851, -24.04865595, -23.03392645, -21.89366707, -20.93517364,
|
||||
-19.99388660, -18.91620943, -18.03749683, -16.99532379, -15.98683813,
|
||||
-15.06421479, -13.99359211, -12.99714098, -11.97022520, -10.98500279,
|
||||
-9.98834422, -8.95729330, -8.01232284, -7.00253661, -5.99681626,
|
||||
-5.01207817, -3.95914904, -3.01232178, -1.96615919, -0.97687670,
|
||||
0.01228030, 0.98412288, 2.01753544, 3.00580570, 3.97783510,
|
||||
4.98846894, 6.01321400, 7.00867732, 8.00416375, 9.01771966,
|
||||
9.98637729, 10.98255180, 11.99194163, 13.01807333, 14.00999545,
|
||||
15.00118556, 16.00089224, 17.00584148, 17.98251763, 18.99942091,
|
||||
19.96917690, 20.97839265, 21.98207297, 23.00171271, 23.99930737,
|
||||
24.99746061, 26.00936304, 26.98240132, 28.01126868, 29.01395915,
|
||||
29.98153507, 31.01376711, 31.99876818, 33.00475317, 33.99753994,
|
||||
34.99493913, 35.98933585, 36.95620160, 37.98428461, 38.99317544,
|
||||
40.01832073, 40.98048133, 41.95999283, 42.98232091, 43.96523612,
|
||||
44.99574268, 45.99524194, 47.05464025, 48.03821548, 48.99354366,
|
||||
49.96400411, 50.98017973, 51.95184408, 52.96291806, 54.00194392,
|
||||
54.96603783, 55.95623778, 57.03076595, 58.05889901, 58.99081551,
|
||||
59.97928121, 61.05071612, 62.03971580, 63.01286038, 64.01290338,
|
||||
65.02074503, 65.99454594, 67.00399425, 67.96571257, 68.95305727,
|
||||
69.92030664, 70.95594862, 71.98088567, 73.04764124, 74.00285480,
|
||||
75.02696330, 75.89837673, 76.93459997, 78.16266309, 78.83317543,
|
||||
80.00000000, 80.87251574, 82.09803524, 83.10671664, 84.00000000,
|
||||
84.77023523, 86.00000000, 87.00000000, 87.92946897, 88.69159118,
|
||||
90.00000000, 90.90535270 };
|
||||
|
||||
const double WebRtcIsac_kQKltLevelsShape[578] = {
|
||||
0.00032397, 0.00008053, -0.00061202, -0.00012620, 0.00030437,
|
||||
0.00054764, -0.00027902, 0.00069360, 0.00029449, -0.80219239,
|
||||
0.00091089, -0.74514927, -0.00094283, 0.64030631, -0.60509119,
|
||||
0.00035575, 0.61851665, -0.62129957, 0.00375219, 0.60054900,
|
||||
-0.61554359, 0.00054977, 0.63362016, -1.73118727, -0.65422341,
|
||||
0.00524568, 0.66165298, 1.76785515, -1.83182018, -0.65997434,
|
||||
-0.00011887, 0.67524299, 1.79933938, -1.76344480, -0.72547708,
|
||||
-0.00133017, 0.73104704, 1.75305377, 2.85164534, -2.80423916,
|
||||
-1.71959639, -0.75419722, -0.00329945, 0.77196760, 1.72211069,
|
||||
2.87339653, 0.00031089, -0.00015311, 0.00018201, -0.00035035,
|
||||
-0.77357251, 0.00154647, -0.00047625, -0.00045299, 0.00086590,
|
||||
0.00044762, -0.83383829, 0.00024787, -0.68526258, -0.00122472,
|
||||
0.64643255, -0.60904942, -0.00448987, 0.62309184, -0.59626442,
|
||||
-0.00574132, 0.62296546, -0.63222115, 0.00013441, 0.63609545,
|
||||
-0.66911055, -0.00369971, 0.66346095, 2.07281301, -1.77184694,
|
||||
-0.67640425, -0.00010145, 0.64818392, 1.74948973, -1.69420224,
|
||||
-0.71943894, -0.00004680, 0.75303493, 1.81075983, 2.80610041,
|
||||
-2.80005755, -1.79866753, -0.77409777, -0.00084220, 0.80141293,
|
||||
1.78291081, 2.73954236, 3.82994169, 0.00015140, -0.00012766,
|
||||
-0.00034241, -0.00119125, -0.76113497, 0.00069246, 0.76722027,
|
||||
0.00132862, -0.69107530, 0.00010656, 0.77061578, -0.78012970,
|
||||
0.00095947, 0.77828502, -0.64787758, 0.00217168, 0.63050167,
|
||||
-0.58601125, 0.00306596, 0.59466308, -0.58603410, 0.00059779,
|
||||
0.64257970, 1.76512766, -0.61193600, -0.00259517, 0.59767574,
|
||||
-0.61026273, 0.00315811, 0.61725479, -1.69169719, -0.65816029,
|
||||
0.00067575, 0.65576890, 2.00000000, -1.72689193, -0.69780808,
|
||||
-0.00040990, 0.70668487, 1.74198458, -3.79028154, -3.00000000,
|
||||
-1.73194459, -0.70179341, -0.00106695, 0.71302629, 1.76849782,
|
||||
-2.89332364, -1.78585007, -0.78731491, -0.00132610, 0.79692976,
|
||||
1.75247009, 2.97828682, -5.26238694, -3.69559829, -2.87286122,
|
||||
-1.84908818, -0.84434577, -0.01167975, 0.84641753, 1.84087672,
|
||||
2.87628156, 3.83556679, -0.00190204, 0.00092642, 0.00354385,
|
||||
-0.00012982, -0.67742785, 0.00229509, 0.64935672, -0.58444751,
|
||||
0.00470733, 0.57299534, -0.58456202, -0.00097715, 0.64593607,
|
||||
-0.64060330, -0.00638534, 0.59680157, -0.59287537, 0.00490772,
|
||||
0.58919707, -0.60306173, -0.00417464, 0.60562100, -1.75218757,
|
||||
-0.63018569, -0.00225922, 0.63863300, -0.63949939, -0.00126421,
|
||||
0.64268914, -1.75851182, -0.68318060, 0.00510418, 0.69049211,
|
||||
1.88178506, -1.71136148, -0.72710534, -0.00815559, 0.73412917,
|
||||
1.79996711, -2.77111145, -1.73940498, -0.78212945, 0.01074476,
|
||||
0.77688916, 1.76873972, 2.87281379, 3.77554698, -3.75832725,
|
||||
-2.95463235, -1.80451491, -0.80017226, 0.00149902, 0.80729206,
|
||||
1.78265046, 2.89391793, -3.78236148, -2.83640598, -1.82532067,
|
||||
-0.88844327, -0.00620952, 0.88208030, 1.85757631, 2.81712391,
|
||||
3.88430176, 5.16179367, -7.00000000, -5.93805408, -4.87172597,
|
||||
-3.87524433, -2.89399744, -1.92359563, -0.92136341, -0.00172725,
|
||||
0.93087018, 1.90528280, 2.89809686, 3.88085708, 4.89147740,
|
||||
5.89078692, -0.00239502, 0.00312564, -1.00000000, 0.00178325,
|
||||
1.00000000, -0.62198029, 0.00143254, 0.65344051, -0.59851220,
|
||||
-0.00676987, 0.61510140, -0.58894151, 0.00385055, 0.59794203,
|
||||
-0.59808568, -0.00038214, 0.57625703, -0.63009713, -0.01107985,
|
||||
0.61278758, -0.64206758, -0.00154369, 0.65480598, 1.80604162,
|
||||
-1.80909286, -0.67810514, 0.00205762, 0.68571097, 1.79453891,
|
||||
-3.22682422, -1.73808453, -0.71870305, -0.00738594, 0.71486172,
|
||||
1.73005326, -1.66891897, -0.73689615, -0.00616203, 0.74262409,
|
||||
1.73807899, -2.92417482, -1.73866741, -0.78133871, 0.00764425,
|
||||
0.80027264, 1.78668732, 2.74992588, -4.00000000, -2.75578740,
|
||||
-1.83697516, -0.83117035, -0.00355191, 0.83527172, 1.82814700,
|
||||
2.77377675, 3.80718693, -3.81667698, -2.83575471, -1.83372350,
|
||||
-0.86579471, 0.00547578, 0.87582281, 1.82858793, 2.87265007,
|
||||
3.91405377, -4.87521600, -3.78999094, -2.86437014, -1.86964365,
|
||||
-0.90618018, 0.00128243, 0.91497811, 1.87374952, 2.83199819,
|
||||
3.91519130, 4.76632822, -6.68713448, -6.01252467, -4.94587936,
|
||||
-3.88795368, -2.91299088, -1.92592211, -0.95504570, -0.00089980,
|
||||
0.94565200, 1.93239633, 2.91832808, 3.91363475, 4.88920034,
|
||||
5.96471415, 6.83905252, 7.86195009, 8.81571018,-12.96141759,
|
||||
-11.73039516,-10.96459719, -9.97382433, -9.04414433, -7.89460619,
|
||||
-6.96628608, -5.93236595, -4.93337924, -3.95479990, -2.96451499,
|
||||
-1.96635876, -0.97271229, -0.00402238, 0.98343930, 1.98348291,
|
||||
2.96641164, 3.95456471, 4.95517089, 5.98975714, 6.90322073,
|
||||
7.90468849, 8.85639467, 9.97255498, 10.79006309, 11.81988596,
|
||||
0.04950500, -1.00000000, -0.01226628, 1.00000000, -0.59479469,
|
||||
-0.10438305, 0.59822144, -2.00000000, -0.67109149, -0.09256692,
|
||||
0.65171621, 2.00000000, -3.00000000, -1.68391999, -0.76681039,
|
||||
-0.03354151, 0.71509146, 1.77615472, -2.00000000, -0.68661511,
|
||||
-0.02497881, 0.66478398, 2.00000000, -2.00000000, -0.67032784,
|
||||
-0.00920582, 0.64892756, 2.00000000, -2.00000000, -0.68561894,
|
||||
0.03641869, 0.73021611, 1.68293863, -4.00000000, -2.72024184,
|
||||
-1.80096059, -0.81696185, 0.03604685, 0.79232033, 1.70070730,
|
||||
3.00000000, -4.00000000, -2.71795670, -1.80482986, -0.86001162,
|
||||
0.03764903, 0.87723968, 1.79970771, 2.72685932, 3.67589143,
|
||||
-5.00000000, -4.00000000, -2.85492548, -1.78996365, -0.83250358,
|
||||
-0.01376828, 0.84195506, 1.78161105, 2.76754458, 4.00000000,
|
||||
-6.00000000, -5.00000000, -3.82268811, -2.77563624, -1.82608163,
|
||||
-0.86486114, -0.02671886, 0.86693165, 1.88422879, 2.86248347,
|
||||
3.95632216, -7.00000000, -6.00000000, -5.00000000, -3.77533988,
|
||||
-2.86391432, -1.87052039, -0.90513658, 0.06271236, 0.91083620,
|
||||
1.85734756, 2.86031688, 3.82019418, 4.94420394, 6.00000000,
|
||||
-11.00000000,-10.00000000, -9.00000000, -8.00000000, -6.91952415,
|
||||
-6.00000000, -4.92044374, -3.87845165, -2.87392362, -1.88413020,
|
||||
-0.91915740, 0.00318517, 0.91602800, 1.89664838, 2.88925058,
|
||||
3.84123856, 4.78988651, 5.94526812, 6.81953917, 8.00000000,
|
||||
-9.00000000, -8.00000000, -7.03319143, -5.94530963, -4.86669720,
|
||||
-3.92438007, -2.88620396, -1.92848070, -0.94365985, 0.01671855,
|
||||
0.97349410, 1.93419878, 2.89740109, 3.89662823, 4.83235583,
|
||||
5.88106535, 6.80328232, 8.00000000,-13.00000000,-12.00000000,
|
||||
-11.00000000,-10.00000000, -9.00000000, -7.86033489, -6.83344055,
|
||||
-5.89844215, -4.90811454, -3.94841298, -2.95820490, -1.98627966,
|
||||
-0.99161468, -0.02286136, 0.96055651, 1.95052433, 2.93969396,
|
||||
3.94304346, 4.88522624, 5.87434241, 6.78309433, 7.87244101,
|
||||
9.00000000, 10.00000000,-12.09117356,-11.00000000,-10.00000000,
|
||||
-8.84766108, -7.86934236, -6.98544896, -5.94233429, -4.95583292,
|
||||
-3.95575986, -2.97085529, -1.98955811, -0.99359873, -0.00485413,
|
||||
0.98298870, 1.98093258, 2.96430203, 3.95540216, 4.96915010,
|
||||
5.96775124, 6.99236918, 7.96503302, 8.99864542, 9.85857723,
|
||||
10.96541926, 11.91647197, 12.71060069,-26.00000000,-25.00000000,
|
||||
-24.00585596,-23.11642573,-22.14271284,-20.89800711,-19.87815799,
|
||||
-19.05036354,-17.88555651,-16.86471209,-15.97711073,-14.94012359,
|
||||
-14.02661226,-12.98243228,-11.97489256,-10.97402777, -9.96425624,
|
||||
-9.01085220, -7.97372506, -6.98795002, -5.97271328, -5.00191694,
|
||||
-3.98055849, -2.98458048, -1.99470442, -0.99656768, -0.00825666,
|
||||
1.00272004, 1.99922218, 2.99357669, 4.01407905, 5.01003897,
|
||||
5.98115528, 7.00018958, 8.00338125, 8.98981046, 9.98990318,
|
||||
10.96341479, 11.96866930, 12.99175139, 13.94580443, 14.95745083,
|
||||
15.98992869, 16.97484646, 17.99630043, 18.93396897, 19.88347741,
|
||||
20.96532482, 21.92191032, 23.22314702 };
|
||||
|
||||
|
||||
/* cdf tables for quantizer indices */
|
||||
const uint16_t WebRtcIsac_kQKltCdfGain[404] = {
|
||||
0, 13, 301, 3730, 61784, 65167, 65489, 65535, 0, 17,
|
||||
142, 314, 929, 2466, 7678, 56450, 63463, 64740, 65204, 65426,
|
||||
65527, 65535, 0, 8, 100, 724, 6301, 60105, 65125, 65510,
|
||||
65531, 65535, 0, 13, 117, 368, 1068, 3010, 11928, 53603,
|
||||
61177, 63404, 64505, 65108, 65422, 65502, 65531, 65535, 0, 4,
|
||||
17, 96, 410, 1859, 12125, 54361, 64103, 65305, 65497, 65535,
|
||||
0, 4, 88, 230, 469, 950, 1746, 3228, 6092, 16592,
|
||||
44756, 56848, 61256, 63308, 64325, 64920, 65309, 65460, 65502,
|
||||
65522, 65535, 0, 88, 352, 1675, 6339, 20749, 46686, 59284, 63525,
|
||||
64949, 65359, 65502, 65527, 65535, 0, 13, 38, 63, 117,
|
||||
234, 381, 641, 929, 1407, 2043, 2809, 4032, 5753, 8792,
|
||||
14407, 24308, 38941, 48947, 55403, 59293, 61411, 62688, 63630,
|
||||
64329, 64840, 65188, 65376, 65472, 65506, 65527, 65531, 65535,
|
||||
0, 8, 29, 75, 222, 615, 1327, 2801, 5623, 9931, 16094, 24966,
|
||||
34419, 43458, 50676, 56186, 60055, 62500, 63936, 64765, 65225,
|
||||
65435, 65514, 65535, 0, 8, 13, 15, 17, 21, 33, 59,
|
||||
71, 92, 151, 243, 360, 456, 674, 934, 1223, 1583,
|
||||
1989, 2504, 3031, 3617, 4354, 5154, 6163, 7411, 8780, 10747,
|
||||
12874, 15591, 18974, 23027, 27436, 32020, 36948, 41830, 46205,
|
||||
49797, 53042, 56094, 58418, 60360, 61763, 62818, 63559, 64103,
|
||||
64509, 64798, 65045, 65162, 65288, 65363, 65447, 65506, 65522,
|
||||
65531, 65533, 65535, 0, 4, 6, 25, 38, 71, 138, 264, 519, 808,
|
||||
1227, 1825, 2516, 3408, 4279, 5560, 7092, 9197, 11420, 14108,
|
||||
16947, 20300, 23926, 27459, 31164, 34827, 38575, 42178, 45540,
|
||||
48747, 51444, 54090, 56426, 58460, 60080, 61595, 62734, 63668,
|
||||
64275, 64673, 64936, 65112, 65217, 65334, 65426, 65464, 65477,
|
||||
65489, 65518, 65527, 65529, 65531, 65533, 65535, 0, 2, 4, 8, 10,
|
||||
12, 14, 16, 21, 33, 50, 71, 84, 92, 105, 138, 180, 255, 318,
|
||||
377, 435, 473, 511, 590, 682, 758, 913, 1097, 1256, 1449, 1671,
|
||||
1884, 2169, 2445, 2772, 3157, 3563, 3944, 4375, 4848, 5334, 5820,
|
||||
6448, 7101, 7716, 8378, 9102, 9956, 10752, 11648, 12707, 13670,
|
||||
14758, 15910, 17187, 18472, 19627, 20649, 21951, 23169, 24283,
|
||||
25552, 26862, 28227, 29391, 30764, 31882, 33213, 34432, 35600,
|
||||
36910, 38116, 39464, 40729, 41872, 43144, 44371, 45514, 46762,
|
||||
47813, 48968, 50069, 51032, 51974, 52908, 53737, 54603, 55445,
|
||||
56282, 56990, 57572, 58191, 58840, 59410, 59887, 60264, 60607,
|
||||
60946, 61269, 61516, 61771, 61960, 62198, 62408, 62558, 62776,
|
||||
62985, 63207, 63408, 63546, 63739, 63906, 64070, 64237, 64371,
|
||||
64551, 64677, 64836, 64999, 65095, 65213, 65284, 65338, 65380,
|
||||
65426, 65447, 65472, 65485, 65487, 65489, 65502, 65510, 65512,
|
||||
65514, 65516, 65518, 65522, 65531, 65533, 65535 };
|
||||
|
||||
|
||||
const uint16_t WebRtcIsac_kQKltCdfShape[686] = {
|
||||
0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535,
|
||||
0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 4,
|
||||
65535, 0, 8, 65514, 65535, 0, 29, 65481, 65535, 0,
|
||||
121, 65439, 65535, 0, 239, 65284, 65535, 0, 8, 779,
|
||||
64999, 65527, 65535, 0, 8, 888, 64693, 65522, 65535, 0,
|
||||
29, 2604, 62843, 65497, 65531, 65535, 0, 25, 176, 4576,
|
||||
61164, 65275, 65527, 65535, 0, 65535, 0, 65535, 0, 65535,
|
||||
0, 65535, 0, 4, 65535, 0, 65535, 0, 65535, 0,
|
||||
65535, 0, 65535, 0, 4, 65535, 0, 33, 65502, 65535,
|
||||
0, 54, 65481, 65535, 0, 251, 65309, 65535, 0, 611,
|
||||
65074, 65535, 0, 1273, 64292, 65527, 65535, 0, 4, 1809,
|
||||
63940, 65518, 65535, 0, 88, 4392, 60603, 65426, 65531, 65535,
|
||||
0, 25, 419, 7046, 57756, 64961, 65514, 65531, 65535, 0,
|
||||
65535, 0, 65535, 0, 65535, 0, 65535, 0, 4, 65531,
|
||||
65535, 0, 65535, 0, 8, 65531, 65535, 0, 4, 65527,
|
||||
65535, 0, 17, 65510, 65535, 0, 42, 65481, 65535, 0,
|
||||
197, 65342, 65531, 65535, 0, 385, 65154, 65535, 0, 1005,
|
||||
64522, 65535, 0, 8, 1985, 63469, 65533, 65535, 0, 38,
|
||||
3119, 61884, 65514, 65535, 0, 4, 6, 67, 4961, 60804,
|
||||
65472, 65535, 0, 17, 565, 9182, 56538, 65087, 65514, 65535,
|
||||
0, 8, 63, 327, 2118, 14490, 52774, 63839, 65376, 65522,
|
||||
65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0,
|
||||
17, 65522, 65535, 0, 59, 65489, 65535, 0, 50, 65522,
|
||||
65535, 0, 54, 65489, 65535, 0, 310, 65179, 65535, 0,
|
||||
615, 64836, 65535, 0, 4, 1503, 63965, 65535, 0, 2780,
|
||||
63383, 65535, 0, 21, 3919, 61051, 65527, 65535, 0, 84,
|
||||
6674, 59929, 65435, 65535, 0, 4, 255, 7976, 55784, 65150,
|
||||
65518, 65531, 65535, 0, 4, 8, 582, 10726, 53465, 64949,
|
||||
65518, 65535, 0, 29, 339, 3006, 17555, 49517, 62956, 65200,
|
||||
65497, 65531, 65535, 0, 2, 33, 138, 565, 2324, 7670,
|
||||
22089, 45966, 58949, 63479, 64966, 65380, 65518, 65535, 0, 65535,
|
||||
0, 65535, 0, 2, 65533, 65535, 0, 46, 65514, 65535,
|
||||
0, 414, 65091, 65535, 0, 540, 64911, 65535, 0, 419,
|
||||
65162, 65535, 0, 976, 64790, 65535, 0, 2977, 62495, 65531,
|
||||
65535, 0, 4, 3852, 61034, 65527, 65535, 0, 4, 29,
|
||||
6021, 60243, 65468, 65535, 0, 84, 6711, 58066, 65418, 65535,
|
||||
0, 13, 281, 9550, 54917, 65125, 65506, 65535, 0, 2,
|
||||
63, 984, 12108, 52644, 64342, 65435, 65527, 65535, 0, 29,
|
||||
251, 2014, 14871, 47553, 62881, 65229, 65518, 65535, 0, 13,
|
||||
142, 749, 4220, 18497, 45200, 60913, 64823, 65426, 65527, 65535,
|
||||
0, 13, 71, 264, 1176, 3789, 10500, 24480, 43488, 56324,
|
||||
62315, 64493, 65242, 65464, 65514, 65522, 65531, 65535, 0, 4,
|
||||
13, 38, 109, 205, 448, 850, 1708, 3429, 6276, 11371,
|
||||
19221, 29734, 40955, 49391, 55411, 59460, 62102, 63793, 64656,
|
||||
65150, 65401, 65485, 65522, 65531, 65535, 0, 65535, 0, 2, 65533,
|
||||
65535, 0, 1160, 65476, 65535, 0, 2, 6640, 64763, 65533,
|
||||
65535, 0, 2, 38, 9923, 61009, 65527, 65535, 0, 2,
|
||||
4949, 63092, 65533, 65535, 0, 2, 3090, 63398, 65533, 65535,
|
||||
0, 2, 2520, 58744, 65510, 65535, 0, 2, 13, 544,
|
||||
8784, 51403, 65148, 65533, 65535, 0, 2, 25, 1017, 10412,
|
||||
43550, 63651, 65489, 65527, 65535, 0, 2, 4, 29, 783,
|
||||
13377, 52462, 64524, 65495, 65533, 65535, 0, 2, 4, 6,
|
||||
100, 1817, 18451, 52590, 63559, 65376, 65531, 65535, 0, 2,
|
||||
4, 6, 46, 385, 2562, 11225, 37416, 60488, 65026, 65487,
|
||||
65529, 65533, 65535, 0, 2, 4, 6, 8, 10, 12,
|
||||
42, 222, 971, 5221, 19811, 45048, 60312, 64486, 65294, 65474,
|
||||
65525, 65529, 65533, 65535, 0, 2, 4, 8, 71, 167,
|
||||
666, 2533, 7875, 19622, 38082, 54359, 62108, 64633, 65290, 65495,
|
||||
65529, 65533, 65535, 0, 2, 4, 6, 8, 10, 13,
|
||||
109, 586, 1930, 4949, 11600, 22641, 36125, 48312, 56899, 61495,
|
||||
63927, 64932, 65389, 65489, 65518, 65531, 65533, 65535, 0, 4,
|
||||
6, 8, 67, 209, 712, 1838, 4195, 8432, 14432, 22834,
|
||||
31723, 40523, 48139, 53929, 57865, 60657, 62403, 63584, 64363,
|
||||
64907, 65167, 65372, 65472, 65514, 65535, 0, 2, 4, 13, 25,
|
||||
42, 46, 50, 75, 113, 147, 281, 448, 657, 909,
|
||||
1185, 1591, 1976, 2600, 3676, 5317, 7398, 9914, 12941, 16169,
|
||||
19477, 22885, 26464, 29851, 33360, 37228, 41139, 44802, 48654,
|
||||
52058, 55181, 57676, 59581, 61022, 62190, 63107, 63676, 64199,
|
||||
64547, 64924, 65158, 65313, 65430, 65481, 65518, 65535 };
|
||||
|
||||
|
||||
/* pointers to cdf tables for quantizer indices */
|
||||
const uint16_t *WebRtcIsac_kQKltCdfPtrGain[12] = {
|
||||
WebRtcIsac_kQKltCdfGain +0 +0, WebRtcIsac_kQKltCdfGain +0 +8,
|
||||
WebRtcIsac_kQKltCdfGain +0 +22, WebRtcIsac_kQKltCdfGain +0 +32,
|
||||
WebRtcIsac_kQKltCdfGain +0 +48, WebRtcIsac_kQKltCdfGain +0 +60,
|
||||
WebRtcIsac_kQKltCdfGain +0 +81, WebRtcIsac_kQKltCdfGain +0 +95,
|
||||
WebRtcIsac_kQKltCdfGain +0 +128, WebRtcIsac_kQKltCdfGain +0 +152,
|
||||
WebRtcIsac_kQKltCdfGain +0 +210, WebRtcIsac_kQKltCdfGain +0 +264 };
|
||||
|
||||
const uint16_t *WebRtcIsac_kQKltCdfPtrShape[108] = {
|
||||
WebRtcIsac_kQKltCdfShape +0 +0, WebRtcIsac_kQKltCdfShape +0 +2,
|
||||
WebRtcIsac_kQKltCdfShape +0 +4, WebRtcIsac_kQKltCdfShape +0 +6,
|
||||
WebRtcIsac_kQKltCdfShape +0 +8, WebRtcIsac_kQKltCdfShape +0 +10,
|
||||
WebRtcIsac_kQKltCdfShape +0 +12, WebRtcIsac_kQKltCdfShape +0 +14,
|
||||
WebRtcIsac_kQKltCdfShape +0 +16, WebRtcIsac_kQKltCdfShape +0 +18,
|
||||
WebRtcIsac_kQKltCdfShape +0 +21, WebRtcIsac_kQKltCdfShape +0 +25,
|
||||
WebRtcIsac_kQKltCdfShape +0 +29, WebRtcIsac_kQKltCdfShape +0 +33,
|
||||
WebRtcIsac_kQKltCdfShape +0 +37, WebRtcIsac_kQKltCdfShape +0 +43,
|
||||
WebRtcIsac_kQKltCdfShape +0 +49, WebRtcIsac_kQKltCdfShape +0 +56,
|
||||
WebRtcIsac_kQKltCdfShape +0 +64, WebRtcIsac_kQKltCdfShape +0 +66,
|
||||
WebRtcIsac_kQKltCdfShape +0 +68, WebRtcIsac_kQKltCdfShape +0 +70,
|
||||
WebRtcIsac_kQKltCdfShape +0 +72, WebRtcIsac_kQKltCdfShape +0 +75,
|
||||
WebRtcIsac_kQKltCdfShape +0 +77, WebRtcIsac_kQKltCdfShape +0 +79,
|
||||
WebRtcIsac_kQKltCdfShape +0 +81, WebRtcIsac_kQKltCdfShape +0 +83,
|
||||
WebRtcIsac_kQKltCdfShape +0 +86, WebRtcIsac_kQKltCdfShape +0 +90,
|
||||
WebRtcIsac_kQKltCdfShape +0 +94, WebRtcIsac_kQKltCdfShape +0 +98,
|
||||
WebRtcIsac_kQKltCdfShape +0 +102, WebRtcIsac_kQKltCdfShape +0 +107,
|
||||
WebRtcIsac_kQKltCdfShape +0 +113, WebRtcIsac_kQKltCdfShape +0 +120,
|
||||
WebRtcIsac_kQKltCdfShape +0 +129, WebRtcIsac_kQKltCdfShape +0 +131,
|
||||
WebRtcIsac_kQKltCdfShape +0 +133, WebRtcIsac_kQKltCdfShape +0 +135,
|
||||
WebRtcIsac_kQKltCdfShape +0 +137, WebRtcIsac_kQKltCdfShape +0 +141,
|
||||
WebRtcIsac_kQKltCdfShape +0 +143, WebRtcIsac_kQKltCdfShape +0 +147,
|
||||
WebRtcIsac_kQKltCdfShape +0 +151, WebRtcIsac_kQKltCdfShape +0 +155,
|
||||
WebRtcIsac_kQKltCdfShape +0 +159, WebRtcIsac_kQKltCdfShape +0 +164,
|
||||
WebRtcIsac_kQKltCdfShape +0 +168, WebRtcIsac_kQKltCdfShape +0 +172,
|
||||
WebRtcIsac_kQKltCdfShape +0 +178, WebRtcIsac_kQKltCdfShape +0 +184,
|
||||
WebRtcIsac_kQKltCdfShape +0 +192, WebRtcIsac_kQKltCdfShape +0 +200,
|
||||
WebRtcIsac_kQKltCdfShape +0 +211, WebRtcIsac_kQKltCdfShape +0 +213,
|
||||
WebRtcIsac_kQKltCdfShape +0 +215, WebRtcIsac_kQKltCdfShape +0 +217,
|
||||
WebRtcIsac_kQKltCdfShape +0 +219, WebRtcIsac_kQKltCdfShape +0 +223,
|
||||
WebRtcIsac_kQKltCdfShape +0 +227, WebRtcIsac_kQKltCdfShape +0 +231,
|
||||
WebRtcIsac_kQKltCdfShape +0 +235, WebRtcIsac_kQKltCdfShape +0 +239,
|
||||
WebRtcIsac_kQKltCdfShape +0 +243, WebRtcIsac_kQKltCdfShape +0 +248,
|
||||
WebRtcIsac_kQKltCdfShape +0 +252, WebRtcIsac_kQKltCdfShape +0 +258,
|
||||
WebRtcIsac_kQKltCdfShape +0 +264, WebRtcIsac_kQKltCdfShape +0 +273,
|
||||
WebRtcIsac_kQKltCdfShape +0 +282, WebRtcIsac_kQKltCdfShape +0 +293,
|
||||
WebRtcIsac_kQKltCdfShape +0 +308, WebRtcIsac_kQKltCdfShape +0 +310,
|
||||
WebRtcIsac_kQKltCdfShape +0 +312, WebRtcIsac_kQKltCdfShape +0 +316,
|
||||
WebRtcIsac_kQKltCdfShape +0 +320, WebRtcIsac_kQKltCdfShape +0 +324,
|
||||
WebRtcIsac_kQKltCdfShape +0 +328, WebRtcIsac_kQKltCdfShape +0 +332,
|
||||
WebRtcIsac_kQKltCdfShape +0 +336, WebRtcIsac_kQKltCdfShape +0 +341,
|
||||
WebRtcIsac_kQKltCdfShape +0 +347, WebRtcIsac_kQKltCdfShape +0 +354,
|
||||
WebRtcIsac_kQKltCdfShape +0 +360, WebRtcIsac_kQKltCdfShape +0 +368,
|
||||
WebRtcIsac_kQKltCdfShape +0 +378, WebRtcIsac_kQKltCdfShape +0 +388,
|
||||
WebRtcIsac_kQKltCdfShape +0 +400, WebRtcIsac_kQKltCdfShape +0 +418,
|
||||
WebRtcIsac_kQKltCdfShape +0 +445, WebRtcIsac_kQKltCdfShape +0 +447,
|
||||
WebRtcIsac_kQKltCdfShape +0 +451, WebRtcIsac_kQKltCdfShape +0 +455,
|
||||
WebRtcIsac_kQKltCdfShape +0 +461, WebRtcIsac_kQKltCdfShape +0 +468,
|
||||
WebRtcIsac_kQKltCdfShape +0 +474, WebRtcIsac_kQKltCdfShape +0 +480,
|
||||
WebRtcIsac_kQKltCdfShape +0 +486, WebRtcIsac_kQKltCdfShape +0 +495,
|
||||
WebRtcIsac_kQKltCdfShape +0 +505, WebRtcIsac_kQKltCdfShape +0 +516,
|
||||
WebRtcIsac_kQKltCdfShape +0 +528, WebRtcIsac_kQKltCdfShape +0 +543,
|
||||
WebRtcIsac_kQKltCdfShape +0 +564, WebRtcIsac_kQKltCdfShape +0 +583,
|
||||
WebRtcIsac_kQKltCdfShape +0 +608, WebRtcIsac_kQKltCdfShape +0 +635 };
|
||||
|
||||
|
||||
/* left KLT transforms */
|
||||
const double WebRtcIsac_kKltT1Gain[4] = {
|
||||
-0.79742827, 0.60341375, 0.60341375, 0.79742827 };
|
||||
|
||||
const double WebRtcIsac_kKltT1Shape[324] = {
|
||||
0.00159597, 0.00049320, 0.00513821, 0.00021066, 0.01338581,
|
||||
-0.00422367, -0.00272072, 0.00935107, 0.02047622, 0.02691189,
|
||||
0.00478236, 0.03969702, 0.00886698, 0.04877604, -0.10898362,
|
||||
-0.05930891, -0.03415047, 0.98889721, 0.00293558, -0.00035282,
|
||||
0.01156321, -0.00195341, -0.00937631, 0.01052213, -0.02551163,
|
||||
0.01644059, 0.03189927, 0.07754773, -0.08742313, -0.03026338,
|
||||
0.05136248, -0.14395974, 0.17725040, 0.22664856, 0.93380230,
|
||||
0.07076411, 0.00557890, -0.00222834, 0.01377569, 0.01466808,
|
||||
0.02847361, -0.00603178, 0.02382480, -0.01210452, 0.03797267,
|
||||
-0.02371480, 0.11260335, -0.07366682, 0.00453436, -0.04136941,
|
||||
-0.07912843, -0.95031418, 0.25295337, -0.05302216, -0.00617554,
|
||||
-0.00044040, -0.00653778, 0.01097838, 0.01529174, 0.01374431,
|
||||
-0.00748512, -0.00020034, 0.02432713, 0.11101570, -0.08556891,
|
||||
0.09282249, -0.01029446, 0.67556443, -0.67454300, 0.06910063,
|
||||
0.20866865, -0.10318050, 0.00932175, 0.00524058, 0.00803610,
|
||||
-0.00594676, -0.01082578, 0.01069906, 0.00546768, 0.01565291,
|
||||
0.06816200, 0.10201227, 0.16812734, 0.22984074, 0.58213170,
|
||||
-0.54138651, -0.51379962, 0.06847390, -0.01920037, -0.04592324,
|
||||
-0.00467394, 0.00328858, 0.00377424, -0.00987448, 0.08222096,
|
||||
-0.00377301, 0.04551941, -0.02592517, 0.16317082, 0.13077530,
|
||||
0.22702921, -0.31215289, -0.69645962, -0.38047101, -0.39339411,
|
||||
0.11124777, 0.02508035, -0.00708074, 0.00400344, 0.00040331,
|
||||
0.01142402, 0.01725406, 0.01635170, 0.14285366, 0.03949233,
|
||||
-0.05905676, 0.05877154, -0.17497577, -0.32479440, 0.80754464,
|
||||
-0.38085603, -0.17055430, -0.03168622, -0.07531451, 0.02942002,
|
||||
-0.02148095, -0.00754114, -0.00322372, 0.00567812, -0.01701521,
|
||||
-0.12358320, 0.11473564, 0.09070136, 0.06533068, -0.22560802,
|
||||
0.19209022, 0.81605094, 0.36592275, -0.09919829, 0.16667122,
|
||||
0.16300725, 0.04803807, 0.06739263, -0.00156752, -0.01685302,
|
||||
-0.00905240, -0.02297836, -0.00469939, 0.06310613, -0.16391930,
|
||||
0.10919511, 0.12529293, 0.85581322, -0.32145522, 0.24539076,
|
||||
0.07181839, 0.07289591, 0.14066759, 0.10406711, 0.05815518,
|
||||
0.01072680, -0.00759339, 0.00053486, -0.00044865, 0.03407361,
|
||||
0.01645348, 0.08758579, 0.27722240, 0.53665485, -0.74853376,
|
||||
-0.01118192, -0.19805430, 0.06130619, -0.09675299, 0.08978480,
|
||||
0.03405255, -0.00706867, 0.05102045, 0.03250746, 0.01849966,
|
||||
-0.01216314, -0.01184187, -0.01579288, 0.00114807, 0.11376166,
|
||||
0.88342114, -0.36425379, 0.13863190, 0.12524180, -0.13553892,
|
||||
0.04715856, -0.12341103, 0.04531568, 0.01899360, -0.00206897,
|
||||
0.00567768, -0.01444163, 0.00411946, -0.00855896, 0.00381663,
|
||||
-0.01664861, -0.05534280, 0.21328278, 0.20161162, 0.72360394,
|
||||
0.59130708, -0.08043791, 0.08757349, -0.13893918, -0.05147377,
|
||||
0.02680690, -0.01144070, 0.00625162, -0.00634215, -0.01248947,
|
||||
-0.00329455, -0.00609625, -0.00136305, -0.05097048, -0.01029851,
|
||||
0.25065384, -0.16856837, -0.07123372, 0.15992623, -0.39487617,
|
||||
-0.79972301, 0.18118185, -0.04826639, -0.01805578, -0.02927253,
|
||||
-0.16400618, 0.07472763, 0.10376449, 0.01705406, 0.01065801,
|
||||
-0.01500498, 0.02039914, 0.37776349, -0.84484186, 0.10434286,
|
||||
0.15616990, 0.13474456, -0.00906238, -0.25238368, -0.03820885,
|
||||
-0.10650905, -0.03880833, -0.03660028, -0.09640894, 0.00583314,
|
||||
0.01922097, 0.01489911, -0.02431117, -0.09372217, 0.39404721,
|
||||
-0.84786223, -0.31277121, 0.03193850, 0.01974060, 0.01887901,
|
||||
0.00337911, -0.11359599, -0.02792521, -0.03220184, -0.01533311,
|
||||
0.00015962, -0.04225043, -0.00933965, 0.00675311, 0.00206060,
|
||||
0.15926771, 0.40199829, -0.80792558, -0.35591604, -0.17169764,
|
||||
0.02830436, 0.02459982, -0.03438589, 0.00718705, -0.01798329,
|
||||
-0.01594508, -0.00702430, -0.00952419, -0.00962701, -0.01307212,
|
||||
-0.01749740, 0.01299602, 0.00587270, -0.36103108, -0.82039266,
|
||||
-0.43092844, -0.08500097, -0.04361674, -0.00333482, 0.01250434,
|
||||
-0.02538295, -0.00921797, 0.01645071, -0.01400872, 0.00317607,
|
||||
0.00003277, -0.01617646, -0.00616863, -0.00882661, 0.00466157,
|
||||
0.00353237, 0.91803104, -0.39503305, -0.02048964, 0.00060125,
|
||||
0.01980634, 0.00300109, 0.00313880, 0.00657337, 0.00715163,
|
||||
0.00000261, 0.00854276, -0.00154825, -0.00516128, 0.00909527,
|
||||
0.00095609, 0.00701196, -0.00221867, -0.00156741 };
|
||||
|
||||
/* right KLT transforms */
|
||||
const double WebRtcIsac_kKltT2Gain[36] = {
|
||||
0.14572837, -0.45446306, 0.61990621, -0.52197033, 0.32145074,
|
||||
-0.11026900, -0.20698282, 0.48962182, -0.27127933, -0.33627476,
|
||||
0.65094037, -0.32715751, 0.40262573, -0.47844405, -0.33876075,
|
||||
0.44130653, 0.37383966, -0.39964662, -0.51730480, 0.06611973,
|
||||
0.49030187, 0.47512886, -0.02141226, -0.51129451, -0.58578569,
|
||||
-0.39132064, -0.13187771, 0.15649421, 0.40735596, 0.54396897,
|
||||
0.40381276, 0.40904942, 0.41179766, 0.41167576, 0.40840251,
|
||||
0.40468132 };
|
||||
|
||||
const double WebRtcIsac_kKltT2Shape[36] = {
|
||||
0.13427386, -0.35132558, 0.52506528, -0.59419077, 0.45075085,
|
||||
-0.16312057, 0.29857439, -0.58660147, 0.34265431, 0.20879510,
|
||||
-0.56063262, 0.30238345, 0.43308283, -0.41186999, -0.35288681,
|
||||
0.42768996, 0.36094634, -0.45284910, -0.47116680, 0.02893449,
|
||||
0.54326135, 0.45249040, -0.06264420, -0.52283830, 0.57137758,
|
||||
0.44298139, 0.12617554, -0.20819946, -0.42324603, -0.48876443,
|
||||
0.39597050, 0.40713935, 0.41389880, 0.41512486, 0.41130400,
|
||||
0.40575001 };
|
||||
|
||||
/* means of log gains and LAR coefficients*/
|
||||
const double WebRtcIsac_kLpcMeansGain[12] = {
|
||||
-6.86881911, -5.35075273, -6.86792680, -5.36200897, -6.86401538,
|
||||
-5.36921533, -6.86802969, -5.36893966, -6.86538097, -5.36315063,
|
||||
-6.85535304, -5.35155315 };
|
||||
|
||||
const double WebRtcIsac_kLpcMeansShape[108] = {
|
||||
-0.91232981, 0.26258634, -0.33716701, 0.08477430, -0.03378426,
|
||||
0.14423909, 0.07036185, 0.06155019, 0.01490385, 0.04138740,
|
||||
0.01427317, 0.01288970, 0.83872106, 0.25750199, 0.07988929,
|
||||
-0.01957923, 0.00831390, 0.01770300, -0.90957164, 0.25732216,
|
||||
-0.33385344, 0.08735740, -0.03715332, 0.14584917, 0.06998990,
|
||||
0.06131968, 0.01504379, 0.04067339, 0.01428039, 0.01406460,
|
||||
0.83846243, 0.26169862, 0.08109025, -0.01767055, 0.00970539,
|
||||
0.01954310, -0.90490803, 0.24656405, -0.33578607, 0.08843286,
|
||||
-0.03749139, 0.14443959, 0.07214669, 0.06170993, 0.01449947,
|
||||
0.04134309, 0.01314762, 0.01413471, 0.83895203, 0.26748062,
|
||||
0.08197507, -0.01781298, 0.00885967, 0.01922394, -0.90922472,
|
||||
0.24495889, -0.33921540, 0.08877169, -0.03581332, 0.14199172,
|
||||
0.07444032, 0.06185940, 0.01502054, 0.04185113, 0.01276579,
|
||||
0.01355457, 0.83645358, 0.26631720, 0.08119697, -0.01835449,
|
||||
0.00788512, 0.01846446, -0.90482253, 0.24658310, -0.34019734,
|
||||
0.08281090, -0.03486038, 0.14359248, 0.07401336, 0.06001471,
|
||||
0.01528421, 0.04254560, 0.01321472, 0.01240799, 0.83857127,
|
||||
0.26281654, 0.08174380, -0.02099842, 0.00755176, 0.01699448,
|
||||
-0.90132307, 0.25174308, -0.33838268, 0.07883863, -0.02877906,
|
||||
0.14105407, 0.07220290, 0.06000352, 0.01684879, 0.04226844,
|
||||
0.01331331, 0.01269244, 0.83832138, 0.25467485, 0.08118028,
|
||||
-0.02120528, 0.00747832, 0.01567212 };
|
||||
100
webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.h
Normal file
100
webrtc/modules/audio_coding/codecs/isac/main/source/lpc_tables.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* lpc_tables.h
|
||||
*
|
||||
* header file for coding tables for the LPC coefficients
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_
|
||||
|
||||
#include "structs.h"
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#define KLT_STEPSIZE 1.00000000
|
||||
#define KLT_NUM_AVG_GAIN 0
|
||||
#define KLT_NUM_AVG_SHAPE 0
|
||||
#define KLT_NUM_MODELS 3
|
||||
#define LPC_GAIN_SCALE 4.000f
|
||||
#define LPC_LOBAND_SCALE 2.100f
|
||||
#define LPC_LOBAND_ORDER ORDERLO
|
||||
#define LPC_HIBAND_SCALE 0.450f
|
||||
#define LPC_HIBAND_ORDER ORDERHI
|
||||
#define LPC_GAIN_ORDER 2
|
||||
|
||||
#define LPC_SHAPE_ORDER (LPC_LOBAND_ORDER + LPC_HIBAND_ORDER)
|
||||
|
||||
#define KLT_ORDER_GAIN (LPC_GAIN_ORDER * SUBFRAMES)
|
||||
#define KLT_ORDER_SHAPE (LPC_SHAPE_ORDER * SUBFRAMES)
|
||||
|
||||
/* cdf array for model indicator */
|
||||
extern const uint16_t WebRtcIsac_kQKltModelCdf[KLT_NUM_MODELS+1];
|
||||
|
||||
/* pointer to cdf array for model indicator */
|
||||
extern const uint16_t *WebRtcIsac_kQKltModelCdfPtr[1];
|
||||
|
||||
/* initial cdf index for decoder of model indicator */
|
||||
extern const uint16_t WebRtcIsac_kQKltModelInitIndex[1];
|
||||
|
||||
/* offset to go from rounded value to quantization index */
|
||||
extern const short WebRtcIsac_kQKltQuantMinGain[12];
|
||||
|
||||
extern const short WebRtcIsac_kQKltQuantMinShape[108];
|
||||
|
||||
/* maximum quantization index */
|
||||
extern const uint16_t WebRtcIsac_kQKltMaxIndGain[12];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kQKltMaxIndShape[108];
|
||||
|
||||
/* index offset */
|
||||
extern const uint16_t WebRtcIsac_kQKltOffsetGain[12];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kQKltOffsetShape[108];
|
||||
|
||||
/* initial cdf index for KLT coefficients */
|
||||
extern const uint16_t WebRtcIsac_kQKltInitIndexGain[12];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kQKltInitIndexShape[108];
|
||||
|
||||
/* quantizer representation levels */
|
||||
extern const double WebRtcIsac_kQKltLevelsGain[392];
|
||||
|
||||
extern const double WebRtcIsac_kQKltLevelsShape[578];
|
||||
|
||||
/* cdf tables for quantizer indices */
|
||||
extern const uint16_t WebRtcIsac_kQKltCdfGain[404];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kQKltCdfShape[686];
|
||||
|
||||
/* pointers to cdf tables for quantizer indices */
|
||||
extern const uint16_t *WebRtcIsac_kQKltCdfPtrGain[12];
|
||||
|
||||
extern const uint16_t *WebRtcIsac_kQKltCdfPtrShape[108];
|
||||
|
||||
/* left KLT transforms */
|
||||
extern const double WebRtcIsac_kKltT1Gain[4];
|
||||
|
||||
extern const double WebRtcIsac_kKltT1Shape[324];
|
||||
|
||||
/* right KLT transforms */
|
||||
extern const double WebRtcIsac_kKltT2Gain[36];
|
||||
|
||||
extern const double WebRtcIsac_kKltT2Shape[36];
|
||||
|
||||
/* means of log gains and LAR coefficients */
|
||||
extern const double WebRtcIsac_kLpcMeansGain[12];
|
||||
|
||||
extern const double WebRtcIsac_kLpcMeansShape[108];
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_ */
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_
|
||||
|
||||
#include <math.h>
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
#if defined(WEBRTC_POSIX)
|
||||
#define WebRtcIsac_lrint lrint
|
||||
#elif (defined(WEBRTC_ARCH_X86) && defined(WIN32))
|
||||
static __inline long int WebRtcIsac_lrint(double x_dbl) {
|
||||
long int x_int;
|
||||
|
||||
__asm {
|
||||
fld x_dbl
|
||||
fistp x_int
|
||||
};
|
||||
|
||||
return x_int;
|
||||
}
|
||||
#else // Do a slow but correct implementation of lrint
|
||||
|
||||
static __inline long int WebRtcIsac_lrint(double x_dbl) {
|
||||
long int x_int;
|
||||
x_int = (long int)floor(x_dbl + 0.499999999999);
|
||||
return x_int;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_
|
||||
@@ -0,0 +1,623 @@
|
||||
/*
|
||||
* 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 "pitch_estimator.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
#ifdef WEBRTC_ANDROID
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
static const double kInterpolWin[8] = {-0.00067556028640, 0.02184247643159, -0.12203175715679, 0.60086484101160,
|
||||
0.60086484101160, -0.12203175715679, 0.02184247643159, -0.00067556028640};
|
||||
|
||||
/* interpolation filter */
|
||||
__inline static void IntrepolFilter(double *data_ptr, double *intrp)
|
||||
{
|
||||
*intrp = kInterpolWin[0] * data_ptr[-3];
|
||||
*intrp += kInterpolWin[1] * data_ptr[-2];
|
||||
*intrp += kInterpolWin[2] * data_ptr[-1];
|
||||
*intrp += kInterpolWin[3] * data_ptr[0];
|
||||
*intrp += kInterpolWin[4] * data_ptr[1];
|
||||
*intrp += kInterpolWin[5] * data_ptr[2];
|
||||
*intrp += kInterpolWin[6] * data_ptr[3];
|
||||
*intrp += kInterpolWin[7] * data_ptr[4];
|
||||
}
|
||||
|
||||
|
||||
/* 2D parabolic interpolation */
|
||||
/* probably some 0.5 factors can be eliminated, and the square-roots can be removed from the Cholesky fact. */
|
||||
__inline static void Intrpol2D(double T[3][3], double *x, double *y, double *peak_val)
|
||||
{
|
||||
double c, b[2], A[2][2];
|
||||
double t1, t2, d;
|
||||
double delta1, delta2;
|
||||
|
||||
|
||||
// double T[3][3] = {{-1.25, -.25,-.25}, {-.25, .75, .75}, {-.25, .75, .75}};
|
||||
// should result in: delta1 = 0.5; delta2 = 0.0; peak_val = 1.0
|
||||
|
||||
c = T[1][1];
|
||||
b[0] = 0.5 * (T[1][2] + T[2][1] - T[0][1] - T[1][0]);
|
||||
b[1] = 0.5 * (T[1][0] + T[2][1] - T[0][1] - T[1][2]);
|
||||
A[0][1] = -0.5 * (T[0][1] + T[2][1] - T[1][0] - T[1][2]);
|
||||
t1 = 0.5 * (T[0][0] + T[2][2]) - c;
|
||||
t2 = 0.5 * (T[2][0] + T[0][2]) - c;
|
||||
d = (T[0][1] + T[1][2] + T[1][0] + T[2][1]) - 4.0 * c - t1 - t2;
|
||||
A[0][0] = -t1 - 0.5 * d;
|
||||
A[1][1] = -t2 - 0.5 * d;
|
||||
|
||||
/* deal with singularities or ill-conditioned cases */
|
||||
if ( (A[0][0] < 1e-7) || ((A[0][0] * A[1][1] - A[0][1] * A[0][1]) < 1e-7) ) {
|
||||
*peak_val = T[1][1];
|
||||
return;
|
||||
}
|
||||
|
||||
/* Cholesky decomposition: replace A by upper-triangular factor */
|
||||
A[0][0] = sqrt(A[0][0]);
|
||||
A[0][1] = A[0][1] / A[0][0];
|
||||
A[1][1] = sqrt(A[1][1] - A[0][1] * A[0][1]);
|
||||
|
||||
/* compute [x; y] = -0.5 * inv(A) * b */
|
||||
t1 = b[0] / A[0][0];
|
||||
t2 = (b[1] - t1 * A[0][1]) / A[1][1];
|
||||
delta2 = t2 / A[1][1];
|
||||
delta1 = 0.5 * (t1 - delta2 * A[0][1]) / A[0][0];
|
||||
delta2 *= 0.5;
|
||||
|
||||
/* limit norm */
|
||||
t1 = delta1 * delta1 + delta2 * delta2;
|
||||
if (t1 > 1.0) {
|
||||
delta1 /= t1;
|
||||
delta2 /= t1;
|
||||
}
|
||||
|
||||
*peak_val = 0.5 * (b[0] * delta1 + b[1] * delta2) + c;
|
||||
|
||||
*x += delta1;
|
||||
*y += delta2;
|
||||
}
|
||||
|
||||
|
||||
static void PCorr(const double *in, double *outcorr)
|
||||
{
|
||||
double sum, ysum, prod;
|
||||
const double *x, *inptr;
|
||||
int k, n;
|
||||
|
||||
//ysum = 1e-6; /* use this with float (i.s.o. double)! */
|
||||
ysum = 1e-13;
|
||||
sum = 0.0;
|
||||
x = in + PITCH_MAX_LAG/2 + 2;
|
||||
for (n = 0; n < PITCH_CORR_LEN2; n++) {
|
||||
ysum += in[n] * in[n];
|
||||
sum += x[n] * in[n];
|
||||
}
|
||||
|
||||
outcorr += PITCH_LAG_SPAN2 - 1; /* index of last element in array */
|
||||
*outcorr = sum / sqrt(ysum);
|
||||
|
||||
for (k = 1; k < PITCH_LAG_SPAN2; k++) {
|
||||
ysum -= in[k-1] * in[k-1];
|
||||
ysum += in[PITCH_CORR_LEN2 + k - 1] * in[PITCH_CORR_LEN2 + k - 1];
|
||||
sum = 0.0;
|
||||
inptr = &in[k];
|
||||
prod = x[0] * inptr[0];
|
||||
for (n = 1; n < PITCH_CORR_LEN2; n++) {
|
||||
sum += prod;
|
||||
prod = x[n] * inptr[n];
|
||||
}
|
||||
sum += prod;
|
||||
outcorr--;
|
||||
*outcorr = sum / sqrt(ysum);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WebRtcIsac_InitializePitch(const double *in,
|
||||
const double old_lag,
|
||||
const double old_gain,
|
||||
PitchAnalysisStruct *State,
|
||||
double *lags)
|
||||
{
|
||||
double buf_dec[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2+2];
|
||||
double ratio, log_lag, gain_bias;
|
||||
double bias;
|
||||
double corrvec1[PITCH_LAG_SPAN2];
|
||||
double corrvec2[PITCH_LAG_SPAN2];
|
||||
int m, k;
|
||||
// Allocating 10 extra entries at the begining of the CorrSurf
|
||||
double corrSurfBuff[10 + (2*PITCH_BW+3)*(PITCH_LAG_SPAN2+4)];
|
||||
double* CorrSurf[2*PITCH_BW+3];
|
||||
double *CorrSurfPtr1, *CorrSurfPtr2;
|
||||
double LagWin[3] = {0.2, 0.5, 0.98};
|
||||
int ind1, ind2, peaks_ind, peak, max_ind;
|
||||
int peaks[PITCH_MAX_NUM_PEAKS];
|
||||
double adj, gain_tmp;
|
||||
double corr, corr_max;
|
||||
double intrp_a, intrp_b, intrp_c, intrp_d;
|
||||
double peak_vals[PITCH_MAX_NUM_PEAKS];
|
||||
double lags1[PITCH_MAX_NUM_PEAKS];
|
||||
double lags2[PITCH_MAX_NUM_PEAKS];
|
||||
double T[3][3];
|
||||
int row;
|
||||
|
||||
for(k = 0; k < 2*PITCH_BW+3; k++)
|
||||
{
|
||||
CorrSurf[k] = &corrSurfBuff[10 + k * (PITCH_LAG_SPAN2+4)];
|
||||
}
|
||||
/* reset CorrSurf matrix */
|
||||
memset(corrSurfBuff, 0, sizeof(double) * (10 + (2*PITCH_BW+3) * (PITCH_LAG_SPAN2+4)));
|
||||
|
||||
//warnings -DH
|
||||
max_ind = 0;
|
||||
peak = 0;
|
||||
|
||||
/* copy old values from state buffer */
|
||||
memcpy(buf_dec, State->dec_buffer, sizeof(double) * (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2));
|
||||
|
||||
/* decimation; put result after the old values */
|
||||
WebRtcIsac_DecimateAllpass(in, State->decimator_state, PITCH_FRAME_LEN,
|
||||
&buf_dec[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2]);
|
||||
|
||||
/* low-pass filtering */
|
||||
for (k = PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2; k < PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2+2; k++)
|
||||
buf_dec[k] += 0.75 * buf_dec[k-1] - 0.25 * buf_dec[k-2];
|
||||
|
||||
/* copy end part back into state buffer */
|
||||
memcpy(State->dec_buffer, buf_dec+PITCH_FRAME_LEN/2, sizeof(double) * (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2));
|
||||
|
||||
/* compute correlation for first and second half of the frame */
|
||||
PCorr(buf_dec, corrvec1);
|
||||
PCorr(buf_dec + PITCH_CORR_STEP2, corrvec2);
|
||||
|
||||
/* bias towards pitch lag of previous frame */
|
||||
log_lag = log(0.5 * old_lag);
|
||||
gain_bias = 4.0 * old_gain * old_gain;
|
||||
if (gain_bias > 0.8) gain_bias = 0.8;
|
||||
for (k = 0; k < PITCH_LAG_SPAN2; k++)
|
||||
{
|
||||
ratio = log((double) (k + (PITCH_MIN_LAG/2-2))) - log_lag;
|
||||
bias = 1.0 + gain_bias * exp(-5.0 * ratio * ratio);
|
||||
corrvec1[k] *= bias;
|
||||
}
|
||||
|
||||
/* taper correlation functions */
|
||||
for (k = 0; k < 3; k++) {
|
||||
gain_tmp = LagWin[k];
|
||||
corrvec1[k] *= gain_tmp;
|
||||
corrvec2[k] *= gain_tmp;
|
||||
corrvec1[PITCH_LAG_SPAN2-1-k] *= gain_tmp;
|
||||
corrvec2[PITCH_LAG_SPAN2-1-k] *= gain_tmp;
|
||||
}
|
||||
|
||||
corr_max = 0.0;
|
||||
/* fill middle row of correlation surface */
|
||||
ind1 = 0;
|
||||
ind2 = 0;
|
||||
CorrSurfPtr1 = &CorrSurf[PITCH_BW][2];
|
||||
for (k = 0; k < PITCH_LAG_SPAN2; k++) {
|
||||
corr = corrvec1[ind1++] + corrvec2[ind2++];
|
||||
CorrSurfPtr1[k] = corr;
|
||||
if (corr > corr_max) {
|
||||
corr_max = corr; /* update maximum */
|
||||
max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]);
|
||||
}
|
||||
}
|
||||
/* fill first and last rows of correlation surface */
|
||||
ind1 = 0;
|
||||
ind2 = PITCH_BW;
|
||||
CorrSurfPtr1 = &CorrSurf[0][2];
|
||||
CorrSurfPtr2 = &CorrSurf[2*PITCH_BW][PITCH_BW+2];
|
||||
for (k = 0; k < PITCH_LAG_SPAN2-PITCH_BW; k++) {
|
||||
ratio = ((double) (ind1 + 12)) / ((double) (ind2 + 12));
|
||||
adj = 0.2 * ratio * (2.0 - ratio); /* adjustment factor; inverse parabola as a function of ratio */
|
||||
corr = adj * (corrvec1[ind1] + corrvec2[ind2]);
|
||||
CorrSurfPtr1[k] = corr;
|
||||
if (corr > corr_max) {
|
||||
corr_max = corr; /* update maximum */
|
||||
max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]);
|
||||
}
|
||||
corr = adj * (corrvec1[ind2++] + corrvec2[ind1++]);
|
||||
CorrSurfPtr2[k] = corr;
|
||||
if (corr > corr_max) {
|
||||
corr_max = corr; /* update maximum */
|
||||
max_ind = (int)(&CorrSurfPtr2[k] - &CorrSurf[0][0]);
|
||||
}
|
||||
}
|
||||
/* fill second and next to last rows of correlation surface */
|
||||
ind1 = 0;
|
||||
ind2 = PITCH_BW-1;
|
||||
CorrSurfPtr1 = &CorrSurf[1][2];
|
||||
CorrSurfPtr2 = &CorrSurf[2*PITCH_BW-1][PITCH_BW+1];
|
||||
for (k = 0; k < PITCH_LAG_SPAN2-PITCH_BW+1; k++) {
|
||||
ratio = ((double) (ind1 + 12)) / ((double) (ind2 + 12));
|
||||
adj = 0.9 * ratio * (2.0 - ratio); /* adjustment factor; inverse parabola as a function of ratio */
|
||||
corr = adj * (corrvec1[ind1] + corrvec2[ind2]);
|
||||
CorrSurfPtr1[k] = corr;
|
||||
if (corr > corr_max) {
|
||||
corr_max = corr; /* update maximum */
|
||||
max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]);
|
||||
}
|
||||
corr = adj * (corrvec1[ind2++] + corrvec2[ind1++]);
|
||||
CorrSurfPtr2[k] = corr;
|
||||
if (corr > corr_max) {
|
||||
corr_max = corr; /* update maximum */
|
||||
max_ind = (int)(&CorrSurfPtr2[k] - &CorrSurf[0][0]);
|
||||
}
|
||||
}
|
||||
/* fill remainder of correlation surface */
|
||||
for (m = 2; m < PITCH_BW; m++) {
|
||||
ind1 = 0;
|
||||
ind2 = PITCH_BW - m; /* always larger than ind1 */
|
||||
CorrSurfPtr1 = &CorrSurf[m][2];
|
||||
CorrSurfPtr2 = &CorrSurf[2*PITCH_BW-m][PITCH_BW+2-m];
|
||||
for (k = 0; k < PITCH_LAG_SPAN2-PITCH_BW+m; k++) {
|
||||
ratio = ((double) (ind1 + 12)) / ((double) (ind2 + 12));
|
||||
adj = ratio * (2.0 - ratio); /* adjustment factor; inverse parabola as a function of ratio */
|
||||
corr = adj * (corrvec1[ind1] + corrvec2[ind2]);
|
||||
CorrSurfPtr1[k] = corr;
|
||||
if (corr > corr_max) {
|
||||
corr_max = corr; /* update maximum */
|
||||
max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]);
|
||||
}
|
||||
corr = adj * (corrvec1[ind2++] + corrvec2[ind1++]);
|
||||
CorrSurfPtr2[k] = corr;
|
||||
if (corr > corr_max) {
|
||||
corr_max = corr; /* update maximum */
|
||||
max_ind = (int)(&CorrSurfPtr2[k] - &CorrSurf[0][0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* threshold value to qualify as a peak */
|
||||
corr_max *= 0.6;
|
||||
|
||||
peaks_ind = 0;
|
||||
/* find peaks */
|
||||
for (m = 1; m < PITCH_BW+1; m++) {
|
||||
if (peaks_ind == PITCH_MAX_NUM_PEAKS) break;
|
||||
CorrSurfPtr1 = &CorrSurf[m][2];
|
||||
for (k = 2; k < PITCH_LAG_SPAN2-PITCH_BW-2+m; k++) {
|
||||
corr = CorrSurfPtr1[k];
|
||||
if (corr > corr_max) {
|
||||
if ( (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+5)]) && (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+4)]) ) {
|
||||
if ( (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+4)]) && (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+5)]) ) {
|
||||
/* found a peak; store index into matrix */
|
||||
peaks[peaks_ind++] = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]);
|
||||
if (peaks_ind == PITCH_MAX_NUM_PEAKS) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (m = PITCH_BW+1; m < 2*PITCH_BW; m++) {
|
||||
if (peaks_ind == PITCH_MAX_NUM_PEAKS) break;
|
||||
CorrSurfPtr1 = &CorrSurf[m][2];
|
||||
for (k = 2+m-PITCH_BW; k < PITCH_LAG_SPAN2-2; k++) {
|
||||
corr = CorrSurfPtr1[k];
|
||||
if (corr > corr_max) {
|
||||
if ( (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+5)]) && (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+4)]) ) {
|
||||
if ( (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+4)]) && (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+5)]) ) {
|
||||
/* found a peak; store index into matrix */
|
||||
peaks[peaks_ind++] = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]);
|
||||
if (peaks_ind == PITCH_MAX_NUM_PEAKS) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (peaks_ind > 0) {
|
||||
/* examine each peak */
|
||||
CorrSurfPtr1 = &CorrSurf[0][0];
|
||||
for (k = 0; k < peaks_ind; k++) {
|
||||
peak = peaks[k];
|
||||
|
||||
/* compute four interpolated values around current peak */
|
||||
IntrepolFilter(&CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)], &intrp_a);
|
||||
IntrepolFilter(&CorrSurfPtr1[peak - 1 ], &intrp_b);
|
||||
IntrepolFilter(&CorrSurfPtr1[peak ], &intrp_c);
|
||||
IntrepolFilter(&CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)], &intrp_d);
|
||||
|
||||
/* determine maximum of the interpolated values */
|
||||
corr = CorrSurfPtr1[peak];
|
||||
corr_max = intrp_a;
|
||||
if (intrp_b > corr_max) corr_max = intrp_b;
|
||||
if (intrp_c > corr_max) corr_max = intrp_c;
|
||||
if (intrp_d > corr_max) corr_max = intrp_d;
|
||||
|
||||
/* determine where the peak sits and fill a 3x3 matrix around it */
|
||||
row = peak / (PITCH_LAG_SPAN2+4);
|
||||
lags1[k] = (double) ((peak - row * (PITCH_LAG_SPAN2+4)) + PITCH_MIN_LAG/2 - 4);
|
||||
lags2[k] = (double) (lags1[k] + PITCH_BW - row);
|
||||
if ( corr > corr_max ) {
|
||||
T[0][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)];
|
||||
T[2][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)];
|
||||
T[1][1] = corr;
|
||||
T[0][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)];
|
||||
T[2][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)];
|
||||
T[1][0] = intrp_a;
|
||||
T[0][1] = intrp_b;
|
||||
T[2][1] = intrp_c;
|
||||
T[1][2] = intrp_d;
|
||||
} else {
|
||||
if (intrp_a == corr_max) {
|
||||
lags1[k] -= 0.5;
|
||||
lags2[k] += 0.5;
|
||||
IntrepolFilter(&CorrSurfPtr1[peak - 2*(PITCH_LAG_SPAN2+5)], &T[0][0]);
|
||||
IntrepolFilter(&CorrSurfPtr1[peak - (2*PITCH_LAG_SPAN2+9)], &T[2][0]);
|
||||
T[1][1] = intrp_a;
|
||||
T[0][2] = intrp_b;
|
||||
T[2][2] = intrp_c;
|
||||
T[1][0] = CorrSurfPtr1[peak - (2*PITCH_LAG_SPAN2+9)];
|
||||
T[0][1] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)];
|
||||
T[2][1] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)];
|
||||
T[1][2] = corr;
|
||||
} else if (intrp_b == corr_max) {
|
||||
lags1[k] -= 0.5;
|
||||
lags2[k] -= 0.5;
|
||||
IntrepolFilter(&CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+6)], &T[0][0]);
|
||||
T[2][0] = intrp_a;
|
||||
T[1][1] = intrp_b;
|
||||
IntrepolFilter(&CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+3)], &T[0][2]);
|
||||
T[2][2] = intrp_d;
|
||||
T[1][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)];
|
||||
T[0][1] = CorrSurfPtr1[peak - 1];
|
||||
T[2][1] = corr;
|
||||
T[1][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)];
|
||||
} else if (intrp_c == corr_max) {
|
||||
lags1[k] += 0.5;
|
||||
lags2[k] += 0.5;
|
||||
T[0][0] = intrp_a;
|
||||
IntrepolFilter(&CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)], &T[2][0]);
|
||||
T[1][1] = intrp_c;
|
||||
T[0][2] = intrp_d;
|
||||
IntrepolFilter(&CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)], &T[2][2]);
|
||||
T[1][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)];
|
||||
T[0][1] = corr;
|
||||
T[2][1] = CorrSurfPtr1[peak + 1];
|
||||
T[1][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)];
|
||||
} else {
|
||||
lags1[k] += 0.5;
|
||||
lags2[k] -= 0.5;
|
||||
T[0][0] = intrp_b;
|
||||
T[2][0] = intrp_c;
|
||||
T[1][1] = intrp_d;
|
||||
IntrepolFilter(&CorrSurfPtr1[peak + 2*(PITCH_LAG_SPAN2+4)], &T[0][2]);
|
||||
IntrepolFilter(&CorrSurfPtr1[peak + (2*PITCH_LAG_SPAN2+9)], &T[2][2]);
|
||||
T[1][0] = corr;
|
||||
T[0][1] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)];
|
||||
T[2][1] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)];
|
||||
T[1][2] = CorrSurfPtr1[peak + (2*PITCH_LAG_SPAN2+9)];
|
||||
}
|
||||
}
|
||||
|
||||
/* 2D parabolic interpolation gives more accurate lags and peak value */
|
||||
Intrpol2D(T, &lags1[k], &lags2[k], &peak_vals[k]);
|
||||
}
|
||||
|
||||
/* determine the highest peak, after applying a bias towards short lags */
|
||||
corr_max = 0.0;
|
||||
for (k = 0; k < peaks_ind; k++) {
|
||||
corr = peak_vals[k] * pow(PITCH_PEAK_DECAY, log(lags1[k] + lags2[k]));
|
||||
if (corr > corr_max) {
|
||||
corr_max = corr;
|
||||
peak = k;
|
||||
}
|
||||
}
|
||||
|
||||
lags1[peak] *= 2.0;
|
||||
lags2[peak] *= 2.0;
|
||||
|
||||
if (lags1[peak] < (double) PITCH_MIN_LAG) lags1[peak] = (double) PITCH_MIN_LAG;
|
||||
if (lags2[peak] < (double) PITCH_MIN_LAG) lags2[peak] = (double) PITCH_MIN_LAG;
|
||||
if (lags1[peak] > (double) PITCH_MAX_LAG) lags1[peak] = (double) PITCH_MAX_LAG;
|
||||
if (lags2[peak] > (double) PITCH_MAX_LAG) lags2[peak] = (double) PITCH_MAX_LAG;
|
||||
|
||||
/* store lags of highest peak in output array */
|
||||
lags[0] = lags1[peak];
|
||||
lags[1] = lags1[peak];
|
||||
lags[2] = lags2[peak];
|
||||
lags[3] = lags2[peak];
|
||||
}
|
||||
else
|
||||
{
|
||||
row = max_ind / (PITCH_LAG_SPAN2+4);
|
||||
lags1[0] = (double) ((max_ind - row * (PITCH_LAG_SPAN2+4)) + PITCH_MIN_LAG/2 - 4);
|
||||
lags2[0] = (double) (lags1[0] + PITCH_BW - row);
|
||||
|
||||
if (lags1[0] < (double) PITCH_MIN_LAG) lags1[0] = (double) PITCH_MIN_LAG;
|
||||
if (lags2[0] < (double) PITCH_MIN_LAG) lags2[0] = (double) PITCH_MIN_LAG;
|
||||
if (lags1[0] > (double) PITCH_MAX_LAG) lags1[0] = (double) PITCH_MAX_LAG;
|
||||
if (lags2[0] > (double) PITCH_MAX_LAG) lags2[0] = (double) PITCH_MAX_LAG;
|
||||
|
||||
/* store lags of highest peak in output array */
|
||||
lags[0] = lags1[0];
|
||||
lags[1] = lags1[0];
|
||||
lags[2] = lags2[0];
|
||||
lags[3] = lags2[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* create weighting matrix by orthogonalizing a basis of polynomials of increasing order
|
||||
* t = (0:4)';
|
||||
* A = [t.^0, t.^1, t.^2, t.^3, t.^4];
|
||||
* [Q, dummy] = qr(A);
|
||||
* P.Weight = Q * diag([0, .1, .5, 1, 1]) * Q'; */
|
||||
static const double kWeight[5][5] = {
|
||||
{ 0.29714285714286, -0.30857142857143, -0.05714285714286, 0.05142857142857, 0.01714285714286},
|
||||
{-0.30857142857143, 0.67428571428571, -0.27142857142857, -0.14571428571429, 0.05142857142857},
|
||||
{-0.05714285714286, -0.27142857142857, 0.65714285714286, -0.27142857142857, -0.05714285714286},
|
||||
{ 0.05142857142857, -0.14571428571429, -0.27142857142857, 0.67428571428571, -0.30857142857143},
|
||||
{ 0.01714285714286, 0.05142857142857, -0.05714285714286, -0.30857142857143, 0.29714285714286}
|
||||
};
|
||||
|
||||
|
||||
void WebRtcIsac_PitchAnalysis(const double *in, /* PITCH_FRAME_LEN samples */
|
||||
double *out, /* PITCH_FRAME_LEN+QLOOKAHEAD samples */
|
||||
PitchAnalysisStruct *State,
|
||||
double *lags,
|
||||
double *gains)
|
||||
{
|
||||
double HPin[PITCH_FRAME_LEN];
|
||||
double Weighted[PITCH_FRAME_LEN];
|
||||
double Whitened[PITCH_FRAME_LEN + QLOOKAHEAD];
|
||||
double inbuf[PITCH_FRAME_LEN + QLOOKAHEAD];
|
||||
double out_G[PITCH_FRAME_LEN + QLOOKAHEAD]; // could be removed by using out instead
|
||||
double out_dG[4][PITCH_FRAME_LEN + QLOOKAHEAD];
|
||||
double old_lag, old_gain;
|
||||
double nrg_wht, tmp;
|
||||
double Wnrg, Wfluct, Wgain;
|
||||
double H[4][4];
|
||||
double grad[4];
|
||||
double dG[4];
|
||||
int k, m, n, iter;
|
||||
|
||||
/* high pass filtering using second order pole-zero filter */
|
||||
WebRtcIsac_Highpass(in, HPin, State->hp_state, PITCH_FRAME_LEN);
|
||||
|
||||
/* copy from state into buffer */
|
||||
memcpy(Whitened, State->whitened_buf, sizeof(double) * QLOOKAHEAD);
|
||||
|
||||
/* compute weighted and whitened signals */
|
||||
WebRtcIsac_WeightingFilter(HPin, &Weighted[0], &Whitened[QLOOKAHEAD], &(State->Wghtstr));
|
||||
|
||||
/* copy from buffer into state */
|
||||
memcpy(State->whitened_buf, Whitened+PITCH_FRAME_LEN, sizeof(double) * QLOOKAHEAD);
|
||||
|
||||
old_lag = State->PFstr_wght.oldlagp[0];
|
||||
old_gain = State->PFstr_wght.oldgainp[0];
|
||||
|
||||
/* inital pitch estimate */
|
||||
WebRtcIsac_InitializePitch(Weighted, old_lag, old_gain, State, lags);
|
||||
|
||||
|
||||
/* Iterative optimization of lags - to be done */
|
||||
|
||||
/* compute energy of whitened signal */
|
||||
nrg_wht = 0.0;
|
||||
for (k = 0; k < PITCH_FRAME_LEN + QLOOKAHEAD; k++)
|
||||
nrg_wht += Whitened[k] * Whitened[k];
|
||||
|
||||
|
||||
/* Iterative optimization of gains */
|
||||
|
||||
/* set weights for energy, gain fluctiation, and spectral gain penalty functions */
|
||||
Wnrg = 1.0 / nrg_wht;
|
||||
Wgain = 0.005;
|
||||
Wfluct = 3.0;
|
||||
|
||||
/* set initial gains */
|
||||
for (k = 0; k < 4; k++)
|
||||
gains[k] = PITCH_MAX_GAIN_06;
|
||||
|
||||
/* two iterations should be enough */
|
||||
for (iter = 0; iter < 2; iter++) {
|
||||
/* compute Jacobian of pre-filter output towards gains */
|
||||
WebRtcIsac_PitchfilterPre_gains(Whitened, out_G, out_dG, &(State->PFstr_wght), lags, gains);
|
||||
|
||||
/* gradient and approximate Hessian (lower triangle) for minimizing the filter's output power */
|
||||
for (k = 0; k < 4; k++) {
|
||||
tmp = 0.0;
|
||||
for (n = 0; n < PITCH_FRAME_LEN + QLOOKAHEAD; n++)
|
||||
tmp += out_G[n] * out_dG[k][n];
|
||||
grad[k] = tmp * Wnrg;
|
||||
}
|
||||
for (k = 0; k < 4; k++) {
|
||||
for (m = 0; m <= k; m++) {
|
||||
tmp = 0.0;
|
||||
for (n = 0; n < PITCH_FRAME_LEN + QLOOKAHEAD; n++)
|
||||
tmp += out_dG[m][n] * out_dG[k][n];
|
||||
H[k][m] = tmp * Wnrg;
|
||||
}
|
||||
}
|
||||
|
||||
/* add gradient and Hessian (lower triangle) for dampening fast gain changes */
|
||||
for (k = 0; k < 4; k++) {
|
||||
tmp = kWeight[k+1][0] * old_gain;
|
||||
for (m = 0; m < 4; m++)
|
||||
tmp += kWeight[k+1][m+1] * gains[m];
|
||||
grad[k] += tmp * Wfluct;
|
||||
}
|
||||
for (k = 0; k < 4; k++) {
|
||||
for (m = 0; m <= k; m++) {
|
||||
H[k][m] += kWeight[k+1][m+1] * Wfluct;
|
||||
}
|
||||
}
|
||||
|
||||
/* add gradient and Hessian for dampening gain */
|
||||
for (k = 0; k < 3; k++) {
|
||||
tmp = 1.0 / (1 - gains[k]);
|
||||
grad[k] += tmp * tmp * Wgain;
|
||||
H[k][k] += 2.0 * tmp * (tmp * tmp * Wgain);
|
||||
}
|
||||
tmp = 1.0 / (1 - gains[3]);
|
||||
grad[3] += 1.33 * (tmp * tmp * Wgain);
|
||||
H[3][3] += 2.66 * tmp * (tmp * tmp * Wgain);
|
||||
|
||||
|
||||
/* compute Cholesky factorization of Hessian
|
||||
* by overwritting the upper triangle; scale factors on diagonal
|
||||
* (for non pc-platforms store the inverse of the diagonals seperately to minimize divisions) */
|
||||
H[0][1] = H[1][0] / H[0][0];
|
||||
H[0][2] = H[2][0] / H[0][0];
|
||||
H[0][3] = H[3][0] / H[0][0];
|
||||
H[1][1] -= H[0][0] * H[0][1] * H[0][1];
|
||||
H[1][2] = (H[2][1] - H[0][1] * H[2][0]) / H[1][1];
|
||||
H[1][3] = (H[3][1] - H[0][1] * H[3][0]) / H[1][1];
|
||||
H[2][2] -= H[0][0] * H[0][2] * H[0][2] + H[1][1] * H[1][2] * H[1][2];
|
||||
H[2][3] = (H[3][2] - H[0][2] * H[3][0] - H[1][2] * H[1][1] * H[1][3]) / H[2][2];
|
||||
H[3][3] -= H[0][0] * H[0][3] * H[0][3] + H[1][1] * H[1][3] * H[1][3] + H[2][2] * H[2][3] * H[2][3];
|
||||
|
||||
/* Compute update as delta_gains = -inv(H) * grad */
|
||||
/* copy and negate */
|
||||
for (k = 0; k < 4; k++)
|
||||
dG[k] = -grad[k];
|
||||
/* back substitution */
|
||||
dG[1] -= dG[0] * H[0][1];
|
||||
dG[2] -= dG[0] * H[0][2] + dG[1] * H[1][2];
|
||||
dG[3] -= dG[0] * H[0][3] + dG[1] * H[1][3] + dG[2] * H[2][3];
|
||||
/* scale */
|
||||
for (k = 0; k < 4; k++)
|
||||
dG[k] /= H[k][k];
|
||||
/* back substitution */
|
||||
dG[2] -= dG[3] * H[2][3];
|
||||
dG[1] -= dG[3] * H[1][3] + dG[2] * H[1][2];
|
||||
dG[0] -= dG[3] * H[0][3] + dG[2] * H[0][2] + dG[1] * H[0][1];
|
||||
|
||||
/* update gains and check range */
|
||||
for (k = 0; k < 4; k++) {
|
||||
gains[k] += dG[k];
|
||||
if (gains[k] > PITCH_MAX_GAIN)
|
||||
gains[k] = PITCH_MAX_GAIN;
|
||||
else if (gains[k] < 0.0)
|
||||
gains[k] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
/* update state for next frame */
|
||||
WebRtcIsac_PitchfilterPre(Whitened, out, &(State->PFstr_wght), lags, gains);
|
||||
|
||||
/* concatenate previous input's end and current input */
|
||||
memcpy(inbuf, State->inbuf, sizeof(double) * QLOOKAHEAD);
|
||||
memcpy(inbuf+QLOOKAHEAD, in, sizeof(double) * PITCH_FRAME_LEN);
|
||||
|
||||
/* lookahead pitch filtering for masking analysis */
|
||||
WebRtcIsac_PitchfilterPre_la(inbuf, out, &(State->PFstr), lags, gains);
|
||||
|
||||
/* store last part of input */
|
||||
for (k = 0; k < QLOOKAHEAD; k++)
|
||||
State->inbuf[k] = inbuf[k + PITCH_FRAME_LEN];
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* pitch_estimator.h
|
||||
*
|
||||
* Pitch functions
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_
|
||||
|
||||
#include "structs.h"
|
||||
|
||||
|
||||
|
||||
void WebRtcIsac_PitchAnalysis(const double *in, /* PITCH_FRAME_LEN samples */
|
||||
double *out, /* PITCH_FRAME_LEN+QLOOKAHEAD samples */
|
||||
PitchAnalysisStruct *State,
|
||||
double *lags,
|
||||
double *gains);
|
||||
|
||||
void WebRtcIsac_InitializePitch(const double *in,
|
||||
const double old_lag,
|
||||
const double old_gain,
|
||||
PitchAnalysisStruct *State,
|
||||
double *lags);
|
||||
|
||||
void WebRtcIsac_PitchfilterPre(double *indat,
|
||||
double *outdat,
|
||||
PitchFiltstr *pfp,
|
||||
double *lags,
|
||||
double *gains);
|
||||
|
||||
void WebRtcIsac_PitchfilterPost(double *indat,
|
||||
double *outdat,
|
||||
PitchFiltstr *pfp,
|
||||
double *lags,
|
||||
double *gains);
|
||||
|
||||
void WebRtcIsac_PitchfilterPre_la(double *indat,
|
||||
double *outdat,
|
||||
PitchFiltstr *pfp,
|
||||
double *lags,
|
||||
double *gains);
|
||||
|
||||
void WebRtcIsac_PitchfilterPre_gains(double *indat,
|
||||
double *outdat,
|
||||
double out_dG[][PITCH_FRAME_LEN + QLOOKAHEAD],
|
||||
PitchFiltstr *pfp,
|
||||
double *lags,
|
||||
double *gains);
|
||||
|
||||
void WebRtcIsac_WeightingFilter(const double *in, double *weiout, double *whiout, WeightFiltstr *wfdata);
|
||||
|
||||
void WebRtcIsac_Highpass(const double *in,
|
||||
double *out,
|
||||
double *state,
|
||||
size_t N);
|
||||
|
||||
void WebRtcIsac_DecimateAllpass(const double *in,
|
||||
double *state_in, /* array of size:
|
||||
* 2*ALLPASSSECTIONS+1 */
|
||||
size_t N, /* number of input samples */
|
||||
double *out); /* array of size N/2 */
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_ */
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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 "pitch_gain_tables.h"
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
/* header file for coding tables for the pitch filter side-info in the entropy coder */
|
||||
/********************* Pitch Filter Gain Coefficient Tables ************************/
|
||||
/* cdf for quantized pitch filter gains */
|
||||
const uint16_t WebRtcIsac_kQPitchGainCdf[255] = {
|
||||
0, 2, 4, 6, 64, 901, 903, 905, 16954, 16956,
|
||||
16961, 17360, 17362, 17364, 17366, 17368, 17370, 17372, 17374, 17411,
|
||||
17514, 17516, 17583, 18790, 18796, 18802, 20760, 20777, 20782, 21722,
|
||||
21724, 21728, 21738, 21740, 21742, 21744, 21746, 21748, 22224, 22227,
|
||||
22230, 23214, 23229, 23239, 25086, 25108, 25120, 26088, 26094, 26098,
|
||||
26175, 26177, 26179, 26181, 26183, 26185, 26484, 26507, 26522, 27705,
|
||||
27731, 27750, 29767, 29799, 29817, 30866, 30883, 30885, 31025, 31029,
|
||||
31031, 31033, 31035, 31037, 31114, 31126, 31134, 32687, 32722, 32767,
|
||||
35718, 35742, 35757, 36943, 36952, 36954, 37115, 37128, 37130, 37132,
|
||||
37134, 37136, 37143, 37145, 37152, 38843, 38863, 38897, 47458, 47467,
|
||||
47474, 49040, 49061, 49063, 49145, 49157, 49159, 49161, 49163, 49165,
|
||||
49167, 49169, 49171, 49757, 49770, 49782, 61333, 61344, 61346, 62860,
|
||||
62883, 62885, 62887, 62889, 62891, 62893, 62895, 62897, 62899, 62901,
|
||||
62903, 62905, 62907, 62909, 65496, 65498, 65500, 65521, 65523, 65525,
|
||||
65527, 65529, 65531, 65533, 65535, 65535, 65535, 65535, 65535, 65535,
|
||||
65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
|
||||
65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
|
||||
65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
|
||||
65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
|
||||
65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
|
||||
65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
|
||||
65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
|
||||
65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
|
||||
65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
|
||||
65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
|
||||
65535, 65535, 65535, 65535, 65535};
|
||||
|
||||
/* index limits and ranges */
|
||||
const int16_t WebRtcIsac_kIndexLowerLimitGain[3] = {
|
||||
-7, -2, -1};
|
||||
|
||||
const int16_t WebRtcIsac_kIndexUpperLimitGain[3] = {
|
||||
0, 3, 1};
|
||||
|
||||
const uint16_t WebRtcIsac_kIndexMultsGain[2] = {
|
||||
18, 3};
|
||||
|
||||
/* size of cdf table */
|
||||
const uint16_t WebRtcIsac_kQCdfTableSizeGain[1] = {
|
||||
256};
|
||||
|
||||
///////////////////////////FIXED POINT
|
||||
/* mean values of pitch filter gains in FIXED point */
|
||||
const int16_t WebRtcIsac_kQMeanGain1Q12[144] = {
|
||||
843, 1092, 1336, 1222, 1405, 1656, 1500, 1815, 1843, 1838, 1839, 1843, 1843, 1843, 1843, 1843,
|
||||
1843, 1843, 814, 846, 1092, 1013, 1174, 1383, 1391, 1511, 1584, 1734, 1753, 1843, 1843, 1843,
|
||||
1843, 1843, 1843, 1843, 524, 689, 777, 845, 947, 1069, 1090, 1263, 1380, 1447, 1559, 1676,
|
||||
1645, 1749, 1843, 1843, 1843, 1843, 81, 477, 563, 611, 706, 806, 849, 1012, 1192, 1128,
|
||||
1330, 1489, 1425, 1576, 1826, 1741, 1843, 1843, 0, 290, 305, 356, 488, 575, 602, 741,
|
||||
890, 835, 1079, 1196, 1182, 1376, 1519, 1506, 1680, 1843, 0, 47, 97, 69, 289, 381,
|
||||
385, 474, 617, 664, 803, 1079, 935, 1160, 1269, 1265, 1506, 1741, 0, 0, 0, 0,
|
||||
112, 120, 190, 283, 442, 343, 526, 809, 684, 935, 1134, 1020, 1265, 1506, 0, 0,
|
||||
0, 0, 0, 0, 0, 111, 256, 87, 373, 597, 430, 684, 935, 770, 1020, 1265};
|
||||
|
||||
const int16_t WebRtcIsac_kQMeanGain2Q12[144] = {
|
||||
1760, 1525, 1285, 1747, 1671, 1393, 1843, 1826, 1555, 1843, 1784, 1606, 1843, 1843, 1711, 1843,
|
||||
1843, 1814, 1389, 1275, 1040, 1564, 1414, 1252, 1610, 1495, 1343, 1753, 1592, 1405, 1804, 1720,
|
||||
1475, 1843, 1814, 1581, 1208, 1061, 856, 1349, 1148, 994, 1390, 1253, 1111, 1495, 1343, 1178,
|
||||
1770, 1465, 1234, 1814, 1581, 1342, 1040, 793, 713, 1053, 895, 737, 1128, 1003, 861, 1277,
|
||||
1094, 981, 1475, 1192, 1019, 1581, 1342, 1098, 855, 570, 483, 833, 648, 540, 948, 744,
|
||||
572, 1009, 844, 636, 1234, 934, 685, 1342, 1217, 984, 537, 318, 124, 603, 423, 350,
|
||||
687, 479, 322, 791, 581, 430, 987, 671, 488, 1098, 849, 597, 283, 27, 0, 397,
|
||||
222, 38, 513, 271, 124, 624, 325, 157, 737, 484, 233, 849, 597, 343, 27, 0,
|
||||
0, 141, 0, 0, 256, 69, 0, 370, 87, 0, 484, 229, 0, 597, 343, 87};
|
||||
|
||||
const int16_t WebRtcIsac_kQMeanGain3Q12[144] = {
|
||||
1843, 1843, 1711, 1843, 1818, 1606, 1843, 1827, 1511, 1814, 1639, 1393, 1760, 1525, 1285, 1656,
|
||||
1419, 1176, 1835, 1718, 1475, 1841, 1650, 1387, 1648, 1498, 1287, 1600, 1411, 1176, 1522, 1299,
|
||||
1040, 1419, 1176, 928, 1773, 1461, 1128, 1532, 1355, 1202, 1429, 1260, 1115, 1398, 1151, 1025,
|
||||
1172, 1080, 790, 1176, 928, 677, 1475, 1147, 1019, 1276, 1096, 922, 1214, 1010, 901, 1057,
|
||||
893, 800, 1040, 796, 734, 928, 677, 424, 1137, 897, 753, 1120, 830, 710, 875, 751,
|
||||
601, 795, 642, 583, 790, 544, 475, 677, 474, 140, 987, 750, 482, 697, 573, 450,
|
||||
691, 487, 303, 661, 394, 332, 537, 303, 220, 424, 168, 0, 737, 484, 229, 624,
|
||||
348, 153, 441, 261, 136, 397, 166, 51, 283, 27, 0, 168, 0, 0, 484, 229,
|
||||
0, 370, 57, 0, 256, 43, 0, 141, 0, 0, 27, 0, 0, 0, 0, 0};
|
||||
|
||||
|
||||
const int16_t WebRtcIsac_kQMeanGain4Q12[144] = {
|
||||
1843, 1843, 1843, 1843, 1841, 1843, 1500, 1821, 1843, 1222, 1434, 1656, 843, 1092, 1336, 504,
|
||||
757, 1007, 1843, 1843, 1843, 1838, 1791, 1843, 1265, 1505, 1599, 965, 1219, 1425, 730, 821,
|
||||
1092, 249, 504, 757, 1783, 1819, 1843, 1351, 1567, 1727, 1096, 1268, 1409, 805, 961, 1131,
|
||||
444, 670, 843, 0, 249, 504, 1425, 1655, 1743, 1096, 1324, 1448, 822, 1019, 1199, 490,
|
||||
704, 867, 81, 450, 555, 0, 0, 249, 1247, 1428, 1530, 881, 1073, 1283, 610, 759,
|
||||
939, 278, 464, 645, 0, 200, 270, 0, 0, 0, 935, 1163, 1410, 528, 790, 1068,
|
||||
377, 499, 717, 173, 240, 274, 0, 43, 62, 0, 0, 0, 684, 935, 1182, 343,
|
||||
551, 735, 161, 262, 423, 0, 55, 27, 0, 0, 0, 0, 0, 0, 430, 684,
|
||||
935, 87, 377, 597, 0, 46, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* pitch_gain_tables.h
|
||||
*
|
||||
* This file contains tables for the pitch filter side-info in the entropy coder.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
/* header file for coding tables for the pitch filter side-info in the entropy coder */
|
||||
/********************* Pitch Filter Gain Coefficient Tables ************************/
|
||||
/* cdf for quantized pitch filter gains */
|
||||
extern const uint16_t WebRtcIsac_kQPitchGainCdf[255];
|
||||
|
||||
/* index limits and ranges */
|
||||
extern const int16_t WebRtcIsac_kIndexLowerLimitGain[3];
|
||||
|
||||
extern const int16_t WebRtcIsac_kIndexUpperLimitGain[3];
|
||||
extern const uint16_t WebRtcIsac_kIndexMultsGain[2];
|
||||
|
||||
/* mean values of pitch filter gains */
|
||||
//(Y)
|
||||
extern const int16_t WebRtcIsac_kQMeanGain1Q12[144];
|
||||
extern const int16_t WebRtcIsac_kQMeanGain2Q12[144];
|
||||
extern const int16_t WebRtcIsac_kQMeanGain3Q12[144];
|
||||
extern const int16_t WebRtcIsac_kQMeanGain4Q12[144];
|
||||
//(Y)
|
||||
|
||||
/* size of cdf table */
|
||||
extern const uint16_t WebRtcIsac_kQCdfTableSizeGain[1];
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_ */
|
||||
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* 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 "pitch_lag_tables.h"
|
||||
#include "settings.h"
|
||||
|
||||
/* header file for coding tables for the pitch filter side-info in the entropy coder */
|
||||
/********************* Pitch Filter Gain Coefficient Tables ************************/
|
||||
|
||||
/* tables for use with small pitch gain */
|
||||
|
||||
/* cdf for quantized pitch filter lags */
|
||||
const uint16_t WebRtcIsac_kQPitchLagCdf1Lo[127] = {
|
||||
0, 134, 336, 549, 778, 998, 1264, 1512, 1777, 2070,
|
||||
2423, 2794, 3051, 3361, 3708, 3979, 4315, 4610, 4933, 5269,
|
||||
5575, 5896, 6155, 6480, 6816, 7129, 7477, 7764, 8061, 8358,
|
||||
8718, 9020, 9390, 9783, 10177, 10543, 10885, 11342, 11795, 12213,
|
||||
12680, 13096, 13524, 13919, 14436, 14903, 15349, 15795, 16267, 16734,
|
||||
17266, 17697, 18130, 18632, 19080, 19447, 19884, 20315, 20735, 21288,
|
||||
21764, 22264, 22723, 23193, 23680, 24111, 24557, 25022, 25537, 26082,
|
||||
26543, 27090, 27620, 28139, 28652, 29149, 29634, 30175, 30692, 31273,
|
||||
31866, 32506, 33059, 33650, 34296, 34955, 35629, 36295, 36967, 37726,
|
||||
38559, 39458, 40364, 41293, 42256, 43215, 44231, 45253, 46274, 47359,
|
||||
48482, 49678, 50810, 51853, 53016, 54148, 55235, 56263, 57282, 58363,
|
||||
59288, 60179, 61076, 61806, 62474, 63129, 63656, 64160, 64533, 64856,
|
||||
65152, 65535, 65535, 65535, 65535, 65535, 65535};
|
||||
|
||||
const uint16_t WebRtcIsac_kQPitchLagCdf2Lo[20] = {
|
||||
0, 429, 3558, 5861, 8558, 11639, 15210, 19502, 24773, 31983,
|
||||
42602, 48567, 52601, 55676, 58160, 60172, 61889, 63235, 65383, 65535};
|
||||
|
||||
const uint16_t WebRtcIsac_kQPitchLagCdf3Lo[2] = {
|
||||
0, 65535};
|
||||
|
||||
const uint16_t WebRtcIsac_kQPitchLagCdf4Lo[10] = {
|
||||
0, 2966, 6368, 11182, 19431, 37793, 48532, 55353, 60626, 65535};
|
||||
|
||||
const uint16_t *WebRtcIsac_kQPitchLagCdfPtrLo[4] = {WebRtcIsac_kQPitchLagCdf1Lo, WebRtcIsac_kQPitchLagCdf2Lo, WebRtcIsac_kQPitchLagCdf3Lo, WebRtcIsac_kQPitchLagCdf4Lo};
|
||||
|
||||
/* size of first cdf table */
|
||||
const uint16_t WebRtcIsac_kQPitchLagCdfSizeLo[1] = {128};
|
||||
|
||||
/* index limits and ranges */
|
||||
const int16_t WebRtcIsac_kQIndexLowerLimitLagLo[4] = {
|
||||
-140, -9, 0, -4};
|
||||
|
||||
const int16_t WebRtcIsac_kQIndexUpperLimitLagLo[4] = {
|
||||
-20, 9, 0, 4};
|
||||
|
||||
/* initial index for arithmetic decoder */
|
||||
const uint16_t WebRtcIsac_kQInitIndexLagLo[3] = {
|
||||
10, 1, 5};
|
||||
|
||||
/* mean values of pitch filter lags */
|
||||
const double WebRtcIsac_kQMeanLag2Lo[19] = {
|
||||
-17.21385070, -15.82678944, -14.07123081, -12.03003877, -10.01311864, -8.00794627, -5.91162987, -3.89231876, -1.90220980, -0.01879275,
|
||||
1.89144232, 3.88123171, 5.92146992, 7.96435361, 9.98923648, 11.98266347, 13.96101002, 15.74855713, 17.10976611};
|
||||
|
||||
const double WebRtcIsac_kQMeanLag3Lo[1] = {
|
||||
0.00000000};
|
||||
|
||||
const double WebRtcIsac_kQMeanLag4Lo[9] = {
|
||||
-7.76246496, -5.92083980, -3.94095226, -1.89502305, 0.03724681, 1.93054221, 3.96443467, 5.91726366, 7.78434291};
|
||||
|
||||
const double WebRtcIsac_kQPitchLagStepsizeLo = 2.000000;
|
||||
|
||||
|
||||
/* tables for use with medium pitch gain */
|
||||
|
||||
/* cdf for quantized pitch filter lags */
|
||||
const uint16_t WebRtcIsac_kQPitchLagCdf1Mid[255] = {
|
||||
0, 28, 61, 88, 121, 149, 233, 331, 475, 559,
|
||||
624, 661, 689, 712, 745, 791, 815, 843, 866, 922,
|
||||
959, 1024, 1061, 1117, 1178, 1238, 1280, 1350, 1453, 1513,
|
||||
1564, 1625, 1671, 1741, 1788, 1904, 2072, 2421, 2626, 2770,
|
||||
2840, 2900, 2942, 3012, 3068, 3115, 3147, 3194, 3254, 3319,
|
||||
3366, 3520, 3678, 3780, 3850, 3911, 3957, 4032, 4106, 4185,
|
||||
4292, 4474, 4683, 4842, 5019, 5191, 5321, 5428, 5540, 5675,
|
||||
5763, 5847, 5959, 6127, 6304, 6564, 6839, 7090, 7263, 7421,
|
||||
7556, 7728, 7872, 7984, 8142, 8361, 8580, 8743, 8938, 9227,
|
||||
9409, 9539, 9674, 9795, 9930, 10060, 10177, 10382, 10614, 10861,
|
||||
11038, 11271, 11415, 11629, 11792, 12044, 12193, 12416, 12574, 12821,
|
||||
13007, 13235, 13445, 13654, 13901, 14134, 14488, 15000, 15703, 16285,
|
||||
16504, 16797, 17086, 17328, 17579, 17807, 17998, 18268, 18538, 18836,
|
||||
19087, 19274, 19474, 19716, 19935, 20270, 20833, 21303, 21532, 21741,
|
||||
21978, 22207, 22523, 22770, 23054, 23613, 23943, 24204, 24399, 24651,
|
||||
24832, 25074, 25270, 25549, 25759, 26015, 26150, 26424, 26713, 27048,
|
||||
27342, 27504, 27681, 27854, 28021, 28207, 28412, 28664, 28859, 29064,
|
||||
29278, 29548, 29748, 30107, 30377, 30656, 30856, 31164, 31452, 31755,
|
||||
32011, 32328, 32626, 32919, 33319, 33789, 34329, 34925, 35396, 35973,
|
||||
36443, 36964, 37551, 38156, 38724, 39357, 40023, 40908, 41587, 42602,
|
||||
43924, 45037, 45810, 46597, 47421, 48291, 49092, 50051, 51448, 52719,
|
||||
53440, 54241, 54944, 55977, 56676, 57299, 57872, 58389, 59059, 59688,
|
||||
60237, 60782, 61094, 61573, 61890, 62290, 62658, 63030, 63217, 63454,
|
||||
63622, 63882, 64003, 64273, 64427, 64529, 64581, 64697, 64758, 64902,
|
||||
65414, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
|
||||
65535, 65535, 65535, 65535, 65535};
|
||||
|
||||
const uint16_t WebRtcIsac_kQPitchLagCdf2Mid[36] = {
|
||||
0, 71, 335, 581, 836, 1039, 1323, 1795, 2258, 2608,
|
||||
3005, 3591, 4243, 5344, 7163, 10583, 16848, 28078, 49448, 57007,
|
||||
60357, 61850, 62837, 63437, 63872, 64188, 64377, 64614, 64774, 64949,
|
||||
65039, 65115, 65223, 65360, 65474, 65535};
|
||||
|
||||
const uint16_t WebRtcIsac_kQPitchLagCdf3Mid[2] = {
|
||||
0, 65535};
|
||||
|
||||
const uint16_t WebRtcIsac_kQPitchLagCdf4Mid[20] = {
|
||||
0, 28, 246, 459, 667, 1045, 1523, 2337, 4337, 11347,
|
||||
44231, 56709, 60781, 62243, 63161, 63969, 64608, 65062, 65502, 65535};
|
||||
|
||||
const uint16_t *WebRtcIsac_kQPitchLagCdfPtrMid[4] = {WebRtcIsac_kQPitchLagCdf1Mid, WebRtcIsac_kQPitchLagCdf2Mid, WebRtcIsac_kQPitchLagCdf3Mid, WebRtcIsac_kQPitchLagCdf4Mid};
|
||||
|
||||
/* size of first cdf table */
|
||||
const uint16_t WebRtcIsac_kQPitchLagCdfSizeMid[1] = {256};
|
||||
|
||||
/* index limits and ranges */
|
||||
const int16_t WebRtcIsac_kQIndexLowerLimitLagMid[4] = {
|
||||
-280, -17, 0, -9};
|
||||
|
||||
const int16_t WebRtcIsac_kQIndexUpperLimitLagMid[4] = {
|
||||
-40, 17, 0, 9};
|
||||
|
||||
/* initial index for arithmetic decoder */
|
||||
const uint16_t WebRtcIsac_kQInitIndexLagMid[3] = {
|
||||
18, 1, 10};
|
||||
|
||||
/* mean values of pitch filter lags */
|
||||
const double WebRtcIsac_kQMeanLag2Mid[35] = {
|
||||
-16.89183900, -15.86949778, -15.05476653, -14.00664348, -13.02793036, -12.07324237, -11.00542532, -10.11250602, -8.90792971, -8.02474753,
|
||||
-7.00426767, -5.94055287, -4.98251338, -3.91053158, -2.98820425, -1.93524245, -0.92978085, -0.01722509, 0.91317387, 1.92973955,
|
||||
2.96908851, 3.93728974, 4.96308471, 5.92244151, 7.08673497, 8.00993708, 9.04656316, 9.98538742, 10.97851694, 11.94772884,
|
||||
13.02426166, 14.00039951, 15.01347042, 15.80758023, 16.94086895};
|
||||
|
||||
const double WebRtcIsac_kQMeanLag3Mid[1] = {
|
||||
0.00000000};
|
||||
|
||||
const double WebRtcIsac_kQMeanLag4Mid[19] = {
|
||||
-8.60409403, -7.89198395, -7.03450280, -5.86260421, -4.93822322, -3.93078706, -2.91302322, -1.91824007, -0.87003282, 0.02822649,
|
||||
0.89951758, 1.87495484, 2.91802604, 3.96874074, 5.06571703, 5.93618227, 7.00520185, 7.88497726, 8.64160364};
|
||||
|
||||
const double WebRtcIsac_kQPitchLagStepsizeMid = 1.000000;
|
||||
|
||||
|
||||
/* tables for use with large pitch gain */
|
||||
|
||||
/* cdf for quantized pitch filter lags */
|
||||
const uint16_t WebRtcIsac_kQPitchLagCdf1Hi[511] = {
|
||||
0, 7, 18, 33, 69, 105, 156, 228, 315, 612,
|
||||
680, 691, 709, 724, 735, 738, 742, 746, 749, 753,
|
||||
756, 760, 764, 774, 782, 785, 789, 796, 800, 803,
|
||||
807, 814, 818, 822, 829, 832, 847, 854, 858, 869,
|
||||
876, 883, 898, 908, 934, 977, 1010, 1050, 1060, 1064,
|
||||
1075, 1078, 1086, 1089, 1093, 1104, 1111, 1122, 1133, 1136,
|
||||
1151, 1162, 1183, 1209, 1252, 1281, 1339, 1364, 1386, 1401,
|
||||
1411, 1415, 1426, 1430, 1433, 1440, 1448, 1455, 1462, 1477,
|
||||
1487, 1495, 1502, 1506, 1509, 1516, 1524, 1531, 1535, 1542,
|
||||
1553, 1556, 1578, 1589, 1611, 1625, 1639, 1643, 1654, 1665,
|
||||
1672, 1687, 1694, 1705, 1708, 1719, 1730, 1744, 1752, 1759,
|
||||
1791, 1795, 1820, 1867, 1886, 1915, 1936, 1943, 1965, 1987,
|
||||
2041, 2099, 2161, 2175, 2200, 2211, 2226, 2233, 2244, 2251,
|
||||
2266, 2280, 2287, 2298, 2309, 2316, 2331, 2342, 2356, 2378,
|
||||
2403, 2418, 2447, 2497, 2544, 2602, 2863, 2895, 2903, 2935,
|
||||
2950, 2971, 3004, 3011, 3018, 3029, 3040, 3062, 3087, 3127,
|
||||
3152, 3170, 3199, 3243, 3293, 3322, 3340, 3377, 3402, 3427,
|
||||
3474, 3518, 3543, 3579, 3601, 3637, 3659, 3706, 3731, 3760,
|
||||
3818, 3847, 3869, 3901, 3920, 3952, 4068, 4169, 4220, 4271,
|
||||
4524, 4571, 4604, 4632, 4672, 4730, 4777, 4806, 4857, 4904,
|
||||
4951, 5002, 5031, 5060, 5107, 5150, 5212, 5266, 5331, 5382,
|
||||
5432, 5490, 5544, 5610, 5700, 5762, 5812, 5874, 5972, 6022,
|
||||
6091, 6163, 6232, 6305, 6402, 6540, 6685, 6880, 7090, 7271,
|
||||
7379, 7452, 7542, 7625, 7687, 7770, 7843, 7911, 7966, 8024,
|
||||
8096, 8190, 8252, 8320, 8411, 8501, 8585, 8639, 8751, 8842,
|
||||
8918, 8986, 9066, 9127, 9203, 9269, 9345, 9406, 9464, 9536,
|
||||
9612, 9667, 9735, 9844, 9931, 10036, 10119, 10199, 10260, 10358,
|
||||
10441, 10514, 10666, 10734, 10872, 10951, 11053, 11125, 11223, 11324,
|
||||
11516, 11664, 11737, 11816, 11892, 12008, 12120, 12200, 12280, 12392,
|
||||
12490, 12576, 12685, 12812, 12917, 13003, 13108, 13210, 13300, 13384,
|
||||
13470, 13579, 13673, 13771, 13879, 13999, 14136, 14201, 14368, 14614,
|
||||
14759, 14867, 14958, 15030, 15121, 15189, 15280, 15385, 15461, 15555,
|
||||
15653, 15768, 15884, 15971, 16069, 16145, 16210, 16279, 16380, 16463,
|
||||
16539, 16615, 16688, 16818, 16919, 17017, 18041, 18338, 18523, 18649,
|
||||
18790, 18917, 19047, 19167, 19315, 19460, 19601, 19731, 19858, 20068,
|
||||
20173, 20318, 20466, 20625, 20741, 20911, 21045, 21201, 21396, 21588,
|
||||
21816, 22022, 22305, 22547, 22786, 23072, 23322, 23600, 23879, 24168,
|
||||
24433, 24769, 25120, 25511, 25895, 26289, 26792, 27219, 27683, 28077,
|
||||
28566, 29094, 29546, 29977, 30491, 30991, 31573, 32105, 32594, 33173,
|
||||
33788, 34497, 35181, 35833, 36488, 37255, 37921, 38645, 39275, 39894,
|
||||
40505, 41167, 41790, 42431, 43096, 43723, 44385, 45134, 45858, 46607,
|
||||
47349, 48091, 48768, 49405, 49955, 50555, 51167, 51985, 52611, 53078,
|
||||
53494, 53965, 54435, 54996, 55601, 56125, 56563, 56838, 57244, 57566,
|
||||
57967, 58297, 58771, 59093, 59419, 59647, 59886, 60143, 60461, 60693,
|
||||
60917, 61170, 61416, 61634, 61891, 62122, 62310, 62455, 62632, 62839,
|
||||
63103, 63436, 63639, 63805, 63906, 64015, 64192, 64355, 64475, 64558,
|
||||
64663, 64742, 64811, 64865, 64916, 64956, 64981, 65025, 65068, 65115,
|
||||
65195, 65314, 65419, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
|
||||
65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
|
||||
65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
|
||||
65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535,
|
||||
65535};
|
||||
|
||||
const uint16_t WebRtcIsac_kQPitchLagCdf2Hi[68] = {
|
||||
0, 7, 11, 22, 37, 52, 56, 59, 81, 85,
|
||||
89, 96, 115, 130, 137, 152, 170, 181, 193, 200,
|
||||
207, 233, 237, 259, 289, 318, 363, 433, 592, 992,
|
||||
1607, 3062, 6149, 12206, 25522, 48368, 58223, 61918, 63640, 64584,
|
||||
64943, 65098, 65206, 65268, 65294, 65335, 65350, 65372, 65387, 65402,
|
||||
65413, 65420, 65428, 65435, 65439, 65450, 65454, 65468, 65472, 65476,
|
||||
65483, 65491, 65498, 65505, 65516, 65520, 65528, 65535};
|
||||
|
||||
const uint16_t WebRtcIsac_kQPitchLagCdf3Hi[2] = {
|
||||
0, 65535};
|
||||
|
||||
const uint16_t WebRtcIsac_kQPitchLagCdf4Hi[35] = {
|
||||
0, 7, 19, 30, 41, 48, 63, 74, 82, 96,
|
||||
122, 152, 215, 330, 701, 2611, 10931, 48106, 61177, 64341,
|
||||
65112, 65238, 65309, 65338, 65364, 65379, 65401, 65427, 65453, 65465,
|
||||
65476, 65490, 65509, 65528, 65535};
|
||||
|
||||
const uint16_t *WebRtcIsac_kQPitchLagCdfPtrHi[4] = {WebRtcIsac_kQPitchLagCdf1Hi, WebRtcIsac_kQPitchLagCdf2Hi, WebRtcIsac_kQPitchLagCdf3Hi, WebRtcIsac_kQPitchLagCdf4Hi};
|
||||
|
||||
/* size of first cdf table */
|
||||
const uint16_t WebRtcIsac_kQPitchLagCdfSizeHi[1] = {512};
|
||||
|
||||
/* index limits and ranges */
|
||||
const int16_t WebRtcIsac_kQindexLowerLimitLagHi[4] = {
|
||||
-552, -34, 0, -16};
|
||||
|
||||
const int16_t WebRtcIsac_kQindexUpperLimitLagHi[4] = {
|
||||
-80, 32, 0, 17};
|
||||
|
||||
/* initial index for arithmetic decoder */
|
||||
const uint16_t WebRtcIsac_kQInitIndexLagHi[3] = {
|
||||
34, 1, 18};
|
||||
|
||||
/* mean values of pitch filter lags */
|
||||
const double WebRtcIsac_kQMeanLag2Hi[67] = {
|
||||
-17.07263295, -16.50000000, -15.83966081, -15.55613708, -14.96948007, -14.50000000, -14.00000000, -13.48377986, -13.00000000, -12.50000000,
|
||||
-11.93199636, -11.44530414, -11.04197641, -10.39910301, -10.15202337, -9.51322461, -8.93357741, -8.46456632, -8.10270672, -7.53751847,
|
||||
-6.98686404, -6.50000000, -6.08463150, -5.46872991, -5.00864717, -4.50163760, -4.01382410, -3.43856708, -2.96898001, -2.46554810,
|
||||
-1.96861004, -1.47106701, -0.97197237, -0.46561654, -0.00531409, 0.45767857, 0.96777907, 1.47507903, 1.97740425, 2.46695420,
|
||||
3.00695774, 3.47167185, 4.02712538, 4.49280007, 5.01087640, 5.48191963, 6.04916550, 6.51511058, 6.97297819, 7.46565499,
|
||||
8.01489405, 8.39912001, 8.91819757, 9.50000000, 10.11654065, 10.50000000, 11.03712583, 11.50000000, 12.00000000, 12.38964346,
|
||||
12.89466127, 13.43657881, 13.96013840, 14.46279912, 15.00000000, 15.39412269, 15.96662441};
|
||||
|
||||
const double WebRtcIsac_kQMeanLag3Hi[1] = {
|
||||
0.00000000};
|
||||
|
||||
const double WebRtcIsac_kQMeanLag4Hi[34] = {
|
||||
-7.98331221, -7.47988769, -7.03626557, -6.52708003, -6.06982173, -5.51856292, -5.05827033, -4.45909878, -3.99125864, -3.45308135,
|
||||
-3.02328139, -2.47297273, -1.94341995, -1.44699056, -0.93612243, -0.43012406, 0.01120357, 0.44054812, 0.93199883, 1.45669587,
|
||||
1.97218322, 2.50187419, 2.98748690, 3.49343202, 4.01660147, 4.50984306, 5.01402683, 5.58936797, 5.91787793, 6.59998900,
|
||||
6.85034315, 7.53503316, 7.87711194, 8.53631648};
|
||||
|
||||
const double WebRtcIsac_kQPitchLagStepsizeHi = 0.500000;
|
||||
|
||||
/* transform matrix */
|
||||
const double WebRtcIsac_kTransform[4][4] = {
|
||||
{-0.50000000, -0.50000000, -0.50000000, -0.50000000},
|
||||
{ 0.67082039, 0.22360680, -0.22360680, -0.67082039},
|
||||
{ 0.50000000, -0.50000000, -0.50000000, 0.50000000},
|
||||
{ 0.22360680, -0.67082039, 0.67082039, -0.22360680}};
|
||||
|
||||
/* transpose transform matrix */
|
||||
const double WebRtcIsac_kTransformTranspose[4][4] = {
|
||||
{-0.50000000, 0.67082039, 0.50000000, 0.22360680},
|
||||
{-0.50000000, 0.22360680, -0.50000000, -0.67082039},
|
||||
{-0.50000000, -0.22360680, -0.50000000, 0.67082039},
|
||||
{-0.50000000, -0.67082039, 0.50000000, -0.22360680}};
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* pitch_lag_tables.h
|
||||
*
|
||||
* This file contains tables for the pitch filter side-info in the entropy coder.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
/* header file for coding tables for the pitch filter side-info in the entropy coder */
|
||||
/********************* Pitch Filter Lag Coefficient Tables ************************/
|
||||
|
||||
/* tables for use with small pitch gain */
|
||||
|
||||
/* cdfs for quantized pitch lags */
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdf1Lo[127];
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdf2Lo[20];
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdf3Lo[2];
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdf4Lo[10];
|
||||
|
||||
extern const uint16_t *WebRtcIsac_kQPitchLagCdfPtrLo[4];
|
||||
|
||||
/* size of first cdf table */
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdfSizeLo[1];
|
||||
|
||||
/* index limits and ranges */
|
||||
extern const int16_t WebRtcIsac_kQIndexLowerLimitLagLo[4];
|
||||
extern const int16_t WebRtcIsac_kQIndexUpperLimitLagLo[4];
|
||||
|
||||
/* initial index for arithmetic decoder */
|
||||
extern const uint16_t WebRtcIsac_kQInitIndexLagLo[3];
|
||||
|
||||
/* mean values of pitch filter lags */
|
||||
extern const double WebRtcIsac_kQMeanLag2Lo[19];
|
||||
extern const double WebRtcIsac_kQMeanLag3Lo[1];
|
||||
extern const double WebRtcIsac_kQMeanLag4Lo[9];
|
||||
|
||||
extern const double WebRtcIsac_kQPitchLagStepsizeLo;
|
||||
|
||||
|
||||
/* tables for use with medium pitch gain */
|
||||
|
||||
/* cdfs for quantized pitch lags */
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdf1Mid[255];
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdf2Mid[36];
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdf3Mid[2];
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdf4Mid[20];
|
||||
|
||||
extern const uint16_t *WebRtcIsac_kQPitchLagCdfPtrMid[4];
|
||||
|
||||
/* size of first cdf table */
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdfSizeMid[1];
|
||||
|
||||
/* index limits and ranges */
|
||||
extern const int16_t WebRtcIsac_kQIndexLowerLimitLagMid[4];
|
||||
extern const int16_t WebRtcIsac_kQIndexUpperLimitLagMid[4];
|
||||
|
||||
/* initial index for arithmetic decoder */
|
||||
extern const uint16_t WebRtcIsac_kQInitIndexLagMid[3];
|
||||
|
||||
/* mean values of pitch filter lags */
|
||||
extern const double WebRtcIsac_kQMeanLag2Mid[35];
|
||||
extern const double WebRtcIsac_kQMeanLag3Mid[1];
|
||||
extern const double WebRtcIsac_kQMeanLag4Mid[19];
|
||||
|
||||
extern const double WebRtcIsac_kQPitchLagStepsizeMid;
|
||||
|
||||
|
||||
/* tables for use with large pitch gain */
|
||||
|
||||
/* cdfs for quantized pitch lags */
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdf1Hi[511];
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdf2Hi[68];
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdf3Hi[2];
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdf4Hi[35];
|
||||
|
||||
extern const uint16_t *WebRtcIsac_kQPitchLagCdfPtrHi[4];
|
||||
|
||||
/* size of first cdf table */
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdfSizeHi[1];
|
||||
|
||||
/* index limits and ranges */
|
||||
extern const int16_t WebRtcIsac_kQindexLowerLimitLagHi[4];
|
||||
extern const int16_t WebRtcIsac_kQindexUpperLimitLagHi[4];
|
||||
|
||||
/* initial index for arithmetic decoder */
|
||||
extern const uint16_t WebRtcIsac_kQInitIndexLagHi[3];
|
||||
|
||||
/* mean values of pitch filter lags */
|
||||
extern const double WebRtcIsac_kQMeanLag2Hi[67];
|
||||
extern const double WebRtcIsac_kQMeanLag3Hi[1];
|
||||
extern const double WebRtcIsac_kQMeanLag4Hi[34];
|
||||
|
||||
extern const double WebRtcIsac_kQPitchLagStepsizeHi;
|
||||
|
||||
/* transform matrix */
|
||||
extern const double WebRtcIsac_kTransform[4][4];
|
||||
|
||||
/* transpose transform matrix */
|
||||
extern const double WebRtcIsac_kTransformTranspose[4][4];
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_ */
|
||||
207
webrtc/modules/audio_coding/codecs/isac/main/source/settings.h
Normal file
207
webrtc/modules/audio_coding/codecs/isac/main/source/settings.h
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* settings.h
|
||||
*
|
||||
* Declaration of #defines used in the iSAC codec
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_
|
||||
|
||||
/* sampling frequency (Hz) */
|
||||
#define FS 16000
|
||||
|
||||
/* number of samples per frame (either 320 (20ms), 480 (30ms) or 960 (60ms)) */
|
||||
#define INITIAL_FRAMESAMPLES 960
|
||||
|
||||
|
||||
#define MAXFFTSIZE 2048
|
||||
#define NFACTOR 11
|
||||
|
||||
|
||||
|
||||
/* do not modify the following; this will have to be modified if we
|
||||
* have a 20ms framesize option */
|
||||
/**********************************************************************/
|
||||
/* miliseconds */
|
||||
#define FRAMESIZE 30
|
||||
/* number of samples per frame processed in the encoder, 480 */
|
||||
#define FRAMESAMPLES 480 /* ((FRAMESIZE*FS)/1000) */
|
||||
#define FRAMESAMPLES_HALF 240
|
||||
#define FRAMESAMPLES_QUARTER 120
|
||||
/**********************************************************************/
|
||||
|
||||
|
||||
|
||||
/* max number of samples per frame (= 60 ms frame) */
|
||||
#define MAX_FRAMESAMPLES 960
|
||||
#define MAX_SWBFRAMESAMPLES (MAX_FRAMESAMPLES * 2)
|
||||
/* number of samples per 10ms frame */
|
||||
#define FRAMESAMPLES_10ms ((10*FS)/1000)
|
||||
#define SWBFRAMESAMPLES_10ms (FRAMESAMPLES_10ms * 2)
|
||||
/* number of samples in 30 ms frame */
|
||||
#define FRAMESAMPLES_30ms 480
|
||||
/* number of subframes */
|
||||
#define SUBFRAMES 6
|
||||
/* length of a subframe */
|
||||
#define UPDATE 80
|
||||
/* length of half a subframe (low/high band) */
|
||||
#define HALF_SUBFRAMELEN (UPDATE/2)
|
||||
/* samples of look ahead (in a half-band, so actually
|
||||
* half the samples of look ahead @ FS) */
|
||||
#define QLOOKAHEAD 24 /* 3 ms */
|
||||
/* order of AR model in spectral entropy coder */
|
||||
#define AR_ORDER 6
|
||||
/* order of LP model in spectral entropy coder */
|
||||
#define LP_ORDER 0
|
||||
|
||||
/* window length (masking analysis) */
|
||||
#define WINLEN 256
|
||||
/* order of low-band pole filter used to approximate masking curve */
|
||||
#define ORDERLO 12
|
||||
/* order of hi-band pole filter used to approximate masking curve */
|
||||
#define ORDERHI 6
|
||||
|
||||
#define UB_LPC_ORDER 4
|
||||
#define UB_LPC_VEC_PER_FRAME 2
|
||||
#define UB16_LPC_VEC_PER_FRAME 4
|
||||
#define UB_ACTIVE_SUBFRAMES 2
|
||||
#define UB_MAX_LPC_ORDER 6
|
||||
#define UB_INTERPOL_SEGMENTS 1
|
||||
#define UB16_INTERPOL_SEGMENTS 3
|
||||
#define LB_TOTAL_DELAY_SAMPLES 48
|
||||
enum ISACBandwidth {isac8kHz = 8, isac12kHz = 12, isac16kHz = 16};
|
||||
enum ISACBand {kIsacLowerBand = 0, kIsacUpperBand12 = 1, kIsacUpperBand16 = 2};
|
||||
enum IsacSamplingRate {kIsacWideband = 16, kIsacSuperWideband = 32};
|
||||
#define UB_LPC_GAIN_DIM SUBFRAMES
|
||||
#define FB_STATE_SIZE_WORD32 6
|
||||
|
||||
|
||||
/* order for post_filter_bank */
|
||||
#define POSTQORDER 3
|
||||
/* order for pre-filterbank */
|
||||
#define QORDER 3
|
||||
/* another order */
|
||||
#define QORDER_ALL (POSTQORDER+QORDER-1)
|
||||
/* for decimator */
|
||||
#define ALLPASSSECTIONS 2
|
||||
|
||||
|
||||
/* array size for byte stream in number of bytes. */
|
||||
/* The old maximum size still needed for the decoding */
|
||||
#define STREAM_SIZE_MAX 600
|
||||
#define STREAM_SIZE_MAX_30 200 /* 200 bytes=53.4 kbps @ 30 ms.framelength */
|
||||
#define STREAM_SIZE_MAX_60 400 /* 400 bytes=53.4 kbps @ 60 ms.framelength */
|
||||
|
||||
/* storage size for bit counts */
|
||||
#define BIT_COUNTER_SIZE 30
|
||||
/* maximum order of any AR model or filter */
|
||||
#define MAX_AR_MODEL_ORDER 12//50
|
||||
|
||||
|
||||
/* For pitch analysis */
|
||||
#define PITCH_FRAME_LEN (FRAMESAMPLES_HALF) /* 30 ms */
|
||||
#define PITCH_MAX_LAG 140 /* 57 Hz */
|
||||
#define PITCH_MIN_LAG 20 /* 400 Hz */
|
||||
#define PITCH_MAX_GAIN 0.45
|
||||
#define PITCH_MAX_GAIN_06 0.27 /* PITCH_MAX_GAIN*0.6 */
|
||||
#define PITCH_MAX_GAIN_Q12 1843
|
||||
#define PITCH_LAG_SPAN2 (PITCH_MAX_LAG/2-PITCH_MIN_LAG/2+5)
|
||||
#define PITCH_CORR_LEN2 60 /* 15 ms */
|
||||
#define PITCH_CORR_STEP2 (PITCH_FRAME_LEN/4)
|
||||
#define PITCH_BW 11 /* half the band width of correlation surface */
|
||||
#define PITCH_SUBFRAMES 4
|
||||
#define PITCH_GRAN_PER_SUBFRAME 5
|
||||
#define PITCH_SUBFRAME_LEN (PITCH_FRAME_LEN/PITCH_SUBFRAMES)
|
||||
#define PITCH_UPDATE (PITCH_SUBFRAME_LEN/PITCH_GRAN_PER_SUBFRAME)
|
||||
/* maximum number of peaks to be examined in correlation surface */
|
||||
#define PITCH_MAX_NUM_PEAKS 10
|
||||
#define PITCH_PEAK_DECAY 0.85
|
||||
/* For weighting filter */
|
||||
#define PITCH_WLPCORDER 6
|
||||
#define PITCH_WLPCWINLEN PITCH_FRAME_LEN
|
||||
#define PITCH_WLPCASYM 0.3 /* asymmetry parameter */
|
||||
#define PITCH_WLPCBUFLEN PITCH_WLPCWINLEN
|
||||
/* For pitch filter */
|
||||
/* Extra 50 for fraction and LP filters */
|
||||
#define PITCH_BUFFSIZE (PITCH_MAX_LAG + 50)
|
||||
#define PITCH_INTBUFFSIZE (PITCH_FRAME_LEN+PITCH_BUFFSIZE)
|
||||
/* Max rel. step for interpolation */
|
||||
#define PITCH_UPSTEP 1.5
|
||||
/* Max rel. step for interpolation */
|
||||
#define PITCH_DOWNSTEP 0.67
|
||||
#define PITCH_FRACS 8
|
||||
#define PITCH_FRACORDER 9
|
||||
#define PITCH_DAMPORDER 5
|
||||
#define PITCH_FILTDELAY 1.5f
|
||||
/* stepsize for quantization of the pitch Gain */
|
||||
#define PITCH_GAIN_STEPSIZE 0.125
|
||||
|
||||
|
||||
|
||||
/* Order of high pass filter */
|
||||
#define HPORDER 2
|
||||
|
||||
/* some mathematical constants */
|
||||
/* log2(exp) */
|
||||
#define LOG2EXP 1.44269504088896
|
||||
#define PI 3.14159265358979
|
||||
|
||||
/* Maximum number of iterations allowed to limit payload size */
|
||||
#define MAX_PAYLOAD_LIMIT_ITERATION 5
|
||||
|
||||
/* Redundant Coding */
|
||||
#define RCU_BOTTLENECK_BPS 16000
|
||||
#define RCU_TRANSCODING_SCALE 0.40f
|
||||
#define RCU_TRANSCODING_SCALE_INVERSE 2.5f
|
||||
|
||||
#define RCU_TRANSCODING_SCALE_UB 0.50f
|
||||
#define RCU_TRANSCODING_SCALE_UB_INVERSE 2.0f
|
||||
|
||||
#define SIZE_RESAMPLER_STATE 6
|
||||
|
||||
/* Define Error codes */
|
||||
/* 6000 General */
|
||||
#define ISAC_MEMORY_ALLOCATION_FAILED 6010
|
||||
#define ISAC_MODE_MISMATCH 6020
|
||||
#define ISAC_DISALLOWED_BOTTLENECK 6030
|
||||
#define ISAC_DISALLOWED_FRAME_LENGTH 6040
|
||||
#define ISAC_UNSUPPORTED_SAMPLING_FREQUENCY 6050
|
||||
|
||||
/* 6200 Bandwidth estimator */
|
||||
#define ISAC_RANGE_ERROR_BW_ESTIMATOR 6240
|
||||
/* 6400 Encoder */
|
||||
#define ISAC_ENCODER_NOT_INITIATED 6410
|
||||
#define ISAC_DISALLOWED_CODING_MODE 6420
|
||||
#define ISAC_DISALLOWED_FRAME_MODE_ENCODER 6430
|
||||
#define ISAC_DISALLOWED_BITSTREAM_LENGTH 6440
|
||||
#define ISAC_PAYLOAD_LARGER_THAN_LIMIT 6450
|
||||
#define ISAC_DISALLOWED_ENCODER_BANDWIDTH 6460
|
||||
/* 6600 Decoder */
|
||||
#define ISAC_DECODER_NOT_INITIATED 6610
|
||||
#define ISAC_EMPTY_PACKET 6620
|
||||
#define ISAC_DISALLOWED_FRAME_MODE_DECODER 6630
|
||||
#define ISAC_RANGE_ERROR_DECODE_FRAME_LENGTH 6640
|
||||
#define ISAC_RANGE_ERROR_DECODE_BANDWIDTH 6650
|
||||
#define ISAC_RANGE_ERROR_DECODE_PITCH_GAIN 6660
|
||||
#define ISAC_RANGE_ERROR_DECODE_PITCH_LAG 6670
|
||||
#define ISAC_RANGE_ERROR_DECODE_LPC 6680
|
||||
#define ISAC_RANGE_ERROR_DECODE_SPECTRUM 6690
|
||||
#define ISAC_LENGTH_MISMATCH 6730
|
||||
#define ISAC_RANGE_ERROR_DECODE_BANDWITH 6740
|
||||
#define ISAC_DISALLOWED_BANDWIDTH_MODE_DECODER 6750
|
||||
#define ISAC_DISALLOWED_LPC_MODEL 6760
|
||||
/* 6800 Call setup formats */
|
||||
#define ISAC_INCOMPATIBLE_FORMATS 6810
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_ */
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "spectrum_ar_model_tables.h"
|
||||
#include "settings.h"
|
||||
|
||||
/********************* AR Coefficient Tables ************************/
|
||||
/* cdf for quantized reflection coefficient 1 */
|
||||
const uint16_t WebRtcIsac_kQArRc1Cdf[NUM_AR_RC_QUANT_BAUNDARY] = {
|
||||
0, 2, 4, 129, 7707, 57485, 65495, 65527, 65529, 65531,
|
||||
65533, 65535};
|
||||
|
||||
/* cdf for quantized reflection coefficient 2 */
|
||||
const uint16_t WebRtcIsac_kQArRc2Cdf[NUM_AR_RC_QUANT_BAUNDARY] = {
|
||||
0, 2, 4, 7, 531, 25298, 64525, 65526, 65529, 65531,
|
||||
65533, 65535};
|
||||
|
||||
/* cdf for quantized reflection coefficient 3 */
|
||||
const uint16_t WebRtcIsac_kQArRc3Cdf[NUM_AR_RC_QUANT_BAUNDARY] = {
|
||||
0, 2, 4, 6, 620, 22898, 64843, 65527, 65529, 65531,
|
||||
65533, 65535};
|
||||
|
||||
/* cdf for quantized reflection coefficient 4 */
|
||||
const uint16_t WebRtcIsac_kQArRc4Cdf[NUM_AR_RC_QUANT_BAUNDARY] = {
|
||||
0, 2, 4, 6, 35, 10034, 60733, 65506, 65529, 65531,
|
||||
65533, 65535};
|
||||
|
||||
/* cdf for quantized reflection coefficient 5 */
|
||||
const uint16_t WebRtcIsac_kQArRc5Cdf[NUM_AR_RC_QUANT_BAUNDARY] = {
|
||||
0, 2, 4, 6, 36, 7567, 56727, 65385, 65529, 65531,
|
||||
65533, 65535};
|
||||
|
||||
/* cdf for quantized reflection coefficient 6 */
|
||||
const uint16_t WebRtcIsac_kQArRc6Cdf[NUM_AR_RC_QUANT_BAUNDARY] = {
|
||||
0, 2, 4, 6, 14, 6579, 57360, 65409, 65529, 65531,
|
||||
65533, 65535};
|
||||
|
||||
/* representation levels for quantized reflection coefficient 1 */
|
||||
const int16_t WebRtcIsac_kQArRc1Levels[NUM_AR_RC_QUANT_BAUNDARY - 1] = {
|
||||
-32104, -29007, -23202, -15496, -9279, -2577, 5934, 17535, 24512, 29503, 32104
|
||||
};
|
||||
|
||||
/* representation levels for quantized reflection coefficient 2 */
|
||||
const int16_t WebRtcIsac_kQArRc2Levels[NUM_AR_RC_QUANT_BAUNDARY - 1] = {
|
||||
-32104, -29503, -23494, -15261, -7309, -1399, 6158, 16381, 24512, 29503, 32104
|
||||
};
|
||||
|
||||
/* representation levels for quantized reflection coefficient 3 */
|
||||
const int16_t WebRtcIsac_kQArRc3Levels[NUM_AR_RC_QUANT_BAUNDARY - 1] = {
|
||||
-32104, -29503, -23157, -15186, -7347, -1359, 5829, 17535, 24512, 29503, 32104
|
||||
};
|
||||
|
||||
/* representation levels for quantized reflection coefficient 4 */
|
||||
const int16_t WebRtcIsac_kQArRc4Levels[NUM_AR_RC_QUANT_BAUNDARY - 1] = {
|
||||
-32104, -29503, -24512, -15362, -6665, -342, 6596, 14585, 24512, 29503, 32104
|
||||
};
|
||||
|
||||
/* representation levels for quantized reflection coefficient 5 */
|
||||
const int16_t WebRtcIsac_kQArRc5Levels[NUM_AR_RC_QUANT_BAUNDARY - 1] = {
|
||||
-32104, -29503, -24512, -15005, -6564, -106, 7123, 14920, 24512, 29503, 32104
|
||||
};
|
||||
|
||||
/* representation levels for quantized reflection coefficient 6 */
|
||||
const int16_t WebRtcIsac_kQArRc6Levels[NUM_AR_RC_QUANT_BAUNDARY - 1] = {
|
||||
-32104, -29503, -24512, -15096, -6656, -37, 7036, 14847, 24512, 29503, 32104
|
||||
};
|
||||
|
||||
/* quantization boundary levels for reflection coefficients */
|
||||
const int16_t WebRtcIsac_kQArBoundaryLevels[NUM_AR_RC_QUANT_BAUNDARY] = {
|
||||
-32768, -31441, -27566, -21458, -13612, -4663, 4663, 13612, 21458, 27566, 31441,
|
||||
32767
|
||||
};
|
||||
|
||||
/* initial index for AR reflection coefficient quantizer and cdf table search */
|
||||
const uint16_t WebRtcIsac_kQArRcInitIndex[6] = {
|
||||
5, 5, 5, 5, 5, 5};
|
||||
|
||||
/* pointers to AR cdf tables */
|
||||
const uint16_t *WebRtcIsac_kQArRcCdfPtr[AR_ORDER] = {
|
||||
WebRtcIsac_kQArRc1Cdf, WebRtcIsac_kQArRc2Cdf, WebRtcIsac_kQArRc3Cdf,
|
||||
WebRtcIsac_kQArRc4Cdf, WebRtcIsac_kQArRc5Cdf, WebRtcIsac_kQArRc6Cdf
|
||||
};
|
||||
|
||||
/* pointers to AR representation levels tables */
|
||||
const int16_t *WebRtcIsac_kQArRcLevelsPtr[AR_ORDER] = {
|
||||
WebRtcIsac_kQArRc1Levels, WebRtcIsac_kQArRc2Levels, WebRtcIsac_kQArRc3Levels,
|
||||
WebRtcIsac_kQArRc4Levels, WebRtcIsac_kQArRc5Levels, WebRtcIsac_kQArRc6Levels
|
||||
};
|
||||
|
||||
|
||||
/******************** GAIN Coefficient Tables ***********************/
|
||||
/* cdf for Gain coefficient */
|
||||
const uint16_t WebRtcIsac_kQGainCdf[19] = {
|
||||
0, 2, 4, 6, 8, 10, 12, 14, 16, 1172,
|
||||
11119, 29411, 51699, 64445, 65527, 65529, 65531, 65533, 65535};
|
||||
|
||||
/* representation levels for quantized squared Gain coefficient */
|
||||
const int32_t WebRtcIsac_kQGain2Levels[18] = {
|
||||
// 17, 28, 46, 76, 128, 215, 364, 709, 1268, 1960, 3405, 6078, 11286, 17827, 51918, 134498, 487432, 2048000};
|
||||
128, 128, 128, 128, 128, 215, 364, 709, 1268, 1960, 3405, 6078, 11286, 17827, 51918, 134498, 487432, 2048000};
|
||||
/* quantization boundary levels for squared Gain coefficient */
|
||||
const int32_t WebRtcIsac_kQGain2BoundaryLevels[19] = {
|
||||
0, 21, 35, 59, 99, 166, 280, 475, 815, 1414, 2495, 4505, 8397, 16405, 34431, 81359, 240497, 921600, 0x7FFFFFFF};
|
||||
|
||||
/* pointers to Gain cdf table */
|
||||
const uint16_t *WebRtcIsac_kQGainCdf_ptr[1] = {WebRtcIsac_kQGainCdf};
|
||||
|
||||
/* Gain initial index for gain quantizer and cdf table search */
|
||||
const uint16_t WebRtcIsac_kQGainInitIndex[1] = {11};
|
||||
|
||||
/************************* Cosine Tables ****************************/
|
||||
/* Cosine table */
|
||||
const int16_t WebRtcIsac_kCos[6][60] = {
|
||||
{512, 512, 511, 510, 508, 507, 505, 502, 499, 496, 493, 489, 485, 480, 476, 470, 465, 459, 453, 447,
|
||||
440, 433, 426, 418, 410, 402, 394, 385, 376, 367, 357, 348, 338, 327, 317, 306, 295, 284, 273, 262,
|
||||
250, 238, 226, 214, 202, 190, 177, 165, 152, 139, 126, 113, 100, 87, 73, 60, 47, 33, 20, 7},
|
||||
{512, 510, 508, 503, 498, 491, 483, 473, 462, 450, 437, 422, 406, 389, 371, 352, 333, 312, 290, 268,
|
||||
244, 220, 196, 171, 145, 120, 93, 67, 40, 13, -13, -40, -67, -93, -120, -145, -171, -196, -220, -244,
|
||||
-268, -290, -312, -333, -352, -371, -389, -406, -422, -437, -450, -462, -473, -483, -491, -498, -503, -508, -510, -512},
|
||||
{512, 508, 502, 493, 480, 465, 447, 426, 402, 376, 348, 317, 284, 250, 214, 177, 139, 100, 60, 20,
|
||||
-20, -60, -100, -139, -177, -214, -250, -284, -317, -348, -376, -402, -426, -447, -465, -480, -493, -502, -508, -512,
|
||||
-512, -508, -502, -493, -480, -465, -447, -426, -402, -376, -348, -317, -284, -250, -214, -177, -139, -100, -60, -20},
|
||||
{511, 506, 495, 478, 456, 429, 398, 362, 322, 279, 232, 183, 133, 80, 27, -27, -80, -133, -183, -232,
|
||||
-279, -322, -362, -398, -429, -456, -478, -495, -506, -511, -511, -506, -495, -478, -456, -429, -398, -362, -322, -279,
|
||||
-232, -183, -133, -80, -27, 27, 80, 133, 183, 232, 279, 322, 362, 398, 429, 456, 478, 495, 506, 511},
|
||||
{511, 502, 485, 459, 426, 385, 338, 284, 226, 165, 100, 33, -33, -100, -165, -226, -284, -338, -385, -426,
|
||||
-459, -485, -502, -511, -511, -502, -485, -459, -426, -385, -338, -284, -226, -165, -100, -33, 33, 100, 165, 226,
|
||||
284, 338, 385, 426, 459, 485, 502, 511, 511, 502, 485, 459, 426, 385, 338, 284, 226, 165, 100, 33},
|
||||
{510, 498, 473, 437, 389, 333, 268, 196, 120, 40, -40, -120, -196, -268, -333, -389, -437, -473, -498, -510,
|
||||
-510, -498, -473, -437, -389, -333, -268, -196, -120, -40, 40, 120, 196, 268, 333, 389, 437, 473, 498, 510,
|
||||
510, 498, 473, 437, 389, 333, 268, 196, 120, 40, -40, -120, -196, -268, -333, -389, -437, -473, -498, -510}
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* spectrum_ar_model_tables.h
|
||||
*
|
||||
* This file contains definitions of tables with AR coefficients,
|
||||
* Gain coefficients and cosine tables.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_
|
||||
|
||||
#include "structs.h"
|
||||
|
||||
#define NUM_AR_RC_QUANT_BAUNDARY 12
|
||||
|
||||
/********************* AR Coefficient Tables ************************/
|
||||
/* cdf for quantized reflection coefficient 1 */
|
||||
extern const uint16_t WebRtcIsac_kQArRc1Cdf[NUM_AR_RC_QUANT_BAUNDARY];
|
||||
|
||||
/* cdf for quantized reflection coefficient 2 */
|
||||
extern const uint16_t WebRtcIsac_kQArRc2Cdf[NUM_AR_RC_QUANT_BAUNDARY];
|
||||
|
||||
/* cdf for quantized reflection coefficient 3 */
|
||||
extern const uint16_t WebRtcIsac_kQArRc3Cdf[NUM_AR_RC_QUANT_BAUNDARY];
|
||||
|
||||
/* cdf for quantized reflection coefficient 4 */
|
||||
extern const uint16_t WebRtcIsac_kQArRc4Cdf[NUM_AR_RC_QUANT_BAUNDARY];
|
||||
|
||||
/* cdf for quantized reflection coefficient 5 */
|
||||
extern const uint16_t WebRtcIsac_kQArRc5Cdf[NUM_AR_RC_QUANT_BAUNDARY];
|
||||
|
||||
/* cdf for quantized reflection coefficient 6 */
|
||||
extern const uint16_t WebRtcIsac_kQArRc6Cdf[NUM_AR_RC_QUANT_BAUNDARY];
|
||||
|
||||
/* quantization boundary levels for reflection coefficients */
|
||||
extern const int16_t WebRtcIsac_kQArBoundaryLevels[NUM_AR_RC_QUANT_BAUNDARY];
|
||||
|
||||
/* initial indices for AR reflection coefficient quantizer and cdf table search */
|
||||
extern const uint16_t WebRtcIsac_kQArRcInitIndex[AR_ORDER];
|
||||
|
||||
/* pointers to AR cdf tables */
|
||||
extern const uint16_t *WebRtcIsac_kQArRcCdfPtr[AR_ORDER];
|
||||
|
||||
/* pointers to AR representation levels tables */
|
||||
extern const int16_t *WebRtcIsac_kQArRcLevelsPtr[AR_ORDER];
|
||||
|
||||
|
||||
/******************** GAIN Coefficient Tables ***********************/
|
||||
/* cdf for Gain coefficient */
|
||||
extern const uint16_t WebRtcIsac_kQGainCdf[19];
|
||||
|
||||
/* representation levels for quantized Gain coefficient */
|
||||
extern const int32_t WebRtcIsac_kQGain2Levels[18];
|
||||
|
||||
/* squared quantization boundary levels for Gain coefficient */
|
||||
extern const int32_t WebRtcIsac_kQGain2BoundaryLevels[19];
|
||||
|
||||
/* pointer to Gain cdf table */
|
||||
extern const uint16_t *WebRtcIsac_kQGainCdf_ptr[1];
|
||||
|
||||
/* Gain initial index for gain quantizer and cdf table search */
|
||||
extern const uint16_t WebRtcIsac_kQGainInitIndex[1];
|
||||
|
||||
/************************* Cosine Tables ****************************/
|
||||
/* Cosine table */
|
||||
extern const int16_t WebRtcIsac_kCos[6][60];
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ */
|
||||
498
webrtc/modules/audio_coding/codecs/isac/main/source/structs.h
Normal file
498
webrtc/modules/audio_coding/codecs/isac/main/source/structs.h
Normal file
@@ -0,0 +1,498 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* structs.h
|
||||
*
|
||||
* This header file contains all the structs used in the ISAC codec
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_
|
||||
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/bandwidth_info.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/interface/isac.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
typedef struct Bitstreamstruct {
|
||||
|
||||
uint8_t stream[STREAM_SIZE_MAX];
|
||||
uint32_t W_upper;
|
||||
uint32_t streamval;
|
||||
uint32_t stream_index;
|
||||
|
||||
} Bitstr;
|
||||
|
||||
typedef struct {
|
||||
|
||||
double DataBufferLo[WINLEN];
|
||||
double DataBufferHi[WINLEN];
|
||||
|
||||
double CorrBufLo[ORDERLO+1];
|
||||
double CorrBufHi[ORDERHI+1];
|
||||
|
||||
float PreStateLoF[ORDERLO+1];
|
||||
float PreStateLoG[ORDERLO+1];
|
||||
float PreStateHiF[ORDERHI+1];
|
||||
float PreStateHiG[ORDERHI+1];
|
||||
float PostStateLoF[ORDERLO+1];
|
||||
float PostStateLoG[ORDERLO+1];
|
||||
float PostStateHiF[ORDERHI+1];
|
||||
float PostStateHiG[ORDERHI+1];
|
||||
|
||||
double OldEnergy;
|
||||
|
||||
} MaskFiltstr;
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
//state vectors for each of the two analysis filters
|
||||
double INSTAT1[2*(QORDER-1)];
|
||||
double INSTAT2[2*(QORDER-1)];
|
||||
double INSTATLA1[2*(QORDER-1)];
|
||||
double INSTATLA2[2*(QORDER-1)];
|
||||
double INLABUF1[QLOOKAHEAD];
|
||||
double INLABUF2[QLOOKAHEAD];
|
||||
|
||||
float INSTAT1_float[2*(QORDER-1)];
|
||||
float INSTAT2_float[2*(QORDER-1)];
|
||||
float INSTATLA1_float[2*(QORDER-1)];
|
||||
float INSTATLA2_float[2*(QORDER-1)];
|
||||
float INLABUF1_float[QLOOKAHEAD];
|
||||
float INLABUF2_float[QLOOKAHEAD];
|
||||
|
||||
/* High pass filter */
|
||||
double HPstates[HPORDER];
|
||||
float HPstates_float[HPORDER];
|
||||
|
||||
} PreFiltBankstr;
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
//state vectors for each of the two analysis filters
|
||||
double STATE_0_LOWER[2*POSTQORDER];
|
||||
double STATE_0_UPPER[2*POSTQORDER];
|
||||
|
||||
/* High pass filter */
|
||||
double HPstates1[HPORDER];
|
||||
double HPstates2[HPORDER];
|
||||
|
||||
float STATE_0_LOWER_float[2*POSTQORDER];
|
||||
float STATE_0_UPPER_float[2*POSTQORDER];
|
||||
|
||||
float HPstates1_float[HPORDER];
|
||||
float HPstates2_float[HPORDER];
|
||||
|
||||
} PostFiltBankstr;
|
||||
|
||||
typedef struct {
|
||||
|
||||
//data buffer for pitch filter
|
||||
double ubuf[PITCH_BUFFSIZE];
|
||||
|
||||
//low pass state vector
|
||||
double ystate[PITCH_DAMPORDER];
|
||||
|
||||
//old lag and gain
|
||||
double oldlagp[1];
|
||||
double oldgainp[1];
|
||||
|
||||
} PitchFiltstr;
|
||||
|
||||
typedef struct {
|
||||
|
||||
//data buffer
|
||||
double buffer[PITCH_WLPCBUFLEN];
|
||||
|
||||
//state vectors
|
||||
double istate[PITCH_WLPCORDER];
|
||||
double weostate[PITCH_WLPCORDER];
|
||||
double whostate[PITCH_WLPCORDER];
|
||||
|
||||
//LPC window -> should be a global array because constant
|
||||
double window[PITCH_WLPCWINLEN];
|
||||
|
||||
} WeightFiltstr;
|
||||
|
||||
typedef struct {
|
||||
|
||||
//for inital estimator
|
||||
double dec_buffer[PITCH_CORR_LEN2 + PITCH_CORR_STEP2 +
|
||||
PITCH_MAX_LAG/2 - PITCH_FRAME_LEN/2+2];
|
||||
double decimator_state[2*ALLPASSSECTIONS+1];
|
||||
double hp_state[2];
|
||||
|
||||
double whitened_buf[QLOOKAHEAD];
|
||||
|
||||
double inbuf[QLOOKAHEAD];
|
||||
|
||||
PitchFiltstr PFstr_wght;
|
||||
PitchFiltstr PFstr;
|
||||
WeightFiltstr Wghtstr;
|
||||
|
||||
} PitchAnalysisStruct;
|
||||
|
||||
|
||||
|
||||
/* Have instance of struct together with other iSAC structs */
|
||||
typedef struct {
|
||||
|
||||
/* Previous frame length (in ms) */
|
||||
int32_t prev_frame_length;
|
||||
|
||||
/* Previous RTP timestamp from received
|
||||
packet (in samples relative beginning) */
|
||||
int32_t prev_rec_rtp_number;
|
||||
|
||||
/* Send timestamp for previous packet (in ms using timeGetTime()) */
|
||||
uint32_t prev_rec_send_ts;
|
||||
|
||||
/* Arrival time for previous packet (in ms using timeGetTime()) */
|
||||
uint32_t prev_rec_arr_ts;
|
||||
|
||||
/* rate of previous packet, derived from RTP timestamps (in bits/s) */
|
||||
float prev_rec_rtp_rate;
|
||||
|
||||
/* Time sinse the last update of the BN estimate (in ms) */
|
||||
uint32_t last_update_ts;
|
||||
|
||||
/* Time sinse the last reduction (in ms) */
|
||||
uint32_t last_reduction_ts;
|
||||
|
||||
/* How many times the estimate was update in the beginning */
|
||||
int32_t count_tot_updates_rec;
|
||||
|
||||
/* The estimated bottle neck rate from there to here (in bits/s) */
|
||||
int32_t rec_bw;
|
||||
float rec_bw_inv;
|
||||
float rec_bw_avg;
|
||||
float rec_bw_avg_Q;
|
||||
|
||||
/* The estimated mean absolute jitter value,
|
||||
as seen on this side (in ms) */
|
||||
float rec_jitter;
|
||||
float rec_jitter_short_term;
|
||||
float rec_jitter_short_term_abs;
|
||||
float rec_max_delay;
|
||||
float rec_max_delay_avg_Q;
|
||||
|
||||
/* (assumed) bitrate for headers (bps) */
|
||||
float rec_header_rate;
|
||||
|
||||
/* The estimated bottle neck rate from here to there (in bits/s) */
|
||||
float send_bw_avg;
|
||||
|
||||
/* The estimated mean absolute jitter value, as seen on
|
||||
the other siee (in ms) */
|
||||
float send_max_delay_avg;
|
||||
|
||||
// number of packets received since last update
|
||||
int num_pkts_rec;
|
||||
|
||||
int num_consec_rec_pkts_over_30k;
|
||||
|
||||
// flag for marking that a high speed network has been
|
||||
// detected downstream
|
||||
int hsn_detect_rec;
|
||||
|
||||
int num_consec_snt_pkts_over_30k;
|
||||
|
||||
// flag for marking that a high speed network has
|
||||
// been detected upstream
|
||||
int hsn_detect_snd;
|
||||
|
||||
uint32_t start_wait_period;
|
||||
|
||||
int in_wait_period;
|
||||
|
||||
int change_to_WB;
|
||||
|
||||
uint32_t senderTimestamp;
|
||||
uint32_t receiverTimestamp;
|
||||
//enum IsacSamplingRate incomingStreamSampFreq;
|
||||
uint16_t numConsecLatePkts;
|
||||
float consecLatency;
|
||||
int16_t inWaitLatePkts;
|
||||
|
||||
IsacBandwidthInfo external_bw_info;
|
||||
} BwEstimatorstr;
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
/* boolean, flags if previous packet exceeded B.N. */
|
||||
int PrevExceed;
|
||||
/* ms */
|
||||
int ExceedAgo;
|
||||
/* packets left to send in current burst */
|
||||
int BurstCounter;
|
||||
/* packets */
|
||||
int InitCounter;
|
||||
/* ms remaining in buffer when next packet will be sent */
|
||||
double StillBuffered;
|
||||
|
||||
} RateModel;
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
unsigned int SpaceAlloced;
|
||||
unsigned int MaxPermAlloced;
|
||||
double Tmp0[MAXFFTSIZE];
|
||||
double Tmp1[MAXFFTSIZE];
|
||||
double Tmp2[MAXFFTSIZE];
|
||||
double Tmp3[MAXFFTSIZE];
|
||||
int Perm[MAXFFTSIZE];
|
||||
int factor [NFACTOR];
|
||||
|
||||
} FFTstr;
|
||||
|
||||
|
||||
/* The following strutc is used to store data from encoding, to make it
|
||||
fast and easy to construct a new bitstream with a different Bandwidth
|
||||
estimate. All values (except framelength and minBytes) is double size to
|
||||
handle 60 ms of data.
|
||||
*/
|
||||
typedef struct {
|
||||
|
||||
/* Used to keep track of if it is first or second part of 60 msec packet */
|
||||
int startIdx;
|
||||
|
||||
/* Frame length in samples */
|
||||
int16_t framelength;
|
||||
|
||||
/* Pitch Gain */
|
||||
int pitchGain_index[2];
|
||||
|
||||
/* Pitch Lag */
|
||||
double meanGain[2];
|
||||
int pitchIndex[PITCH_SUBFRAMES*2];
|
||||
|
||||
/* LPC */
|
||||
int LPCindex_s[108*2]; /* KLT_ORDER_SHAPE = 108 */
|
||||
int LPCindex_g[12*2]; /* KLT_ORDER_GAIN = 12 */
|
||||
double LPCcoeffs_lo[(ORDERLO+1)*SUBFRAMES*2];
|
||||
double LPCcoeffs_hi[(ORDERHI+1)*SUBFRAMES*2];
|
||||
|
||||
/* Encode Spec */
|
||||
int16_t fre[FRAMESAMPLES];
|
||||
int16_t fim[FRAMESAMPLES];
|
||||
int16_t AvgPitchGain[2];
|
||||
|
||||
/* Used in adaptive mode only */
|
||||
int minBytes;
|
||||
|
||||
} IsacSaveEncoderData;
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
int indexLPCShape[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
|
||||
double lpcGain[SUBFRAMES<<1];
|
||||
int lpcGainIndex[SUBFRAMES<<1];
|
||||
|
||||
Bitstr bitStreamObj;
|
||||
|
||||
int16_t realFFT[FRAMESAMPLES_HALF];
|
||||
int16_t imagFFT[FRAMESAMPLES_HALF];
|
||||
} ISACUBSaveEncDataStruct;
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
Bitstr bitstr_obj;
|
||||
MaskFiltstr maskfiltstr_obj;
|
||||
PreFiltBankstr prefiltbankstr_obj;
|
||||
PitchFiltstr pitchfiltstr_obj;
|
||||
PitchAnalysisStruct pitchanalysisstr_obj;
|
||||
FFTstr fftstr_obj;
|
||||
IsacSaveEncoderData SaveEnc_obj;
|
||||
|
||||
int buffer_index;
|
||||
int16_t current_framesamples;
|
||||
|
||||
float data_buffer_float[FRAMESAMPLES_30ms];
|
||||
|
||||
int frame_nb;
|
||||
double bottleneck;
|
||||
int16_t new_framelength;
|
||||
double s2nr;
|
||||
|
||||
/* Maximum allowed number of bits for a 30 msec packet */
|
||||
int16_t payloadLimitBytes30;
|
||||
/* Maximum allowed number of bits for a 30 msec packet */
|
||||
int16_t payloadLimitBytes60;
|
||||
/* Maximum allowed number of bits for both 30 and 60 msec packet */
|
||||
int16_t maxPayloadBytes;
|
||||
/* Maximum allowed rate in bytes per 30 msec packet */
|
||||
int16_t maxRateInBytes;
|
||||
|
||||
/*---
|
||||
If set to 1 iSAC will not addapt the frame-size, if used in
|
||||
channel-adaptive mode. The initial value will be used for all rates.
|
||||
---*/
|
||||
int16_t enforceFrameSize;
|
||||
|
||||
/*-----
|
||||
This records the BWE index the encoder injected into the bit-stream.
|
||||
It will be used in RCU. The same BWE index of main payload will be in
|
||||
the redundant payload. We can not retrive it from BWE because it is
|
||||
a recursive procedure (WebRtcIsac_GetDownlinkBwJitIndexImpl) and has to be
|
||||
called only once per each encode.
|
||||
-----*/
|
||||
int16_t lastBWIdx;
|
||||
} ISACLBEncStruct;
|
||||
|
||||
typedef struct {
|
||||
|
||||
Bitstr bitstr_obj;
|
||||
MaskFiltstr maskfiltstr_obj;
|
||||
PreFiltBankstr prefiltbankstr_obj;
|
||||
FFTstr fftstr_obj;
|
||||
ISACUBSaveEncDataStruct SaveEnc_obj;
|
||||
|
||||
int buffer_index;
|
||||
float data_buffer_float[MAX_FRAMESAMPLES +
|
||||
LB_TOTAL_DELAY_SAMPLES];
|
||||
double bottleneck;
|
||||
/* Maximum allowed number of bits for a 30 msec packet */
|
||||
//int16_t payloadLimitBytes30;
|
||||
/* Maximum allowed number of bits for both 30 and 60 msec packet */
|
||||
//int16_t maxPayloadBytes;
|
||||
int16_t maxPayloadSizeBytes;
|
||||
|
||||
double lastLPCVec[UB_LPC_ORDER];
|
||||
int16_t numBytesUsed;
|
||||
int16_t lastJitterInfo;
|
||||
} ISACUBEncStruct;
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
Bitstr bitstr_obj;
|
||||
MaskFiltstr maskfiltstr_obj;
|
||||
PostFiltBankstr postfiltbankstr_obj;
|
||||
PitchFiltstr pitchfiltstr_obj;
|
||||
FFTstr fftstr_obj;
|
||||
|
||||
} ISACLBDecStruct;
|
||||
|
||||
typedef struct {
|
||||
|
||||
Bitstr bitstr_obj;
|
||||
MaskFiltstr maskfiltstr_obj;
|
||||
PostFiltBankstr postfiltbankstr_obj;
|
||||
FFTstr fftstr_obj;
|
||||
|
||||
} ISACUBDecStruct;
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
ISACLBEncStruct ISACencLB_obj;
|
||||
ISACLBDecStruct ISACdecLB_obj;
|
||||
} ISACLBStruct;
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
ISACUBEncStruct ISACencUB_obj;
|
||||
ISACUBDecStruct ISACdecUB_obj;
|
||||
} ISACUBStruct;
|
||||
|
||||
/*
|
||||
This struct is used to take a snapshot of the entropy coder and LPC gains
|
||||
right before encoding LPC gains. This allows us to go back to that state
|
||||
if we like to limit the payload size.
|
||||
*/
|
||||
typedef struct {
|
||||
/* 6 lower-band & 6 upper-band */
|
||||
double loFiltGain[SUBFRAMES];
|
||||
double hiFiltGain[SUBFRAMES];
|
||||
/* Upper boundary of interval W */
|
||||
uint32_t W_upper;
|
||||
uint32_t streamval;
|
||||
/* Index to the current position in bytestream */
|
||||
uint32_t stream_index;
|
||||
uint8_t stream[3];
|
||||
} transcode_obj;
|
||||
|
||||
typedef struct {
|
||||
// TODO(kwiberg): The size of these tables could be reduced by storing floats
|
||||
// instead of doubles, and by making use of the identity cos(x) =
|
||||
// sin(x+pi/2). They could also be made global constants that we fill in at
|
||||
// compile time.
|
||||
double costab1[FRAMESAMPLES_HALF];
|
||||
double sintab1[FRAMESAMPLES_HALF];
|
||||
double costab2[FRAMESAMPLES_QUARTER];
|
||||
double sintab2[FRAMESAMPLES_QUARTER];
|
||||
} TransformTables;
|
||||
|
||||
typedef struct {
|
||||
// lower-band codec instance
|
||||
ISACLBStruct instLB;
|
||||
// upper-band codec instance
|
||||
ISACUBStruct instUB;
|
||||
|
||||
// Bandwidth Estimator and model for the rate.
|
||||
BwEstimatorstr bwestimator_obj;
|
||||
RateModel rate_data_obj;
|
||||
double MaxDelay;
|
||||
|
||||
/* 0 = adaptive; 1 = instantaneous */
|
||||
int16_t codingMode;
|
||||
|
||||
// overall bottleneck of the codec
|
||||
int32_t bottleneck;
|
||||
|
||||
// QMF Filter state
|
||||
int32_t analysisFBState1[FB_STATE_SIZE_WORD32];
|
||||
int32_t analysisFBState2[FB_STATE_SIZE_WORD32];
|
||||
int32_t synthesisFBState1[FB_STATE_SIZE_WORD32];
|
||||
int32_t synthesisFBState2[FB_STATE_SIZE_WORD32];
|
||||
|
||||
// Error Code
|
||||
int16_t errorCode;
|
||||
|
||||
// bandwidth of the encoded audio 8, 12 or 16 kHz
|
||||
enum ISACBandwidth bandwidthKHz;
|
||||
// Sampling rate of audio, encoder and decode, 8 or 16 kHz
|
||||
enum IsacSamplingRate encoderSamplingRateKHz;
|
||||
enum IsacSamplingRate decoderSamplingRateKHz;
|
||||
// Flag to keep track of initializations, lower & upper-band
|
||||
// encoder and decoder.
|
||||
int16_t initFlag;
|
||||
|
||||
// Flag to to indicate signal bandwidth switch
|
||||
int16_t resetFlag_8kHz;
|
||||
|
||||
// Maximum allowed rate, measured in Bytes per 30 ms.
|
||||
int16_t maxRateBytesPer30Ms;
|
||||
// Maximum allowed payload-size, measured in Bytes.
|
||||
int16_t maxPayloadSizeBytes;
|
||||
/* The expected sampling rate of the input signal. Valid values are 16000,
|
||||
* 32000 and 48000. This is not the operation sampling rate of the codec.
|
||||
* Input signals at 48 kHz are resampled to 32 kHz, then encoded. */
|
||||
uint16_t in_sample_rate_hz;
|
||||
/* State for the input-resampler. It is only used for 48 kHz input signals. */
|
||||
int16_t state_in_resampler[SIZE_RESAMPLER_STATE];
|
||||
|
||||
// Trig tables for WebRtcIsac_Time2Spec and WebRtcIsac_Spec2time.
|
||||
TransformTables transform_tables;
|
||||
} ISACMainStruct;
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_ */
|
||||
284
webrtc/modules/audio_processing/BUILD.gn
Normal file
284
webrtc/modules/audio_processing/BUILD.gn
Normal file
@@ -0,0 +1,284 @@
|
||||
# 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("//third_party/protobuf/proto_library.gni")
|
||||
import("../../build/webrtc.gni")
|
||||
|
||||
declare_args() {
|
||||
# Outputs some low-level debug files.
|
||||
aec_debug_dump = false
|
||||
|
||||
# Disables the usual mode where we trust the reported system delay
|
||||
# values the AEC receives. The corresponding define is set appropriately
|
||||
# in the code, but it can be force-enabled here for testing.
|
||||
aec_untrusted_delay_for_testing = false
|
||||
}
|
||||
|
||||
source_set("audio_processing") {
|
||||
sources = [
|
||||
"aec/aec_core.c",
|
||||
"aec/aec_core.h",
|
||||
"aec/aec_core_internal.h",
|
||||
"aec/aec_rdft.c",
|
||||
"aec/aec_rdft.h",
|
||||
"aec/aec_resampler.c",
|
||||
"aec/aec_resampler.h",
|
||||
"aec/echo_cancellation.c",
|
||||
"aec/echo_cancellation_internal.h",
|
||||
"aec/include/echo_cancellation.h",
|
||||
"aecm/aecm_core.c",
|
||||
"aecm/aecm_core.h",
|
||||
"aecm/echo_control_mobile.c",
|
||||
"aecm/include/echo_control_mobile.h",
|
||||
"agc/agc.cc",
|
||||
"agc/agc.h",
|
||||
"agc/agc_manager_direct.cc",
|
||||
"agc/agc_manager_direct.h",
|
||||
"agc/gain_map_internal.h",
|
||||
"agc/histogram.cc",
|
||||
"agc/histogram.h",
|
||||
"agc/legacy/analog_agc.c",
|
||||
"agc/legacy/analog_agc.h",
|
||||
"agc/legacy/digital_agc.c",
|
||||
"agc/legacy/digital_agc.h",
|
||||
"agc/legacy/gain_control.h",
|
||||
"agc/utility.cc",
|
||||
"agc/utility.h",
|
||||
"audio_buffer.cc",
|
||||
"audio_buffer.h",
|
||||
"audio_processing_impl.cc",
|
||||
"audio_processing_impl.h",
|
||||
"beamformer/beamformer.h",
|
||||
"beamformer/complex_matrix.h",
|
||||
"beamformer/covariance_matrix_generator.cc",
|
||||
"beamformer/covariance_matrix_generator.h",
|
||||
"beamformer/matrix.h",
|
||||
"beamformer/nonlinear_beamformer.cc",
|
||||
"beamformer/nonlinear_beamformer.h",
|
||||
"common.h",
|
||||
"echo_cancellation_impl.cc",
|
||||
"echo_cancellation_impl.h",
|
||||
"echo_control_mobile_impl.cc",
|
||||
"echo_control_mobile_impl.h",
|
||||
"gain_control_impl.cc",
|
||||
"gain_control_impl.h",
|
||||
"high_pass_filter_impl.cc",
|
||||
"high_pass_filter_impl.h",
|
||||
"include/audio_processing.h",
|
||||
"intelligibility/intelligibility_enhancer.cc",
|
||||
"intelligibility/intelligibility_enhancer.h",
|
||||
"intelligibility/intelligibility_utils.cc",
|
||||
"intelligibility/intelligibility_utils.h",
|
||||
"level_estimator_impl.cc",
|
||||
"level_estimator_impl.h",
|
||||
"logging/aec_logging.h",
|
||||
"logging/aec_logging_file_handling.cc",
|
||||
"logging/aec_logging_file_handling.h",
|
||||
"noise_suppression_impl.cc",
|
||||
"noise_suppression_impl.h",
|
||||
"processing_component.cc",
|
||||
"processing_component.h",
|
||||
"rms_level.cc",
|
||||
"rms_level.h",
|
||||
"splitting_filter.cc",
|
||||
"splitting_filter.h",
|
||||
"three_band_filter_bank.cc",
|
||||
"three_band_filter_bank.h",
|
||||
"transient/common.h",
|
||||
"transient/daubechies_8_wavelet_coeffs.h",
|
||||
"transient/dyadic_decimator.h",
|
||||
"transient/moving_moments.cc",
|
||||
"transient/moving_moments.h",
|
||||
"transient/transient_detector.cc",
|
||||
"transient/transient_detector.h",
|
||||
"transient/transient_suppressor.cc",
|
||||
"transient/transient_suppressor.h",
|
||||
"transient/wpd_node.cc",
|
||||
"transient/wpd_node.h",
|
||||
"transient/wpd_tree.cc",
|
||||
"transient/wpd_tree.h",
|
||||
"typing_detection.cc",
|
||||
"typing_detection.h",
|
||||
"utility/delay_estimator.c",
|
||||
"utility/delay_estimator.h",
|
||||
"utility/delay_estimator_internal.h",
|
||||
"utility/delay_estimator_wrapper.c",
|
||||
"utility/delay_estimator_wrapper.h",
|
||||
"vad/common.h",
|
||||
"vad/gmm.cc",
|
||||
"vad/gmm.h",
|
||||
"vad/noise_gmm_tables.h",
|
||||
"vad/pitch_based_vad.cc",
|
||||
"vad/pitch_based_vad.h",
|
||||
"vad/pitch_internal.cc",
|
||||
"vad/pitch_internal.h",
|
||||
"vad/pole_zero_filter.cc",
|
||||
"vad/pole_zero_filter.h",
|
||||
"vad/standalone_vad.cc",
|
||||
"vad/standalone_vad.h",
|
||||
"vad/vad_audio_proc.cc",
|
||||
"vad/vad_audio_proc.h",
|
||||
"vad/vad_audio_proc_internal.h",
|
||||
"vad/vad_circular_buffer.cc",
|
||||
"vad/vad_circular_buffer.h",
|
||||
"vad/voice_activity_detector.cc",
|
||||
"vad/voice_activity_detector.h",
|
||||
"vad/voice_gmm_tables.h",
|
||||
"voice_detection_impl.cc",
|
||||
"voice_detection_impl.h",
|
||||
]
|
||||
|
||||
configs += [ "../..:common_config" ]
|
||||
public_configs = [ "../..:common_inherited_config" ]
|
||||
|
||||
defines = []
|
||||
deps = [
|
||||
"../..:webrtc_common",
|
||||
"../audio_coding:isac",
|
||||
]
|
||||
|
||||
if (aec_debug_dump) {
|
||||
defines += [ "WEBRTC_AEC_DEBUG_DUMP" ]
|
||||
}
|
||||
|
||||
if (aec_untrusted_delay_for_testing) {
|
||||
defines += [ "WEBRTC_UNTRUSTED_DELAY" ]
|
||||
}
|
||||
|
||||
if (rtc_enable_protobuf) {
|
||||
defines += [ "WEBRTC_AUDIOPROC_DEBUG_DUMP" ]
|
||||
deps += [ ":audioproc_debug_proto" ]
|
||||
}
|
||||
|
||||
if (rtc_prefer_fixed_point) {
|
||||
defines += [ "WEBRTC_NS_FIXED" ]
|
||||
sources += [
|
||||
"ns/include/noise_suppression_x.h",
|
||||
"ns/noise_suppression_x.c",
|
||||
"ns/nsx_core.c",
|
||||
"ns/nsx_core.h",
|
||||
"ns/nsx_defines.h",
|
||||
]
|
||||
if (current_cpu == "mipsel") {
|
||||
sources += [ "ns/nsx_core_mips.c" ]
|
||||
} else {
|
||||
sources += [ "ns/nsx_core_c.c" ]
|
||||
}
|
||||
} else {
|
||||
defines += [ "WEBRTC_NS_FLOAT" ]
|
||||
sources += [
|
||||
"ns/defines.h",
|
||||
"ns/include/noise_suppression.h",
|
||||
"ns/noise_suppression.c",
|
||||
"ns/ns_core.c",
|
||||
"ns/ns_core.h",
|
||||
"ns/windows_private.h",
|
||||
]
|
||||
}
|
||||
|
||||
if (current_cpu == "x86" || current_cpu == "x64") {
|
||||
deps += [ ":audio_processing_sse2" ]
|
||||
}
|
||||
|
||||
if (rtc_build_with_neon) {
|
||||
deps += [ ":audio_processing_neon" ]
|
||||
}
|
||||
|
||||
if (current_cpu == "mipsel") {
|
||||
sources += [ "aecm/aecm_core_mips.c" ]
|
||||
if (mips_float_abi == "hard") {
|
||||
sources += [
|
||||
"aec/aec_core_mips.c",
|
||||
"aec/aec_rdft_mips.c",
|
||||
]
|
||||
}
|
||||
} else {
|
||||
sources += [ "aecm/aecm_core_c.c" ]
|
||||
}
|
||||
|
||||
if (is_win) {
|
||||
cflags = [
|
||||
# TODO(jschuh): Bug 1348: fix this warning.
|
||||
"/wd4267", # size_t to int truncations
|
||||
]
|
||||
}
|
||||
|
||||
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" ]
|
||||
}
|
||||
|
||||
deps += [
|
||||
"../../base:rtc_base_approved",
|
||||
"../../common_audio",
|
||||
"../../system_wrappers",
|
||||
]
|
||||
}
|
||||
|
||||
if (rtc_enable_protobuf) {
|
||||
proto_library("audioproc_debug_proto") {
|
||||
sources = [
|
||||
"debug.proto",
|
||||
]
|
||||
|
||||
proto_out_dir = "webrtc/audio_processing"
|
||||
}
|
||||
}
|
||||
|
||||
if (current_cpu == "x86" || current_cpu == "x64") {
|
||||
source_set("audio_processing_sse2") {
|
||||
sources = [
|
||||
"aec/aec_core_sse2.c",
|
||||
"aec/aec_rdft_sse2.c",
|
||||
]
|
||||
|
||||
if (is_posix) {
|
||||
cflags = [ "-msse2" ]
|
||||
}
|
||||
|
||||
configs += [ "../..:common_config" ]
|
||||
public_configs = [ "../..:common_inherited_config" ]
|
||||
}
|
||||
}
|
||||
|
||||
if (rtc_build_with_neon) {
|
||||
source_set("audio_processing_neon") {
|
||||
sources = [
|
||||
"aec/aec_core_neon.c",
|
||||
"aec/aec_rdft_neon.c",
|
||||
"aecm/aecm_core_neon.c",
|
||||
"ns/nsx_core_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" ]
|
||||
|
||||
deps = [
|
||||
"../../common_audio",
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,104 @@
|
||||
SUBDIRS = utility ns aec aecm agc
|
||||
lib_LTLIBRARIES = libwebrtc_audio_processing.la
|
||||
|
||||
if NS_FIXED
|
||||
COMMON_CXXFLAGS += -DWEBRTC_NS_FIXED=1
|
||||
NS_LIB = libns_fix
|
||||
else
|
||||
COMMON_CXXFLAGS += -DWEBRTC_NS_FLOAT=1
|
||||
NS_LIB = libns
|
||||
endif
|
||||
|
||||
webrtcincludedir = $(includedir)/webrtc_audio_processing
|
||||
webrtcinclude_HEADERS = $(top_srcdir)/src/typedefs.h \
|
||||
$(top_srcdir)/src/modules/interface/module.h \
|
||||
interface/audio_processing.h \
|
||||
$(top_srcdir)/src/common_types.h \
|
||||
$(top_srcdir)/src/modules/interface/module_common_types.h
|
||||
webrtcinclude_HEADERS = $(top_srcdir)/webrtc/base/arraysize.h \
|
||||
$(top_srcdir)/webrtc/base/platform_file.h \
|
||||
$(top_srcdir)/webrtc/common.h \
|
||||
$(top_srcdir)/webrtc/typedefs.h \
|
||||
$(top_srcdir)/webrtc/modules/audio_processing/beamformer/array_util.h \
|
||||
include/audio_processing.h
|
||||
|
||||
libwebrtc_audio_processing_la_SOURCES = interface/audio_processing.h \
|
||||
libwebrtc_audio_processing_la_SOURCES = include/audio_processing.h \
|
||||
aec/include/echo_cancellation.h \
|
||||
aec/aec_common.h \
|
||||
aec/aec_core.c \
|
||||
aec/aec_core.h \
|
||||
aec/aec_core_internal.h \
|
||||
aec/aec_core_sse2.c \
|
||||
aec/aec_rdft.c \
|
||||
aec/aec_rdft.h \
|
||||
aec/aec_rdft_sse2.c \
|
||||
aec/aec_resampler.c \
|
||||
aec/aec_resampler.h \
|
||||
aec/echo_cancellation.c \
|
||||
aec/echo_cancellation_internal.h \
|
||||
aecm/include/echo_control_mobile.h \
|
||||
aecm/echo_control_mobile.c \
|
||||
aecm/aecm_core.c \
|
||||
aecm/aecm_core.h \
|
||||
aecm/aecm_core_c.c \
|
||||
agc/legacy/analog_agc.c \
|
||||
agc/legacy/analog_agc.h \
|
||||
agc/legacy/gain_control.h \
|
||||
agc/legacy/digital_agc.c \
|
||||
agc/legacy/digital_agc.h \
|
||||
agc/agc.cc \
|
||||
agc/agc.h \
|
||||
agc/agc_manager_direct.cc \
|
||||
agc/agc_manager_direct.h \
|
||||
agc/gain_map_internal.h \
|
||||
agc/histogram.cc \
|
||||
agc/histogram.h \
|
||||
agc/utility.cc \
|
||||
agc/utility.h \
|
||||
beamformer/array_util.h \
|
||||
beamformer/beamformer.h \
|
||||
beamformer/complex_matrix.h \
|
||||
beamformer/covariance_matrix_generator.h \
|
||||
beamformer/matrix.h \
|
||||
beamformer/matrix_test_helpers.h \
|
||||
beamformer/nonlinear_beamformer.h \
|
||||
beamformer/covariance_matrix_generator.cc \
|
||||
beamformer/nonlinear_beamformer.cc \
|
||||
logging/aec_logging.h \
|
||||
logging/aec_logging_file_handling.h \
|
||||
logging/aec_logging_file_handling.cc \
|
||||
transient/common.h \
|
||||
transient/daubechies_8_wavelet_coeffs.h \
|
||||
transient/dyadic_decimator.h \
|
||||
transient/file_utils.h \
|
||||
transient/moving_moments.h \
|
||||
transient/transient_detector.h \
|
||||
transient/transient_suppressor.h \
|
||||
transient/wpd_node.h \
|
||||
transient/wpd_tree.h \
|
||||
transient/click_annotate.cc \
|
||||
transient/file_utils.cc \
|
||||
transient/moving_moments.cc \
|
||||
transient/transient_detector.cc \
|
||||
transient/transient_suppressor.cc \
|
||||
transient/wpd_node.cc \
|
||||
transient/wpd_tree.cc \
|
||||
utility/delay_estimator.c \
|
||||
utility/delay_estimator.h \
|
||||
utility/delay_estimator_internal.h \
|
||||
utility/delay_estimator_wrapper.c \
|
||||
utility/delay_estimator_wrapper.h \
|
||||
vad/common.h \
|
||||
vad/gmm.h \
|
||||
vad/noise_gmm_tables.h \
|
||||
vad/pitch_based_vad.h \
|
||||
vad/pitch_internal.h \
|
||||
vad/pole_zero_filter.h \
|
||||
vad/standalone_vad.h \
|
||||
vad/vad_audio_proc.h \
|
||||
vad/vad_audio_proc_internal.h \
|
||||
vad/vad_circular_buffer.h \
|
||||
vad/voice_activity_detector.h \
|
||||
vad/voice_gmm_tables.h \
|
||||
vad/gmm.cc \
|
||||
vad/pitch_based_vad.cc \
|
||||
vad/pitch_internal.cc \
|
||||
vad/pole_zero_filter.cc \
|
||||
vad/standalone_vad.cc \
|
||||
vad/vad_audio_proc.cc \
|
||||
vad/vad_circular_buffer.cc \
|
||||
vad/voice_activity_detector.cc \
|
||||
audio_buffer.cc \
|
||||
audio_buffer.h \
|
||||
audio_processing_impl.cc \
|
||||
audio_processing_impl.h \
|
||||
common.h \
|
||||
echo_cancellation_impl.cc \
|
||||
echo_cancellation_impl.h \
|
||||
echo_control_mobile_impl.cc \
|
||||
@@ -33,27 +111,56 @@ libwebrtc_audio_processing_la_SOURCES = interface/audio_processing.h \
|
||||
level_estimator_impl.h \
|
||||
noise_suppression_impl.cc \
|
||||
noise_suppression_impl.h \
|
||||
rms_level.cc \
|
||||
rms_level.h \
|
||||
splitting_filter.cc \
|
||||
splitting_filter.h \
|
||||
processing_component.cc \
|
||||
processing_component.h \
|
||||
three_band_filter_bank.cc \
|
||||
three_band_filter_bank.h \
|
||||
typing_detection.cc \
|
||||
typing_detection.h \
|
||||
voice_detection_impl.cc \
|
||||
voice_detection_impl.h
|
||||
libwebrtc_audio_processing_la_CXXFLAGS = $(AM_CXXFLAGS) $(COMMON_CXXFLAGS) \
|
||||
-I$(top_srcdir)/src/common_audio/signal_processing_library/main/interface \
|
||||
-I$(top_srcdir)/src/common_audio/vad/main/interface \
|
||||
-I$(top_srcdir)/src/system_wrappers/interface \
|
||||
-I$(top_srcdir)/src/modules/audio_processing/utility \
|
||||
-I$(top_srcdir)/src/modules/audio_processing/ns/interface \
|
||||
-I$(top_srcdir)/src/modules/audio_processing/aec/interface \
|
||||
-I$(top_srcdir)/src/modules/audio_processing/aecm/interface \
|
||||
-I$(top_srcdir)/src/modules/audio_processing/agc/interface
|
||||
libwebrtc_audio_processing_la_LIBADD = $(top_builddir)/src/system_wrappers/libsystem_wrappers.la \
|
||||
$(top_builddir)/src/common_audio/signal_processing_library/libspl.la \
|
||||
$(top_builddir)/src/common_audio/vad/libvad.la \
|
||||
$(top_builddir)/src/modules/audio_processing/utility/libapm_util.la \
|
||||
$(top_builddir)/src/modules/audio_processing/ns/$(NS_LIB).la \
|
||||
$(top_builddir)/src/modules/audio_processing/aec/libaec.la \
|
||||
$(top_builddir)/src/modules/audio_processing/aecm/libaecm.la \
|
||||
$(top_builddir)/src/modules/audio_processing/agc/libagc.la
|
||||
|
||||
if NS_FIXED
|
||||
COMMON_CXXFLAGS += -DWEBRTC_NS_FIXED=0
|
||||
libwebrtc_audio_processing_la_SOURCES += \
|
||||
ns/include/noise_suppression_x.h \
|
||||
ns/noise_suppression_x.c \
|
||||
ns/nsx_defines.h \
|
||||
ns/nsx_core.c \
|
||||
ns/nsx_core.h \
|
||||
ns/nsx_core_c.c
|
||||
else
|
||||
COMMON_CXXFLAGS += -DWEBRTC_NS_FIXED=1
|
||||
libwebrtc_audio_processing_la_SOURCES += \
|
||||
ns/include/noise_suppression.h \
|
||||
ns/noise_suppression.c \
|
||||
ns/defines.h \
|
||||
ns/ns_core.c \
|
||||
ns/ns_core.h \
|
||||
ns/windows_private.h
|
||||
endif
|
||||
|
||||
libwebrtc_audio_processing_la_CFLAGS = $(AM_CFLAGS) $(COMMON_CFLAGS)
|
||||
libwebrtc_audio_processing_la_CXXFLAGS = $(AM_CXXFLAGS) $(COMMON_CXXFLAGS)
|
||||
|
||||
libwebrtc_audio_processing_la_LIBADD = $(top_builddir)/webrtc/base/libbase.la \
|
||||
$(top_builddir)/webrtc/system_wrappers/libsystem_wrappers.la \
|
||||
$(top_builddir)/webrtc/common_audio/libcommon_audio.la
|
||||
$(top_builddir)/webrtc/modules/audio_coding/libaudio_coding.la
|
||||
libwebrtc_audio_processing_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(LIBWEBRTC_AUDIO_PROCESSING_VERSION_INFO)
|
||||
|
||||
# FIXME:
|
||||
# x86: aec/aec_core_sse2.c
|
||||
# aec/aec_rdft_sse2.c
|
||||
# NEON: aec/aec_core_neon.c
|
||||
# aec/aec_rdft_neon.c
|
||||
# aecm/aecm_core_neon.c
|
||||
# ns/nsx_core_neon.c
|
||||
# MIPS: aec/aec_core_mips.c
|
||||
# aec/aec_rdft_neon.c
|
||||
# aecm/aecm_core_mips.c
|
||||
# ns/nsx_core_mips.c
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
andrew@webrtc.org
|
||||
bjornv@webrtc.org
|
||||
@@ -1,16 +0,0 @@
|
||||
noinst_LTLIBRARIES = libaec.la
|
||||
|
||||
libaec_la_SOURCES = interface/echo_cancellation.h \
|
||||
echo_cancellation.c \
|
||||
aec_core.h \
|
||||
aec_core.c \
|
||||
aec_core_sse2.c \
|
||||
aec_rdft.h \
|
||||
aec_rdft.c \
|
||||
aec_rdft_sse2.c \
|
||||
resampler.h \
|
||||
resampler.c
|
||||
libaec_la_CFLAGS = $(AM_CFLAGS) $(COMMON_CFLAGS) \
|
||||
-I$(top_srcdir)/src/common_audio/signal_processing_library/main/interface \
|
||||
-I$(top_srcdir)/src/system_wrappers/interface \
|
||||
-I$(top_srcdir)/src/modules/audio_processing/utility
|
||||
@@ -1,40 +0,0 @@
|
||||
# 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.
|
||||
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'aec',
|
||||
'type': '<(library)',
|
||||
'dependencies': [
|
||||
'<(webrtc_root)/common_audio/common_audio.gyp:spl',
|
||||
'apm_util'
|
||||
],
|
||||
'include_dirs': [
|
||||
'interface',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'interface',
|
||||
],
|
||||
},
|
||||
'sources': [
|
||||
'interface/echo_cancellation.h',
|
||||
'echo_cancellation.c',
|
||||
'aec_core.h',
|
||||
'aec_core.c',
|
||||
'aec_core_sse2.c',
|
||||
'aec_rdft.h',
|
||||
'aec_rdft.c',
|
||||
'aec_rdft_sse2.c',
|
||||
'resampler.h',
|
||||
'resampler.c',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
32
webrtc/modules/audio_processing/aec/aec_common.h
Normal file
32
webrtc/modules/audio_processing/aec/aec_common.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_COMMON_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_COMMON_H_
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
#ifdef _MSC_VER /* visual c++ */
|
||||
#define ALIGN16_BEG __declspec(align(16))
|
||||
#define ALIGN16_END
|
||||
#else /* gcc or icc */
|
||||
#define ALIGN16_BEG
|
||||
#define ALIGN16_END __attribute__((aligned(16)))
|
||||
#endif
|
||||
|
||||
extern ALIGN16_BEG const float ALIGN16_END WebRtcAec_sqrtHanning[65];
|
||||
extern ALIGN16_BEG const float ALIGN16_END WebRtcAec_weightCurve[65];
|
||||
extern ALIGN16_BEG const float ALIGN16_END WebRtcAec_overDriveCurve[65];
|
||||
extern const float WebRtcAec_kExtendedSmoothingCoefficients[2][2];
|
||||
extern const float WebRtcAec_kNormalSmoothingCoefficients[2][2];
|
||||
extern const float WebRtcAec_kMinFarendPSD;
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_COMMON_H_
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
* 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
|
||||
@@ -12,29 +12,18 @@
|
||||
* Specifies the interface for the AEC core.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_CORE_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_CORE_H_
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "signal_processing_library.h"
|
||||
#include "typedefs.h"
|
||||
|
||||
//#define AEC_DEBUG // for recording files
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
#define FRAME_LEN 80
|
||||
#define PART_LEN 64 // Length of partition
|
||||
#define PART_LEN1 (PART_LEN + 1) // Unique fft coefficients
|
||||
#define PART_LEN2 (PART_LEN * 2) // Length of partition * 2
|
||||
#define NR_PART 12 // Number of partitions
|
||||
#define FILT_LEN (PART_LEN * NR_PART) // Filter length
|
||||
#define FILT_LEN2 (FILT_LEN * 2) // Double filter length
|
||||
#define FAR_BUF_LEN (FILT_LEN2 * 2)
|
||||
#define PREF_BAND_SIZE 24
|
||||
|
||||
#define BLOCKL_MAX FRAME_LEN
|
||||
// Maximum delay in fixed point delay estimator, used for logging
|
||||
enum {kMaxDelay = 100};
|
||||
#define PART_LEN 64 // Length of partition
|
||||
#define PART_LEN1 (PART_LEN + 1) // Unique fft coefficients
|
||||
#define PART_LEN2 (PART_LEN * 2) // Length of partition * 2
|
||||
#define NUM_HIGH_BANDS_MAX 2 // Max number of high bands
|
||||
|
||||
typedef float complex_t[2];
|
||||
// For performance reasons, some arrays of complex numbers are replaced by twice
|
||||
@@ -46,136 +35,95 @@ typedef float complex_t[2];
|
||||
// compile time.
|
||||
|
||||
// Metrics
|
||||
enum {offsetLevel = -100};
|
||||
enum {
|
||||
kOffsetLevel = -100
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
float sfrsum;
|
||||
int sfrcounter;
|
||||
float framelevel;
|
||||
float frsum;
|
||||
int frcounter;
|
||||
float minlevel;
|
||||
float averagelevel;
|
||||
} power_level_t;
|
||||
typedef struct Stats {
|
||||
float instant;
|
||||
float average;
|
||||
float min;
|
||||
float max;
|
||||
float sum;
|
||||
float hisum;
|
||||
float himean;
|
||||
int counter;
|
||||
int hicounter;
|
||||
} Stats;
|
||||
|
||||
typedef struct {
|
||||
float instant;
|
||||
float average;
|
||||
float min;
|
||||
float max;
|
||||
float sum;
|
||||
float hisum;
|
||||
float himean;
|
||||
int counter;
|
||||
int hicounter;
|
||||
} stats_t;
|
||||
typedef struct AecCore AecCore;
|
||||
|
||||
typedef struct {
|
||||
int farBufWritePos, farBufReadPos;
|
||||
|
||||
int knownDelay;
|
||||
int inSamples, outSamples;
|
||||
int delayEstCtr;
|
||||
|
||||
void *farFrBuf, *nearFrBuf, *outFrBuf;
|
||||
|
||||
void *nearFrBufH;
|
||||
void *outFrBufH;
|
||||
|
||||
float xBuf[PART_LEN2]; // farend
|
||||
float dBuf[PART_LEN2]; // nearend
|
||||
float eBuf[PART_LEN2]; // error
|
||||
|
||||
float dBufH[PART_LEN2]; // nearend
|
||||
|
||||
float xPow[PART_LEN1];
|
||||
float dPow[PART_LEN1];
|
||||
float dMinPow[PART_LEN1];
|
||||
float dInitMinPow[PART_LEN1];
|
||||
float *noisePow;
|
||||
|
||||
float xfBuf[2][NR_PART * PART_LEN1]; // farend fft buffer
|
||||
float wfBuf[2][NR_PART * PART_LEN1]; // filter fft
|
||||
complex_t sde[PART_LEN1]; // cross-psd of nearend and error
|
||||
complex_t sxd[PART_LEN1]; // cross-psd of farend and nearend
|
||||
complex_t xfwBuf[NR_PART * PART_LEN1]; // farend windowed fft buffer
|
||||
|
||||
float sx[PART_LEN1], sd[PART_LEN1], se[PART_LEN1]; // far, near and error psd
|
||||
float hNs[PART_LEN1];
|
||||
float hNlFbMin, hNlFbLocalMin;
|
||||
float hNlXdAvgMin;
|
||||
int hNlNewMin, hNlMinCtr;
|
||||
float overDrive, overDriveSm;
|
||||
float targetSupp, minOverDrive;
|
||||
float outBuf[PART_LEN];
|
||||
int delayIdx;
|
||||
|
||||
short stNearState, echoState;
|
||||
short divergeState;
|
||||
|
||||
int xfBufBlockPos;
|
||||
|
||||
short farBuf[FILT_LEN2 * 2];
|
||||
|
||||
short mult; // sampling frequency multiple
|
||||
int sampFreq;
|
||||
WebRtc_UWord32 seed;
|
||||
|
||||
float mu; // stepsize
|
||||
float errThresh; // error threshold
|
||||
|
||||
int noiseEstCtr;
|
||||
|
||||
power_level_t farlevel;
|
||||
power_level_t nearlevel;
|
||||
power_level_t linoutlevel;
|
||||
power_level_t nlpoutlevel;
|
||||
|
||||
int metricsMode;
|
||||
int stateCounter;
|
||||
stats_t erl;
|
||||
stats_t erle;
|
||||
stats_t aNlp;
|
||||
stats_t rerl;
|
||||
|
||||
// Quantities to control H band scaling for SWB input
|
||||
int freq_avg_ic; //initial bin for averaging nlp gain
|
||||
int flag_Hband_cn; //for comfort noise
|
||||
float cn_scale_Hband; //scale for comfort noise in H band
|
||||
|
||||
int delay_histogram[kMaxDelay];
|
||||
int delay_logging_enabled;
|
||||
void* delay_estimator;
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
FILE *farFile;
|
||||
FILE *nearFile;
|
||||
FILE *outFile;
|
||||
FILE *outLpFile;
|
||||
#endif
|
||||
} aec_t;
|
||||
|
||||
typedef void (*WebRtcAec_FilterFar_t)(aec_t *aec, float yf[2][PART_LEN1]);
|
||||
extern WebRtcAec_FilterFar_t WebRtcAec_FilterFar;
|
||||
typedef void (*WebRtcAec_ScaleErrorSignal_t)(aec_t *aec, float ef[2][PART_LEN1]);
|
||||
extern WebRtcAec_ScaleErrorSignal_t WebRtcAec_ScaleErrorSignal;
|
||||
typedef void (*WebRtcAec_FilterAdaptation_t)
|
||||
(aec_t *aec, float *fft, float ef[2][PART_LEN1]);
|
||||
extern WebRtcAec_FilterAdaptation_t WebRtcAec_FilterAdaptation;
|
||||
typedef void (*WebRtcAec_OverdriveAndSuppress_t)
|
||||
(aec_t *aec, float hNl[PART_LEN1], const float hNlFb, float efw[2][PART_LEN1]);
|
||||
extern WebRtcAec_OverdriveAndSuppress_t WebRtcAec_OverdriveAndSuppress;
|
||||
|
||||
int WebRtcAec_CreateAec(aec_t **aec);
|
||||
int WebRtcAec_FreeAec(aec_t *aec);
|
||||
int WebRtcAec_InitAec(aec_t *aec, int sampFreq);
|
||||
AecCore* WebRtcAec_CreateAec(); // Returns NULL on error.
|
||||
void WebRtcAec_FreeAec(AecCore* aec);
|
||||
int WebRtcAec_InitAec(AecCore* aec, int sampFreq);
|
||||
void WebRtcAec_InitAec_SSE2(void);
|
||||
#if defined(MIPS_FPU_LE)
|
||||
void WebRtcAec_InitAec_mips(void);
|
||||
#endif
|
||||
#if defined(WEBRTC_DETECT_NEON) || defined(WEBRTC_HAS_NEON)
|
||||
void WebRtcAec_InitAec_neon(void);
|
||||
#endif
|
||||
|
||||
void WebRtcAec_InitMetrics(aec_t *aec);
|
||||
void WebRtcAec_ProcessFrame(aec_t *aec, const short *farend,
|
||||
const short *nearend, const short *nearendH,
|
||||
short *out, short *outH,
|
||||
int knownDelay);
|
||||
void WebRtcAec_BufferFarendPartition(AecCore* aec, const float* farend);
|
||||
void WebRtcAec_ProcessFrames(AecCore* aec,
|
||||
const float* const* nearend,
|
||||
size_t num_bands,
|
||||
size_t num_samples,
|
||||
int knownDelay,
|
||||
float* const* out);
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_CORE_H_
|
||||
// A helper function to call WebRtc_MoveReadPtr() for all far-end buffers.
|
||||
// Returns the number of elements moved, and adjusts |system_delay| by the
|
||||
// corresponding amount in ms.
|
||||
int WebRtcAec_MoveFarReadPtr(AecCore* aec, int elements);
|
||||
|
||||
// Calculates the median, standard deviation and amount of poor values among the
|
||||
// delay estimates aggregated up to the first call to the function. After that
|
||||
// first call the metrics are aggregated and updated every second. With poor
|
||||
// values we mean values that most likely will cause the AEC to perform poorly.
|
||||
// TODO(bjornv): Consider changing tests and tools to handle constant
|
||||
// constant aggregation window throughout the session instead.
|
||||
int WebRtcAec_GetDelayMetricsCore(AecCore* self, int* median, int* std,
|
||||
float* fraction_poor_delays);
|
||||
|
||||
// Returns the echo state (1: echo, 0: no echo).
|
||||
int WebRtcAec_echo_state(AecCore* self);
|
||||
|
||||
// Gets statistics of the echo metrics ERL, ERLE, A_NLP.
|
||||
void WebRtcAec_GetEchoStats(AecCore* self,
|
||||
Stats* erl,
|
||||
Stats* erle,
|
||||
Stats* a_nlp);
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
void* WebRtcAec_far_time_buf(AecCore* self);
|
||||
#endif
|
||||
|
||||
// Sets local configuration modes.
|
||||
void WebRtcAec_SetConfigCore(AecCore* self,
|
||||
int nlp_mode,
|
||||
int metrics_mode,
|
||||
int delay_logging);
|
||||
|
||||
// Non-zero enables, zero disables.
|
||||
void WebRtcAec_enable_delay_agnostic(AecCore* self, int enable);
|
||||
|
||||
// Returns non-zero if delay agnostic (i.e., signal based delay estimation) is
|
||||
// enabled and zero if disabled.
|
||||
int WebRtcAec_delay_agnostic_enabled(AecCore* self);
|
||||
|
||||
// Enables or disables extended filter mode. Non-zero enables, zero disables.
|
||||
void WebRtcAec_enable_extended_filter(AecCore* self, int enable);
|
||||
|
||||
// Returns non-zero if extended filter mode is enabled and zero if disabled.
|
||||
int WebRtcAec_extended_filter_enabled(AecCore* self);
|
||||
|
||||
// Returns the current |system_delay|, i.e., the buffered difference between
|
||||
// far-end and near-end.
|
||||
int WebRtcAec_system_delay(AecCore* self);
|
||||
|
||||
// Sets the |system_delay| to |value|. Note that if the value is changed
|
||||
// improperly, there can be a performance regression. So it should be used with
|
||||
// care.
|
||||
void WebRtcAec_SetSystemDelay(AecCore* self, int delay);
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_H_
|
||||
|
||||
202
webrtc/modules/audio_processing/aec/aec_core_internal.h
Normal file
202
webrtc/modules/audio_processing/aec/aec_core_internal.h
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_INTERNAL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_INTERNAL_H_
|
||||
|
||||
#include "webrtc/common_audio/ring_buffer.h"
|
||||
#include "webrtc/common_audio/wav_file.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_common.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_core.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// Number of partitions for the extended filter mode. The first one is an enum
|
||||
// to be used in array declarations, as it represents the maximum filter length.
|
||||
enum {
|
||||
kExtendedNumPartitions = 32
|
||||
};
|
||||
static const int kNormalNumPartitions = 12;
|
||||
|
||||
// Delay estimator constants, used for logging and delay compensation if
|
||||
// if reported delays are disabled.
|
||||
enum {
|
||||
kLookaheadBlocks = 15
|
||||
};
|
||||
enum {
|
||||
// 500 ms for 16 kHz which is equivalent with the limit of reported delays.
|
||||
kHistorySizeBlocks = 125
|
||||
};
|
||||
|
||||
// Extended filter adaptation parameters.
|
||||
// TODO(ajm): No narrowband tuning yet.
|
||||
static const float kExtendedMu = 0.4f;
|
||||
static const float kExtendedErrorThreshold = 1.0e-6f;
|
||||
|
||||
typedef struct PowerLevel {
|
||||
float sfrsum;
|
||||
int sfrcounter;
|
||||
float framelevel;
|
||||
float frsum;
|
||||
int frcounter;
|
||||
float minlevel;
|
||||
float averagelevel;
|
||||
} PowerLevel;
|
||||
|
||||
struct AecCore {
|
||||
int farBufWritePos, farBufReadPos;
|
||||
|
||||
int knownDelay;
|
||||
int inSamples, outSamples;
|
||||
int delayEstCtr;
|
||||
|
||||
RingBuffer* nearFrBuf;
|
||||
RingBuffer* outFrBuf;
|
||||
|
||||
RingBuffer* nearFrBufH[NUM_HIGH_BANDS_MAX];
|
||||
RingBuffer* outFrBufH[NUM_HIGH_BANDS_MAX];
|
||||
|
||||
float dBuf[PART_LEN2]; // nearend
|
||||
float eBuf[PART_LEN2]; // error
|
||||
|
||||
float dBufH[NUM_HIGH_BANDS_MAX][PART_LEN2]; // nearend
|
||||
|
||||
float xPow[PART_LEN1];
|
||||
float dPow[PART_LEN1];
|
||||
float dMinPow[PART_LEN1];
|
||||
float dInitMinPow[PART_LEN1];
|
||||
float* noisePow;
|
||||
|
||||
float xfBuf[2][kExtendedNumPartitions * PART_LEN1]; // farend fft buffer
|
||||
float wfBuf[2][kExtendedNumPartitions * PART_LEN1]; // filter fft
|
||||
complex_t sde[PART_LEN1]; // cross-psd of nearend and error
|
||||
complex_t sxd[PART_LEN1]; // cross-psd of farend and nearend
|
||||
// Farend windowed fft buffer.
|
||||
complex_t xfwBuf[kExtendedNumPartitions * PART_LEN1];
|
||||
|
||||
float sx[PART_LEN1], sd[PART_LEN1], se[PART_LEN1]; // far, near, error psd
|
||||
float hNs[PART_LEN1];
|
||||
float hNlFbMin, hNlFbLocalMin;
|
||||
float hNlXdAvgMin;
|
||||
int hNlNewMin, hNlMinCtr;
|
||||
float overDrive, overDriveSm;
|
||||
int nlp_mode;
|
||||
float outBuf[PART_LEN];
|
||||
int delayIdx;
|
||||
|
||||
short stNearState, echoState;
|
||||
short divergeState;
|
||||
|
||||
int xfBufBlockPos;
|
||||
|
||||
RingBuffer* far_buf;
|
||||
RingBuffer* far_buf_windowed;
|
||||
int system_delay; // Current system delay buffered in AEC.
|
||||
|
||||
int mult; // sampling frequency multiple
|
||||
int sampFreq;
|
||||
size_t num_bands;
|
||||
uint32_t seed;
|
||||
|
||||
float normal_mu; // stepsize
|
||||
float normal_error_threshold; // error threshold
|
||||
|
||||
int noiseEstCtr;
|
||||
|
||||
PowerLevel farlevel;
|
||||
PowerLevel nearlevel;
|
||||
PowerLevel linoutlevel;
|
||||
PowerLevel nlpoutlevel;
|
||||
|
||||
int metricsMode;
|
||||
int stateCounter;
|
||||
Stats erl;
|
||||
Stats erle;
|
||||
Stats aNlp;
|
||||
Stats rerl;
|
||||
|
||||
// Quantities to control H band scaling for SWB input
|
||||
int freq_avg_ic; // initial bin for averaging nlp gain
|
||||
int flag_Hband_cn; // for comfort noise
|
||||
float cn_scale_Hband; // scale for comfort noise in H band
|
||||
|
||||
int delay_metrics_delivered;
|
||||
int delay_histogram[kHistorySizeBlocks];
|
||||
int num_delay_values;
|
||||
int delay_median;
|
||||
int delay_std;
|
||||
float fraction_poor_delays;
|
||||
int delay_logging_enabled;
|
||||
void* delay_estimator_farend;
|
||||
void* delay_estimator;
|
||||
// Variables associated with delay correction through signal based delay
|
||||
// estimation feedback.
|
||||
int signal_delay_correction;
|
||||
int previous_delay;
|
||||
int delay_correction_count;
|
||||
int shift_offset;
|
||||
float delay_quality_threshold;
|
||||
int frame_count;
|
||||
|
||||
// 0 = delay agnostic mode (signal based delay correction) disabled.
|
||||
// Otherwise enabled.
|
||||
int delay_agnostic_enabled;
|
||||
// 1 = extended filter mode enabled, 0 = disabled.
|
||||
int extended_filter_enabled;
|
||||
// Runtime selection of number of filter partitions.
|
||||
int num_partitions;
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
// Sequence number of this AEC instance, so that different instances can
|
||||
// choose different dump file names.
|
||||
int instance_index;
|
||||
|
||||
// Number of times we've restarted dumping; used to pick new dump file names
|
||||
// each time.
|
||||
int debug_dump_count;
|
||||
|
||||
RingBuffer* far_time_buf;
|
||||
rtc_WavWriter* farFile;
|
||||
rtc_WavWriter* nearFile;
|
||||
rtc_WavWriter* outFile;
|
||||
rtc_WavWriter* outLinearFile;
|
||||
FILE* e_fft_file;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef void (*WebRtcAecFilterFar)(AecCore* aec, float yf[2][PART_LEN1]);
|
||||
extern WebRtcAecFilterFar WebRtcAec_FilterFar;
|
||||
typedef void (*WebRtcAecScaleErrorSignal)(AecCore* aec, float ef[2][PART_LEN1]);
|
||||
extern WebRtcAecScaleErrorSignal WebRtcAec_ScaleErrorSignal;
|
||||
typedef void (*WebRtcAecFilterAdaptation)(AecCore* aec,
|
||||
float* fft,
|
||||
float ef[2][PART_LEN1]);
|
||||
extern WebRtcAecFilterAdaptation WebRtcAec_FilterAdaptation;
|
||||
typedef void (*WebRtcAecOverdriveAndSuppress)(AecCore* aec,
|
||||
float hNl[PART_LEN1],
|
||||
const float hNlFb,
|
||||
float efw[2][PART_LEN1]);
|
||||
extern WebRtcAecOverdriveAndSuppress WebRtcAec_OverdriveAndSuppress;
|
||||
|
||||
typedef void (*WebRtcAecComfortNoise)(AecCore* aec,
|
||||
float efw[2][PART_LEN1],
|
||||
complex_t* comfortNoiseHband,
|
||||
const float* noisePow,
|
||||
const float* lambda);
|
||||
extern WebRtcAecComfortNoise WebRtcAec_ComfortNoise;
|
||||
|
||||
typedef void (*WebRtcAecSubBandCoherence)(AecCore* aec,
|
||||
float efw[2][PART_LEN1],
|
||||
float xfw[2][PART_LEN1],
|
||||
float* fft,
|
||||
float* cohde,
|
||||
float* cohxd);
|
||||
extern WebRtcAecSubBandCoherence WebRtcAec_SubbandCoherence;
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_INTERNAL_H_
|
||||
774
webrtc/modules/audio_processing/aec/aec_core_mips.c
Normal file
774
webrtc/modules/audio_processing/aec/aec_core_mips.c
Normal file
@@ -0,0 +1,774 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The core AEC algorithm, which is presented with time-aligned signals.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/audio_processing/aec/aec_core.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_core_internal.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_rdft.h"
|
||||
|
||||
static const int flagHbandCn = 1; // flag for adding comfort noise in H band
|
||||
extern const float WebRtcAec_weightCurve[65];
|
||||
extern const float WebRtcAec_overDriveCurve[65];
|
||||
|
||||
void WebRtcAec_ComfortNoise_mips(AecCore* aec,
|
||||
float efw[2][PART_LEN1],
|
||||
complex_t* comfortNoiseHband,
|
||||
const float* noisePow,
|
||||
const float* lambda) {
|
||||
int i, num;
|
||||
float rand[PART_LEN];
|
||||
float noise, noiseAvg, tmp, tmpAvg;
|
||||
int16_t randW16[PART_LEN];
|
||||
complex_t u[PART_LEN1];
|
||||
|
||||
const float pi2 = 6.28318530717959f;
|
||||
const float pi2t = pi2 / 32768;
|
||||
|
||||
// Generate a uniform random array on [0 1]
|
||||
WebRtcSpl_RandUArray(randW16, PART_LEN, &aec->seed);
|
||||
|
||||
int16_t* randWptr = randW16;
|
||||
float randTemp, randTemp2, randTemp3, randTemp4;
|
||||
int32_t tmp1s, tmp2s, tmp3s, tmp4s;
|
||||
|
||||
for (i = 0; i < PART_LEN; i+=4) {
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"lh %[tmp1s], 0(%[randWptr]) \n\t"
|
||||
"lh %[tmp2s], 2(%[randWptr]) \n\t"
|
||||
"lh %[tmp3s], 4(%[randWptr]) \n\t"
|
||||
"lh %[tmp4s], 6(%[randWptr]) \n\t"
|
||||
"mtc1 %[tmp1s], %[randTemp] \n\t"
|
||||
"mtc1 %[tmp2s], %[randTemp2] \n\t"
|
||||
"mtc1 %[tmp3s], %[randTemp3] \n\t"
|
||||
"mtc1 %[tmp4s], %[randTemp4] \n\t"
|
||||
"cvt.s.w %[randTemp], %[randTemp] \n\t"
|
||||
"cvt.s.w %[randTemp2], %[randTemp2] \n\t"
|
||||
"cvt.s.w %[randTemp3], %[randTemp3] \n\t"
|
||||
"cvt.s.w %[randTemp4], %[randTemp4] \n\t"
|
||||
"addiu %[randWptr], %[randWptr], 8 \n\t"
|
||||
"mul.s %[randTemp], %[randTemp], %[pi2t] \n\t"
|
||||
"mul.s %[randTemp2], %[randTemp2], %[pi2t] \n\t"
|
||||
"mul.s %[randTemp3], %[randTemp3], %[pi2t] \n\t"
|
||||
"mul.s %[randTemp4], %[randTemp4], %[pi2t] \n\t"
|
||||
".set pop \n\t"
|
||||
: [randWptr] "+r" (randWptr), [randTemp] "=&f" (randTemp),
|
||||
[randTemp2] "=&f" (randTemp2), [randTemp3] "=&f" (randTemp3),
|
||||
[randTemp4] "=&f" (randTemp4), [tmp1s] "=&r" (tmp1s),
|
||||
[tmp2s] "=&r" (tmp2s), [tmp3s] "=&r" (tmp3s),
|
||||
[tmp4s] "=&r" (tmp4s)
|
||||
: [pi2t] "f" (pi2t)
|
||||
: "memory"
|
||||
);
|
||||
|
||||
u[i+1][0] = cosf(randTemp);
|
||||
u[i+1][1] = sinf(randTemp);
|
||||
u[i+2][0] = cosf(randTemp2);
|
||||
u[i+2][1] = sinf(randTemp2);
|
||||
u[i+3][0] = cosf(randTemp3);
|
||||
u[i+3][1] = sinf(randTemp3);
|
||||
u[i+4][0] = cosf(randTemp4);
|
||||
u[i+4][1] = sinf(randTemp4);
|
||||
}
|
||||
|
||||
// Reject LF noise
|
||||
float* u_ptr = &u[1][0];
|
||||
float noise2, noise3, noise4;
|
||||
float tmp1f, tmp2f, tmp3f, tmp4f, tmp5f, tmp6f, tmp7f, tmp8f;
|
||||
|
||||
u[0][0] = 0;
|
||||
u[0][1] = 0;
|
||||
for (i = 1; i < PART_LEN1; i+=4) {
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"lwc1 %[noise], 4(%[noisePow]) \n\t"
|
||||
"lwc1 %[noise2], 8(%[noisePow]) \n\t"
|
||||
"lwc1 %[noise3], 12(%[noisePow]) \n\t"
|
||||
"lwc1 %[noise4], 16(%[noisePow]) \n\t"
|
||||
"sqrt.s %[noise], %[noise] \n\t"
|
||||
"sqrt.s %[noise2], %[noise2] \n\t"
|
||||
"sqrt.s %[noise3], %[noise3] \n\t"
|
||||
"sqrt.s %[noise4], %[noise4] \n\t"
|
||||
"lwc1 %[tmp1f], 0(%[u_ptr]) \n\t"
|
||||
"lwc1 %[tmp2f], 4(%[u_ptr]) \n\t"
|
||||
"lwc1 %[tmp3f], 8(%[u_ptr]) \n\t"
|
||||
"lwc1 %[tmp4f], 12(%[u_ptr]) \n\t"
|
||||
"lwc1 %[tmp5f], 16(%[u_ptr]) \n\t"
|
||||
"lwc1 %[tmp6f], 20(%[u_ptr]) \n\t"
|
||||
"lwc1 %[tmp7f], 24(%[u_ptr]) \n\t"
|
||||
"lwc1 %[tmp8f], 28(%[u_ptr]) \n\t"
|
||||
"addiu %[noisePow], %[noisePow], 16 \n\t"
|
||||
"mul.s %[tmp1f], %[tmp1f], %[noise] \n\t"
|
||||
"mul.s %[tmp2f], %[tmp2f], %[noise] \n\t"
|
||||
"mul.s %[tmp3f], %[tmp3f], %[noise2] \n\t"
|
||||
"mul.s %[tmp4f], %[tmp4f], %[noise2] \n\t"
|
||||
"mul.s %[tmp5f], %[tmp5f], %[noise3] \n\t"
|
||||
"mul.s %[tmp6f], %[tmp6f], %[noise3] \n\t"
|
||||
"swc1 %[tmp1f], 0(%[u_ptr]) \n\t"
|
||||
"swc1 %[tmp3f], 8(%[u_ptr]) \n\t"
|
||||
"mul.s %[tmp8f], %[tmp8f], %[noise4] \n\t"
|
||||
"mul.s %[tmp7f], %[tmp7f], %[noise4] \n\t"
|
||||
"neg.s %[tmp2f] \n\t"
|
||||
"neg.s %[tmp4f] \n\t"
|
||||
"neg.s %[tmp6f] \n\t"
|
||||
"neg.s %[tmp8f] \n\t"
|
||||
"swc1 %[tmp5f], 16(%[u_ptr]) \n\t"
|
||||
"swc1 %[tmp7f], 24(%[u_ptr]) \n\t"
|
||||
"swc1 %[tmp2f], 4(%[u_ptr]) \n\t"
|
||||
"swc1 %[tmp4f], 12(%[u_ptr]) \n\t"
|
||||
"swc1 %[tmp6f], 20(%[u_ptr]) \n\t"
|
||||
"swc1 %[tmp8f], 28(%[u_ptr]) \n\t"
|
||||
"addiu %[u_ptr], %[u_ptr], 32 \n\t"
|
||||
".set pop \n\t"
|
||||
: [u_ptr] "+r" (u_ptr), [noisePow] "+r" (noisePow),
|
||||
[noise] "=&f" (noise), [noise2] "=&f" (noise2),
|
||||
[noise3] "=&f" (noise3), [noise4] "=&f" (noise4),
|
||||
[tmp1f] "=&f" (tmp1f), [tmp2f] "=&f" (tmp2f),
|
||||
[tmp3f] "=&f" (tmp3f), [tmp4f] "=&f" (tmp4f),
|
||||
[tmp5f] "=&f" (tmp5f), [tmp6f] "=&f" (tmp6f),
|
||||
[tmp7f] "=&f" (tmp7f), [tmp8f] "=&f" (tmp8f)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
u[PART_LEN][1] = 0;
|
||||
noisePow -= PART_LEN;
|
||||
|
||||
u_ptr = &u[0][0];
|
||||
float* u_ptr_end = &u[PART_LEN][0];
|
||||
float* efw_ptr_0 = &efw[0][0];
|
||||
float* efw_ptr_1 = &efw[1][0];
|
||||
float tmp9f, tmp10f;
|
||||
const float tmp1c = 1.0;
|
||||
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"1: \n\t"
|
||||
"lwc1 %[tmp1f], 0(%[lambda]) \n\t"
|
||||
"lwc1 %[tmp6f], 4(%[lambda]) \n\t"
|
||||
"addiu %[lambda], %[lambda], 8 \n\t"
|
||||
"c.lt.s %[tmp1f], %[tmp1c] \n\t"
|
||||
"bc1f 4f \n\t"
|
||||
" nop \n\t"
|
||||
"c.lt.s %[tmp6f], %[tmp1c] \n\t"
|
||||
"bc1f 3f \n\t"
|
||||
" nop \n\t"
|
||||
"2: \n\t"
|
||||
"mul.s %[tmp1f], %[tmp1f], %[tmp1f] \n\t"
|
||||
"mul.s %[tmp6f], %[tmp6f], %[tmp6f] \n\t"
|
||||
"sub.s %[tmp1f], %[tmp1c], %[tmp1f] \n\t"
|
||||
"sub.s %[tmp6f], %[tmp1c], %[tmp6f] \n\t"
|
||||
"sqrt.s %[tmp1f], %[tmp1f] \n\t"
|
||||
"sqrt.s %[tmp6f], %[tmp6f] \n\t"
|
||||
"lwc1 %[tmp2f], 0(%[efw_ptr_0]) \n\t"
|
||||
"lwc1 %[tmp3f], 0(%[u_ptr]) \n\t"
|
||||
"lwc1 %[tmp7f], 4(%[efw_ptr_0]) \n\t"
|
||||
"lwc1 %[tmp8f], 8(%[u_ptr]) \n\t"
|
||||
"lwc1 %[tmp4f], 0(%[efw_ptr_1]) \n\t"
|
||||
"lwc1 %[tmp5f], 4(%[u_ptr]) \n\t"
|
||||
"lwc1 %[tmp9f], 4(%[efw_ptr_1]) \n\t"
|
||||
"lwc1 %[tmp10f], 12(%[u_ptr]) \n\t"
|
||||
#if !defined(MIPS32_R2_LE)
|
||||
"mul.s %[tmp3f], %[tmp1f], %[tmp3f] \n\t"
|
||||
"add.s %[tmp2f], %[tmp2f], %[tmp3f] \n\t"
|
||||
"mul.s %[tmp3f], %[tmp1f], %[tmp5f] \n\t"
|
||||
"add.s %[tmp4f], %[tmp4f], %[tmp3f] \n\t"
|
||||
"mul.s %[tmp3f], %[tmp6f], %[tmp8f] \n\t"
|
||||
"add.s %[tmp7f], %[tmp7f], %[tmp3f] \n\t"
|
||||
"mul.s %[tmp3f], %[tmp6f], %[tmp10f] \n\t"
|
||||
"add.s %[tmp9f], %[tmp9f], %[tmp3f] \n\t"
|
||||
#else // #if !defined(MIPS32_R2_LE)
|
||||
"madd.s %[tmp2f], %[tmp2f], %[tmp1f], %[tmp3f] \n\t"
|
||||
"madd.s %[tmp4f], %[tmp4f], %[tmp1f], %[tmp5f] \n\t"
|
||||
"madd.s %[tmp7f], %[tmp7f], %[tmp6f], %[tmp8f] \n\t"
|
||||
"madd.s %[tmp9f], %[tmp9f], %[tmp6f], %[tmp10f] \n\t"
|
||||
#endif // #if !defined(MIPS32_R2_LE)
|
||||
"swc1 %[tmp2f], 0(%[efw_ptr_0]) \n\t"
|
||||
"swc1 %[tmp4f], 0(%[efw_ptr_1]) \n\t"
|
||||
"swc1 %[tmp7f], 4(%[efw_ptr_0]) \n\t"
|
||||
"b 5f \n\t"
|
||||
" swc1 %[tmp9f], 4(%[efw_ptr_1]) \n\t"
|
||||
"3: \n\t"
|
||||
"mul.s %[tmp1f], %[tmp1f], %[tmp1f] \n\t"
|
||||
"sub.s %[tmp1f], %[tmp1c], %[tmp1f] \n\t"
|
||||
"sqrt.s %[tmp1f], %[tmp1f] \n\t"
|
||||
"lwc1 %[tmp2f], 0(%[efw_ptr_0]) \n\t"
|
||||
"lwc1 %[tmp3f], 0(%[u_ptr]) \n\t"
|
||||
"lwc1 %[tmp4f], 0(%[efw_ptr_1]) \n\t"
|
||||
"lwc1 %[tmp5f], 4(%[u_ptr]) \n\t"
|
||||
#if !defined(MIPS32_R2_LE)
|
||||
"mul.s %[tmp3f], %[tmp1f], %[tmp3f] \n\t"
|
||||
"add.s %[tmp2f], %[tmp2f], %[tmp3f] \n\t"
|
||||
"mul.s %[tmp3f], %[tmp1f], %[tmp5f] \n\t"
|
||||
"add.s %[tmp4f], %[tmp4f], %[tmp3f] \n\t"
|
||||
#else // #if !defined(MIPS32_R2_LE)
|
||||
"madd.s %[tmp2f], %[tmp2f], %[tmp1f], %[tmp3f] \n\t"
|
||||
"madd.s %[tmp4f], %[tmp4f], %[tmp1f], %[tmp5f] \n\t"
|
||||
#endif // #if !defined(MIPS32_R2_LE)
|
||||
"swc1 %[tmp2f], 0(%[efw_ptr_0]) \n\t"
|
||||
"b 5f \n\t"
|
||||
" swc1 %[tmp4f], 0(%[efw_ptr_1]) \n\t"
|
||||
"4: \n\t"
|
||||
"c.lt.s %[tmp6f], %[tmp1c] \n\t"
|
||||
"bc1f 5f \n\t"
|
||||
" nop \n\t"
|
||||
"mul.s %[tmp6f], %[tmp6f], %[tmp6f] \n\t"
|
||||
"sub.s %[tmp6f], %[tmp1c], %[tmp6f] \n\t"
|
||||
"sqrt.s %[tmp6f], %[tmp6f] \n\t"
|
||||
"lwc1 %[tmp7f], 4(%[efw_ptr_0]) \n\t"
|
||||
"lwc1 %[tmp8f], 8(%[u_ptr]) \n\t"
|
||||
"lwc1 %[tmp9f], 4(%[efw_ptr_1]) \n\t"
|
||||
"lwc1 %[tmp10f], 12(%[u_ptr]) \n\t"
|
||||
#if !defined(MIPS32_R2_LE)
|
||||
"mul.s %[tmp3f], %[tmp6f], %[tmp8f] \n\t"
|
||||
"add.s %[tmp7f], %[tmp7f], %[tmp3f] \n\t"
|
||||
"mul.s %[tmp3f], %[tmp6f], %[tmp10f] \n\t"
|
||||
"add.s %[tmp9f], %[tmp9f], %[tmp3f] \n\t"
|
||||
#else // #if !defined(MIPS32_R2_LE)
|
||||
"madd.s %[tmp7f], %[tmp7f], %[tmp6f], %[tmp8f] \n\t"
|
||||
"madd.s %[tmp9f], %[tmp9f], %[tmp6f], %[tmp10f] \n\t"
|
||||
#endif // #if !defined(MIPS32_R2_LE)
|
||||
"swc1 %[tmp7f], 4(%[efw_ptr_0]) \n\t"
|
||||
"swc1 %[tmp9f], 4(%[efw_ptr_1]) \n\t"
|
||||
"5: \n\t"
|
||||
"addiu %[u_ptr], %[u_ptr], 16 \n\t"
|
||||
"addiu %[efw_ptr_0], %[efw_ptr_0], 8 \n\t"
|
||||
"bne %[u_ptr], %[u_ptr_end], 1b \n\t"
|
||||
" addiu %[efw_ptr_1], %[efw_ptr_1], 8 \n\t"
|
||||
".set pop \n\t"
|
||||
: [lambda] "+r" (lambda), [u_ptr] "+r" (u_ptr),
|
||||
[efw_ptr_0] "+r" (efw_ptr_0), [efw_ptr_1] "+r" (efw_ptr_1),
|
||||
[tmp1f] "=&f" (tmp1f), [tmp2f] "=&f" (tmp2f), [tmp3f] "=&f" (tmp3f),
|
||||
[tmp4f] "=&f" (tmp4f), [tmp5f] "=&f" (tmp5f),
|
||||
[tmp6f] "=&f" (tmp6f), [tmp7f] "=&f" (tmp7f), [tmp8f] "=&f" (tmp8f),
|
||||
[tmp9f] "=&f" (tmp9f), [tmp10f] "=&f" (tmp10f)
|
||||
: [tmp1c] "f" (tmp1c), [u_ptr_end] "r" (u_ptr_end)
|
||||
: "memory"
|
||||
);
|
||||
|
||||
lambda -= PART_LEN;
|
||||
tmp = sqrtf(WEBRTC_SPL_MAX(1 - lambda[PART_LEN] * lambda[PART_LEN], 0));
|
||||
//tmp = 1 - lambda[i];
|
||||
efw[0][PART_LEN] += tmp * u[PART_LEN][0];
|
||||
efw[1][PART_LEN] += tmp * u[PART_LEN][1];
|
||||
|
||||
// For H band comfort noise
|
||||
// TODO: don't compute noise and "tmp" twice. Use the previous results.
|
||||
noiseAvg = 0.0;
|
||||
tmpAvg = 0.0;
|
||||
num = 0;
|
||||
if ((aec->sampFreq == 32000 || aec->sampFreq == 48000) && flagHbandCn == 1) {
|
||||
for (i = 0; i < PART_LEN; i++) {
|
||||
rand[i] = ((float)randW16[i]) / 32768;
|
||||
}
|
||||
|
||||
// average noise scale
|
||||
// average over second half of freq spectrum (i.e., 4->8khz)
|
||||
// TODO: we shouldn't need num. We know how many elements we're summing.
|
||||
for (i = PART_LEN1 >> 1; i < PART_LEN1; i++) {
|
||||
num++;
|
||||
noiseAvg += sqrtf(noisePow[i]);
|
||||
}
|
||||
noiseAvg /= (float)num;
|
||||
|
||||
// average nlp scale
|
||||
// average over second half of freq spectrum (i.e., 4->8khz)
|
||||
// TODO: we shouldn't need num. We know how many elements we're summing.
|
||||
num = 0;
|
||||
for (i = PART_LEN1 >> 1; i < PART_LEN1; i++) {
|
||||
num++;
|
||||
tmpAvg += sqrtf(WEBRTC_SPL_MAX(1 - lambda[i] * lambda[i], 0));
|
||||
}
|
||||
tmpAvg /= (float)num;
|
||||
|
||||
// Use average noise for H band
|
||||
// TODO: we should probably have a new random vector here.
|
||||
// Reject LF noise
|
||||
u[0][0] = 0;
|
||||
u[0][1] = 0;
|
||||
for (i = 1; i < PART_LEN1; i++) {
|
||||
tmp = pi2 * rand[i - 1];
|
||||
|
||||
// Use average noise for H band
|
||||
u[i][0] = noiseAvg * (float)cos(tmp);
|
||||
u[i][1] = -noiseAvg * (float)sin(tmp);
|
||||
}
|
||||
u[PART_LEN][1] = 0;
|
||||
|
||||
for (i = 0; i < PART_LEN1; i++) {
|
||||
// Use average NLP weight for H band
|
||||
comfortNoiseHband[i][0] = tmpAvg * u[i][0];
|
||||
comfortNoiseHband[i][1] = tmpAvg * u[i][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcAec_FilterFar_mips(AecCore* aec, float yf[2][PART_LEN1]) {
|
||||
int i;
|
||||
for (i = 0; i < aec->num_partitions; i++) {
|
||||
int xPos = (i + aec->xfBufBlockPos) * PART_LEN1;
|
||||
int pos = i * PART_LEN1;
|
||||
// Check for wrap
|
||||
if (i + aec->xfBufBlockPos >= aec->num_partitions) {
|
||||
xPos -= aec->num_partitions * (PART_LEN1);
|
||||
}
|
||||
float* yf0 = yf[0];
|
||||
float* yf1 = yf[1];
|
||||
float* aRe = aec->xfBuf[0] + xPos;
|
||||
float* aIm = aec->xfBuf[1] + xPos;
|
||||
float* bRe = aec->wfBuf[0] + pos;
|
||||
float* bIm = aec->wfBuf[1] + pos;
|
||||
float f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13;
|
||||
int len = PART_LEN1 >> 1;
|
||||
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"1: \n\t"
|
||||
"lwc1 %[f0], 0(%[aRe]) \n\t"
|
||||
"lwc1 %[f1], 0(%[bRe]) \n\t"
|
||||
"lwc1 %[f2], 0(%[bIm]) \n\t"
|
||||
"lwc1 %[f3], 0(%[aIm]) \n\t"
|
||||
"lwc1 %[f4], 4(%[aRe]) \n\t"
|
||||
"lwc1 %[f5], 4(%[bRe]) \n\t"
|
||||
"lwc1 %[f6], 4(%[bIm]) \n\t"
|
||||
"mul.s %[f8], %[f0], %[f1] \n\t"
|
||||
"mul.s %[f0], %[f0], %[f2] \n\t"
|
||||
"mul.s %[f9], %[f4], %[f5] \n\t"
|
||||
"mul.s %[f4], %[f4], %[f6] \n\t"
|
||||
"lwc1 %[f7], 4(%[aIm]) \n\t"
|
||||
#if !defined(MIPS32_R2_LE)
|
||||
"mul.s %[f12], %[f2], %[f3] \n\t"
|
||||
"mul.s %[f1], %[f3], %[f1] \n\t"
|
||||
"mul.s %[f11], %[f6], %[f7] \n\t"
|
||||
"addiu %[aRe], %[aRe], 8 \n\t"
|
||||
"addiu %[aIm], %[aIm], 8 \n\t"
|
||||
"addiu %[len], %[len], -1 \n\t"
|
||||
"sub.s %[f8], %[f8], %[f12] \n\t"
|
||||
"mul.s %[f12], %[f7], %[f5] \n\t"
|
||||
"lwc1 %[f2], 0(%[yf0]) \n\t"
|
||||
"add.s %[f1], %[f0], %[f1] \n\t"
|
||||
"lwc1 %[f3], 0(%[yf1]) \n\t"
|
||||
"sub.s %[f9], %[f9], %[f11] \n\t"
|
||||
"lwc1 %[f6], 4(%[yf0]) \n\t"
|
||||
"add.s %[f4], %[f4], %[f12] \n\t"
|
||||
#else // #if !defined(MIPS32_R2_LE)
|
||||
"addiu %[aRe], %[aRe], 8 \n\t"
|
||||
"addiu %[aIm], %[aIm], 8 \n\t"
|
||||
"addiu %[len], %[len], -1 \n\t"
|
||||
"nmsub.s %[f8], %[f8], %[f2], %[f3] \n\t"
|
||||
"lwc1 %[f2], 0(%[yf0]) \n\t"
|
||||
"madd.s %[f1], %[f0], %[f3], %[f1] \n\t"
|
||||
"lwc1 %[f3], 0(%[yf1]) \n\t"
|
||||
"nmsub.s %[f9], %[f9], %[f6], %[f7] \n\t"
|
||||
"lwc1 %[f6], 4(%[yf0]) \n\t"
|
||||
"madd.s %[f4], %[f4], %[f7], %[f5] \n\t"
|
||||
#endif // #if !defined(MIPS32_R2_LE)
|
||||
"lwc1 %[f5], 4(%[yf1]) \n\t"
|
||||
"add.s %[f2], %[f2], %[f8] \n\t"
|
||||
"addiu %[bRe], %[bRe], 8 \n\t"
|
||||
"addiu %[bIm], %[bIm], 8 \n\t"
|
||||
"add.s %[f3], %[f3], %[f1] \n\t"
|
||||
"add.s %[f6], %[f6], %[f9] \n\t"
|
||||
"add.s %[f5], %[f5], %[f4] \n\t"
|
||||
"swc1 %[f2], 0(%[yf0]) \n\t"
|
||||
"swc1 %[f3], 0(%[yf1]) \n\t"
|
||||
"swc1 %[f6], 4(%[yf0]) \n\t"
|
||||
"swc1 %[f5], 4(%[yf1]) \n\t"
|
||||
"addiu %[yf0], %[yf0], 8 \n\t"
|
||||
"bgtz %[len], 1b \n\t"
|
||||
" addiu %[yf1], %[yf1], 8 \n\t"
|
||||
"lwc1 %[f0], 0(%[aRe]) \n\t"
|
||||
"lwc1 %[f1], 0(%[bRe]) \n\t"
|
||||
"lwc1 %[f2], 0(%[bIm]) \n\t"
|
||||
"lwc1 %[f3], 0(%[aIm]) \n\t"
|
||||
"mul.s %[f8], %[f0], %[f1] \n\t"
|
||||
"mul.s %[f0], %[f0], %[f2] \n\t"
|
||||
#if !defined(MIPS32_R2_LE)
|
||||
"mul.s %[f12], %[f2], %[f3] \n\t"
|
||||
"mul.s %[f1], %[f3], %[f1] \n\t"
|
||||
"sub.s %[f8], %[f8], %[f12] \n\t"
|
||||
"lwc1 %[f2], 0(%[yf0]) \n\t"
|
||||
"add.s %[f1], %[f0], %[f1] \n\t"
|
||||
"lwc1 %[f3], 0(%[yf1]) \n\t"
|
||||
#else // #if !defined(MIPS32_R2_LE)
|
||||
"nmsub.s %[f8], %[f8], %[f2], %[f3] \n\t"
|
||||
"lwc1 %[f2], 0(%[yf0]) \n\t"
|
||||
"madd.s %[f1], %[f0], %[f3], %[f1] \n\t"
|
||||
"lwc1 %[f3], 0(%[yf1]) \n\t"
|
||||
#endif // #if !defined(MIPS32_R2_LE)
|
||||
"add.s %[f2], %[f2], %[f8] \n\t"
|
||||
"add.s %[f3], %[f3], %[f1] \n\t"
|
||||
"swc1 %[f2], 0(%[yf0]) \n\t"
|
||||
"swc1 %[f3], 0(%[yf1]) \n\t"
|
||||
".set pop \n\t"
|
||||
: [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2),
|
||||
[f3] "=&f" (f3), [f4] "=&f" (f4), [f5] "=&f" (f5),
|
||||
[f6] "=&f" (f6), [f7] "=&f" (f7), [f8] "=&f" (f8),
|
||||
[f9] "=&f" (f9), [f10] "=&f" (f10), [f11] "=&f" (f11),
|
||||
[f12] "=&f" (f12), [f13] "=&f" (f13), [aRe] "+r" (aRe),
|
||||
[aIm] "+r" (aIm), [bRe] "+r" (bRe), [bIm] "+r" (bIm),
|
||||
[yf0] "+r" (yf0), [yf1] "+r" (yf1), [len] "+r" (len)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcAec_FilterAdaptation_mips(AecCore* aec,
|
||||
float* fft,
|
||||
float ef[2][PART_LEN1]) {
|
||||
int i;
|
||||
for (i = 0; i < aec->num_partitions; i++) {
|
||||
int xPos = (i + aec->xfBufBlockPos)*(PART_LEN1);
|
||||
int pos;
|
||||
// Check for wrap
|
||||
if (i + aec->xfBufBlockPos >= aec->num_partitions) {
|
||||
xPos -= aec->num_partitions * PART_LEN1;
|
||||
}
|
||||
|
||||
pos = i * PART_LEN1;
|
||||
float* aRe = aec->xfBuf[0] + xPos;
|
||||
float* aIm = aec->xfBuf[1] + xPos;
|
||||
float* bRe = ef[0];
|
||||
float* bIm = ef[1];
|
||||
float* fft_tmp;
|
||||
|
||||
float f0, f1, f2, f3, f4, f5, f6 ,f7, f8, f9, f10, f11, f12;
|
||||
int len = PART_LEN >> 1;
|
||||
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"addiu %[fft_tmp], %[fft], 0 \n\t"
|
||||
"1: \n\t"
|
||||
"lwc1 %[f0], 0(%[aRe]) \n\t"
|
||||
"lwc1 %[f1], 0(%[bRe]) \n\t"
|
||||
"lwc1 %[f2], 0(%[bIm]) \n\t"
|
||||
"lwc1 %[f4], 4(%[aRe]) \n\t"
|
||||
"lwc1 %[f5], 4(%[bRe]) \n\t"
|
||||
"lwc1 %[f6], 4(%[bIm]) \n\t"
|
||||
"addiu %[aRe], %[aRe], 8 \n\t"
|
||||
"addiu %[bRe], %[bRe], 8 \n\t"
|
||||
"mul.s %[f8], %[f0], %[f1] \n\t"
|
||||
"mul.s %[f0], %[f0], %[f2] \n\t"
|
||||
"lwc1 %[f3], 0(%[aIm]) \n\t"
|
||||
"mul.s %[f9], %[f4], %[f5] \n\t"
|
||||
"lwc1 %[f7], 4(%[aIm]) \n\t"
|
||||
"mul.s %[f4], %[f4], %[f6] \n\t"
|
||||
#if !defined(MIPS32_R2_LE)
|
||||
"mul.s %[f10], %[f3], %[f2] \n\t"
|
||||
"mul.s %[f1], %[f3], %[f1] \n\t"
|
||||
"mul.s %[f11], %[f7], %[f6] \n\t"
|
||||
"mul.s %[f5], %[f7], %[f5] \n\t"
|
||||
"addiu %[aIm], %[aIm], 8 \n\t"
|
||||
"addiu %[bIm], %[bIm], 8 \n\t"
|
||||
"addiu %[len], %[len], -1 \n\t"
|
||||
"add.s %[f8], %[f8], %[f10] \n\t"
|
||||
"sub.s %[f1], %[f0], %[f1] \n\t"
|
||||
"add.s %[f9], %[f9], %[f11] \n\t"
|
||||
"sub.s %[f5], %[f4], %[f5] \n\t"
|
||||
#else // #if !defined(MIPS32_R2_LE)
|
||||
"addiu %[aIm], %[aIm], 8 \n\t"
|
||||
"addiu %[bIm], %[bIm], 8 \n\t"
|
||||
"addiu %[len], %[len], -1 \n\t"
|
||||
"madd.s %[f8], %[f8], %[f3], %[f2] \n\t"
|
||||
"nmsub.s %[f1], %[f0], %[f3], %[f1] \n\t"
|
||||
"madd.s %[f9], %[f9], %[f7], %[f6] \n\t"
|
||||
"nmsub.s %[f5], %[f4], %[f7], %[f5] \n\t"
|
||||
#endif // #if !defined(MIPS32_R2_LE)
|
||||
"swc1 %[f8], 0(%[fft_tmp]) \n\t"
|
||||
"swc1 %[f1], 4(%[fft_tmp]) \n\t"
|
||||
"swc1 %[f9], 8(%[fft_tmp]) \n\t"
|
||||
"swc1 %[f5], 12(%[fft_tmp]) \n\t"
|
||||
"bgtz %[len], 1b \n\t"
|
||||
" addiu %[fft_tmp], %[fft_tmp], 16 \n\t"
|
||||
"lwc1 %[f0], 0(%[aRe]) \n\t"
|
||||
"lwc1 %[f1], 0(%[bRe]) \n\t"
|
||||
"lwc1 %[f2], 0(%[bIm]) \n\t"
|
||||
"lwc1 %[f3], 0(%[aIm]) \n\t"
|
||||
"mul.s %[f8], %[f0], %[f1] \n\t"
|
||||
#if !defined(MIPS32_R2_LE)
|
||||
"mul.s %[f10], %[f3], %[f2] \n\t"
|
||||
"add.s %[f8], %[f8], %[f10] \n\t"
|
||||
#else // #if !defined(MIPS32_R2_LE)
|
||||
"madd.s %[f8], %[f8], %[f3], %[f2] \n\t"
|
||||
#endif // #if !defined(MIPS32_R2_LE)
|
||||
"swc1 %[f8], 4(%[fft]) \n\t"
|
||||
".set pop \n\t"
|
||||
: [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2),
|
||||
[f3] "=&f" (f3), [f4] "=&f" (f4), [f5] "=&f" (f5),
|
||||
[f6] "=&f" (f6), [f7] "=&f" (f7), [f8] "=&f" (f8),
|
||||
[f9] "=&f" (f9), [f10] "=&f" (f10), [f11] "=&f" (f11),
|
||||
[f12] "=&f" (f12), [aRe] "+r" (aRe), [aIm] "+r" (aIm),
|
||||
[bRe] "+r" (bRe), [bIm] "+r" (bIm), [fft_tmp] "=&r" (fft_tmp),
|
||||
[len] "+r" (len)
|
||||
: [fft] "r" (fft)
|
||||
: "memory"
|
||||
);
|
||||
|
||||
aec_rdft_inverse_128(fft);
|
||||
memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN);
|
||||
|
||||
// fft scaling
|
||||
{
|
||||
float scale = 2.0f / PART_LEN2;
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"addiu %[fft_tmp], %[fft], 0 \n\t"
|
||||
"addiu %[len], $zero, 8 \n\t"
|
||||
"1: \n\t"
|
||||
"addiu %[len], %[len], -1 \n\t"
|
||||
"lwc1 %[f0], 0(%[fft_tmp]) \n\t"
|
||||
"lwc1 %[f1], 4(%[fft_tmp]) \n\t"
|
||||
"lwc1 %[f2], 8(%[fft_tmp]) \n\t"
|
||||
"lwc1 %[f3], 12(%[fft_tmp]) \n\t"
|
||||
"mul.s %[f0], %[f0], %[scale] \n\t"
|
||||
"mul.s %[f1], %[f1], %[scale] \n\t"
|
||||
"mul.s %[f2], %[f2], %[scale] \n\t"
|
||||
"mul.s %[f3], %[f3], %[scale] \n\t"
|
||||
"lwc1 %[f4], 16(%[fft_tmp]) \n\t"
|
||||
"lwc1 %[f5], 20(%[fft_tmp]) \n\t"
|
||||
"lwc1 %[f6], 24(%[fft_tmp]) \n\t"
|
||||
"lwc1 %[f7], 28(%[fft_tmp]) \n\t"
|
||||
"mul.s %[f4], %[f4], %[scale] \n\t"
|
||||
"mul.s %[f5], %[f5], %[scale] \n\t"
|
||||
"mul.s %[f6], %[f6], %[scale] \n\t"
|
||||
"mul.s %[f7], %[f7], %[scale] \n\t"
|
||||
"swc1 %[f0], 0(%[fft_tmp]) \n\t"
|
||||
"swc1 %[f1], 4(%[fft_tmp]) \n\t"
|
||||
"swc1 %[f2], 8(%[fft_tmp]) \n\t"
|
||||
"swc1 %[f3], 12(%[fft_tmp]) \n\t"
|
||||
"swc1 %[f4], 16(%[fft_tmp]) \n\t"
|
||||
"swc1 %[f5], 20(%[fft_tmp]) \n\t"
|
||||
"swc1 %[f6], 24(%[fft_tmp]) \n\t"
|
||||
"swc1 %[f7], 28(%[fft_tmp]) \n\t"
|
||||
"bgtz %[len], 1b \n\t"
|
||||
" addiu %[fft_tmp], %[fft_tmp], 32 \n\t"
|
||||
".set pop \n\t"
|
||||
: [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2),
|
||||
[f3] "=&f" (f3), [f4] "=&f" (f4), [f5] "=&f" (f5),
|
||||
[f6] "=&f" (f6), [f7] "=&f" (f7), [len] "=&r" (len),
|
||||
[fft_tmp] "=&r" (fft_tmp)
|
||||
: [scale] "f" (scale), [fft] "r" (fft)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
aec_rdft_forward_128(fft);
|
||||
aRe = aec->wfBuf[0] + pos;
|
||||
aIm = aec->wfBuf[1] + pos;
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"addiu %[fft_tmp], %[fft], 0 \n\t"
|
||||
"addiu %[len], $zero, 31 \n\t"
|
||||
"lwc1 %[f0], 0(%[aRe]) \n\t"
|
||||
"lwc1 %[f1], 0(%[fft_tmp]) \n\t"
|
||||
"lwc1 %[f2], 256(%[aRe]) \n\t"
|
||||
"lwc1 %[f3], 4(%[fft_tmp]) \n\t"
|
||||
"lwc1 %[f4], 4(%[aRe]) \n\t"
|
||||
"lwc1 %[f5], 8(%[fft_tmp]) \n\t"
|
||||
"lwc1 %[f6], 4(%[aIm]) \n\t"
|
||||
"lwc1 %[f7], 12(%[fft_tmp]) \n\t"
|
||||
"add.s %[f0], %[f0], %[f1] \n\t"
|
||||
"add.s %[f2], %[f2], %[f3] \n\t"
|
||||
"add.s %[f4], %[f4], %[f5] \n\t"
|
||||
"add.s %[f6], %[f6], %[f7] \n\t"
|
||||
"addiu %[fft_tmp], %[fft_tmp], 16 \n\t"
|
||||
"swc1 %[f0], 0(%[aRe]) \n\t"
|
||||
"swc1 %[f2], 256(%[aRe]) \n\t"
|
||||
"swc1 %[f4], 4(%[aRe]) \n\t"
|
||||
"addiu %[aRe], %[aRe], 8 \n\t"
|
||||
"swc1 %[f6], 4(%[aIm]) \n\t"
|
||||
"addiu %[aIm], %[aIm], 8 \n\t"
|
||||
"1: \n\t"
|
||||
"lwc1 %[f0], 0(%[aRe]) \n\t"
|
||||
"lwc1 %[f1], 0(%[fft_tmp]) \n\t"
|
||||
"lwc1 %[f2], 0(%[aIm]) \n\t"
|
||||
"lwc1 %[f3], 4(%[fft_tmp]) \n\t"
|
||||
"lwc1 %[f4], 4(%[aRe]) \n\t"
|
||||
"lwc1 %[f5], 8(%[fft_tmp]) \n\t"
|
||||
"lwc1 %[f6], 4(%[aIm]) \n\t"
|
||||
"lwc1 %[f7], 12(%[fft_tmp]) \n\t"
|
||||
"add.s %[f0], %[f0], %[f1] \n\t"
|
||||
"add.s %[f2], %[f2], %[f3] \n\t"
|
||||
"add.s %[f4], %[f4], %[f5] \n\t"
|
||||
"add.s %[f6], %[f6], %[f7] \n\t"
|
||||
"addiu %[len], %[len], -1 \n\t"
|
||||
"addiu %[fft_tmp], %[fft_tmp], 16 \n\t"
|
||||
"swc1 %[f0], 0(%[aRe]) \n\t"
|
||||
"swc1 %[f2], 0(%[aIm]) \n\t"
|
||||
"swc1 %[f4], 4(%[aRe]) \n\t"
|
||||
"addiu %[aRe], %[aRe], 8 \n\t"
|
||||
"swc1 %[f6], 4(%[aIm]) \n\t"
|
||||
"bgtz %[len], 1b \n\t"
|
||||
" addiu %[aIm], %[aIm], 8 \n\t"
|
||||
".set pop \n\t"
|
||||
: [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2),
|
||||
[f3] "=&f" (f3), [f4] "=&f" (f4), [f5] "=&f" (f5),
|
||||
[f6] "=&f" (f6), [f7] "=&f" (f7), [len] "=&r" (len),
|
||||
[fft_tmp] "=&r" (fft_tmp), [aRe] "+r" (aRe), [aIm] "+r" (aIm)
|
||||
: [fft] "r" (fft)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcAec_OverdriveAndSuppress_mips(AecCore* aec,
|
||||
float hNl[PART_LEN1],
|
||||
const float hNlFb,
|
||||
float efw[2][PART_LEN1]) {
|
||||
int i;
|
||||
const float one = 1.0;
|
||||
float* p_hNl;
|
||||
float* p_efw0;
|
||||
float* p_efw1;
|
||||
float* p_WebRtcAec_wC;
|
||||
float temp1, temp2, temp3, temp4;
|
||||
|
||||
p_hNl = &hNl[0];
|
||||
p_efw0 = &efw[0][0];
|
||||
p_efw1 = &efw[1][0];
|
||||
p_WebRtcAec_wC = (float*)&WebRtcAec_weightCurve[0];
|
||||
|
||||
for (i = 0; i < PART_LEN1; i++) {
|
||||
// Weight subbands
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"lwc1 %[temp1], 0(%[p_hNl]) \n\t"
|
||||
"lwc1 %[temp2], 0(%[p_wC]) \n\t"
|
||||
"c.lt.s %[hNlFb], %[temp1] \n\t"
|
||||
"bc1f 1f \n\t"
|
||||
" mul.s %[temp3], %[temp2], %[hNlFb] \n\t"
|
||||
"sub.s %[temp4], %[one], %[temp2] \n\t"
|
||||
#if !defined(MIPS32_R2_LE)
|
||||
"mul.s %[temp1], %[temp1], %[temp4] \n\t"
|
||||
"add.s %[temp1], %[temp3], %[temp1] \n\t"
|
||||
#else // #if !defined(MIPS32_R2_LE)
|
||||
"madd.s %[temp1], %[temp3], %[temp1], %[temp4] \n\t"
|
||||
#endif // #if !defined(MIPS32_R2_LE)
|
||||
"swc1 %[temp1], 0(%[p_hNl]) \n\t"
|
||||
"1: \n\t"
|
||||
"addiu %[p_wC], %[p_wC], 4 \n\t"
|
||||
".set pop \n\t"
|
||||
: [temp1] "=&f" (temp1), [temp2] "=&f" (temp2), [temp3] "=&f" (temp3),
|
||||
[temp4] "=&f" (temp4), [p_wC] "+r" (p_WebRtcAec_wC)
|
||||
: [hNlFb] "f" (hNlFb), [one] "f" (one), [p_hNl] "r" (p_hNl)
|
||||
: "memory"
|
||||
);
|
||||
|
||||
hNl[i] = powf(hNl[i], aec->overDriveSm * WebRtcAec_overDriveCurve[i]);
|
||||
|
||||
__asm __volatile (
|
||||
"lwc1 %[temp1], 0(%[p_hNl]) \n\t"
|
||||
"lwc1 %[temp3], 0(%[p_efw1]) \n\t"
|
||||
"lwc1 %[temp2], 0(%[p_efw0]) \n\t"
|
||||
"addiu %[p_hNl], %[p_hNl], 4 \n\t"
|
||||
"mul.s %[temp3], %[temp3], %[temp1] \n\t"
|
||||
"mul.s %[temp2], %[temp2], %[temp1] \n\t"
|
||||
"addiu %[p_efw0], %[p_efw0], 4 \n\t"
|
||||
"addiu %[p_efw1], %[p_efw1], 4 \n\t"
|
||||
"neg.s %[temp4], %[temp3] \n\t"
|
||||
"swc1 %[temp2], -4(%[p_efw0]) \n\t"
|
||||
"swc1 %[temp4], -4(%[p_efw1]) \n\t"
|
||||
: [temp1] "=&f" (temp1), [temp2] "=&f" (temp2), [temp3] "=&f" (temp3),
|
||||
[temp4] "=&f" (temp4), [p_efw0] "+r" (p_efw0), [p_efw1] "+r" (p_efw1),
|
||||
[p_hNl] "+r" (p_hNl)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcAec_ScaleErrorSignal_mips(AecCore* aec, float ef[2][PART_LEN1]) {
|
||||
const float mu = aec->extended_filter_enabled ? kExtendedMu : aec->normal_mu;
|
||||
const float error_threshold = aec->extended_filter_enabled
|
||||
? kExtendedErrorThreshold
|
||||
: aec->normal_error_threshold;
|
||||
int len = (PART_LEN1);
|
||||
float* ef0 = ef[0];
|
||||
float* ef1 = ef[1];
|
||||
float* xPow = aec->xPow;
|
||||
float fac1 = 1e-10f;
|
||||
float err_th2 = error_threshold * error_threshold;
|
||||
float f0, f1, f2;
|
||||
#if !defined(MIPS32_R2_LE)
|
||||
float f3;
|
||||
#endif
|
||||
|
||||
__asm __volatile (
|
||||
".set push \n\t"
|
||||
".set noreorder \n\t"
|
||||
"1: \n\t"
|
||||
"lwc1 %[f0], 0(%[xPow]) \n\t"
|
||||
"lwc1 %[f1], 0(%[ef0]) \n\t"
|
||||
"lwc1 %[f2], 0(%[ef1]) \n\t"
|
||||
"add.s %[f0], %[f0], %[fac1] \n\t"
|
||||
"div.s %[f1], %[f1], %[f0] \n\t"
|
||||
"div.s %[f2], %[f2], %[f0] \n\t"
|
||||
"mul.s %[f0], %[f1], %[f1] \n\t"
|
||||
#if defined(MIPS32_R2_LE)
|
||||
"madd.s %[f0], %[f0], %[f2], %[f2] \n\t"
|
||||
#else
|
||||
"mul.s %[f3], %[f2], %[f2] \n\t"
|
||||
"add.s %[f0], %[f0], %[f3] \n\t"
|
||||
#endif
|
||||
"c.le.s %[f0], %[err_th2] \n\t"
|
||||
"nop \n\t"
|
||||
"bc1t 2f \n\t"
|
||||
" nop \n\t"
|
||||
"sqrt.s %[f0], %[f0] \n\t"
|
||||
"add.s %[f0], %[f0], %[fac1] \n\t"
|
||||
"div.s %[f0], %[err_th], %[f0] \n\t"
|
||||
"mul.s %[f1], %[f1], %[f0] \n\t"
|
||||
"mul.s %[f2], %[f2], %[f0] \n\t"
|
||||
"2: \n\t"
|
||||
"mul.s %[f1], %[f1], %[mu] \n\t"
|
||||
"mul.s %[f2], %[f2], %[mu] \n\t"
|
||||
"swc1 %[f1], 0(%[ef0]) \n\t"
|
||||
"swc1 %[f2], 0(%[ef1]) \n\t"
|
||||
"addiu %[len], %[len], -1 \n\t"
|
||||
"addiu %[xPow], %[xPow], 4 \n\t"
|
||||
"addiu %[ef0], %[ef0], 4 \n\t"
|
||||
"bgtz %[len], 1b \n\t"
|
||||
" addiu %[ef1], %[ef1], 4 \n\t"
|
||||
".set pop \n\t"
|
||||
: [f0] "=&f" (f0), [f1] "=&f" (f1), [f2] "=&f" (f2),
|
||||
#if !defined(MIPS32_R2_LE)
|
||||
[f3] "=&f" (f3),
|
||||
#endif
|
||||
[xPow] "+r" (xPow), [ef0] "+r" (ef0), [ef1] "+r" (ef1),
|
||||
[len] "+r" (len)
|
||||
: [fac1] "f" (fac1), [err_th2] "f" (err_th2), [mu] "f" (mu),
|
||||
[err_th] "f" (error_threshold)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
void WebRtcAec_InitAec_mips(void) {
|
||||
WebRtcAec_FilterFar = WebRtcAec_FilterFar_mips;
|
||||
WebRtcAec_FilterAdaptation = WebRtcAec_FilterAdaptation_mips;
|
||||
WebRtcAec_ScaleErrorSignal = WebRtcAec_ScaleErrorSignal_mips;
|
||||
WebRtcAec_ComfortNoise = WebRtcAec_ComfortNoise_mips;
|
||||
WebRtcAec_OverdriveAndSuppress = WebRtcAec_OverdriveAndSuppress_mips;
|
||||
}
|
||||
|
||||
736
webrtc/modules/audio_processing/aec/aec_core_neon.c
Normal file
736
webrtc/modules/audio_processing/aec/aec_core_neon.c
Normal file
@@ -0,0 +1,736 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The core AEC algorithm, neon version of speed-critical functions.
|
||||
*
|
||||
* Based on aec_core_sse2.c.
|
||||
*/
|
||||
|
||||
#include <arm_neon.h>
|
||||
#include <math.h>
|
||||
#include <string.h> // memset
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_common.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_core_internal.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_rdft.h"
|
||||
|
||||
enum { kShiftExponentIntoTopMantissa = 8 };
|
||||
enum { kFloatExponentShift = 23 };
|
||||
|
||||
__inline static float MulRe(float aRe, float aIm, float bRe, float bIm) {
|
||||
return aRe * bRe - aIm * bIm;
|
||||
}
|
||||
|
||||
__inline static float MulIm(float aRe, float aIm, float bRe, float bIm) {
|
||||
return aRe * bIm + aIm * bRe;
|
||||
}
|
||||
|
||||
static void FilterFarNEON(AecCore* aec, float yf[2][PART_LEN1]) {
|
||||
int i;
|
||||
const int num_partitions = aec->num_partitions;
|
||||
for (i = 0; i < num_partitions; i++) {
|
||||
int j;
|
||||
int xPos = (i + aec->xfBufBlockPos) * PART_LEN1;
|
||||
int pos = i * PART_LEN1;
|
||||
// Check for wrap
|
||||
if (i + aec->xfBufBlockPos >= num_partitions) {
|
||||
xPos -= num_partitions * PART_LEN1;
|
||||
}
|
||||
|
||||
// vectorized code (four at once)
|
||||
for (j = 0; j + 3 < PART_LEN1; j += 4) {
|
||||
const float32x4_t xfBuf_re = vld1q_f32(&aec->xfBuf[0][xPos + j]);
|
||||
const float32x4_t xfBuf_im = vld1q_f32(&aec->xfBuf[1][xPos + j]);
|
||||
const float32x4_t wfBuf_re = vld1q_f32(&aec->wfBuf[0][pos + j]);
|
||||
const float32x4_t wfBuf_im = vld1q_f32(&aec->wfBuf[1][pos + j]);
|
||||
const float32x4_t yf_re = vld1q_f32(&yf[0][j]);
|
||||
const float32x4_t yf_im = vld1q_f32(&yf[1][j]);
|
||||
const float32x4_t a = vmulq_f32(xfBuf_re, wfBuf_re);
|
||||
const float32x4_t e = vmlsq_f32(a, xfBuf_im, wfBuf_im);
|
||||
const float32x4_t c = vmulq_f32(xfBuf_re, wfBuf_im);
|
||||
const float32x4_t f = vmlaq_f32(c, xfBuf_im, wfBuf_re);
|
||||
const float32x4_t g = vaddq_f32(yf_re, e);
|
||||
const float32x4_t h = vaddq_f32(yf_im, f);
|
||||
vst1q_f32(&yf[0][j], g);
|
||||
vst1q_f32(&yf[1][j], h);
|
||||
}
|
||||
// scalar code for the remaining items.
|
||||
for (; j < PART_LEN1; j++) {
|
||||
yf[0][j] += MulRe(aec->xfBuf[0][xPos + j],
|
||||
aec->xfBuf[1][xPos + j],
|
||||
aec->wfBuf[0][pos + j],
|
||||
aec->wfBuf[1][pos + j]);
|
||||
yf[1][j] += MulIm(aec->xfBuf[0][xPos + j],
|
||||
aec->xfBuf[1][xPos + j],
|
||||
aec->wfBuf[0][pos + j],
|
||||
aec->wfBuf[1][pos + j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ARM64's arm_neon.h has already defined vdivq_f32 vsqrtq_f32.
|
||||
#if !defined (WEBRTC_ARCH_ARM64)
|
||||
static float32x4_t vdivq_f32(float32x4_t a, float32x4_t b) {
|
||||
int i;
|
||||
float32x4_t x = vrecpeq_f32(b);
|
||||
// from arm documentation
|
||||
// The Newton-Raphson iteration:
|
||||
// x[n+1] = x[n] * (2 - d * x[n])
|
||||
// converges to (1/d) if x0 is the result of VRECPE applied to d.
|
||||
//
|
||||
// Note: The precision did not improve after 2 iterations.
|
||||
for (i = 0; i < 2; i++) {
|
||||
x = vmulq_f32(vrecpsq_f32(b, x), x);
|
||||
}
|
||||
// a/b = a*(1/b)
|
||||
return vmulq_f32(a, x);
|
||||
}
|
||||
|
||||
static float32x4_t vsqrtq_f32(float32x4_t s) {
|
||||
int i;
|
||||
float32x4_t x = vrsqrteq_f32(s);
|
||||
|
||||
// Code to handle sqrt(0).
|
||||
// If the input to sqrtf() is zero, a zero will be returned.
|
||||
// If the input to vrsqrteq_f32() is zero, positive infinity is returned.
|
||||
const uint32x4_t vec_p_inf = vdupq_n_u32(0x7F800000);
|
||||
// check for divide by zero
|
||||
const uint32x4_t div_by_zero = vceqq_u32(vec_p_inf, vreinterpretq_u32_f32(x));
|
||||
// zero out the positive infinity results
|
||||
x = vreinterpretq_f32_u32(vandq_u32(vmvnq_u32(div_by_zero),
|
||||
vreinterpretq_u32_f32(x)));
|
||||
// from arm documentation
|
||||
// The Newton-Raphson iteration:
|
||||
// x[n+1] = x[n] * (3 - d * (x[n] * x[n])) / 2)
|
||||
// converges to (1/√d) if x0 is the result of VRSQRTE applied to d.
|
||||
//
|
||||
// Note: The precision did not improve after 2 iterations.
|
||||
for (i = 0; i < 2; i++) {
|
||||
x = vmulq_f32(vrsqrtsq_f32(vmulq_f32(x, x), s), x);
|
||||
}
|
||||
// sqrt(s) = s * 1/sqrt(s)
|
||||
return vmulq_f32(s, x);;
|
||||
}
|
||||
#endif // WEBRTC_ARCH_ARM64
|
||||
|
||||
static void ScaleErrorSignalNEON(AecCore* aec, float ef[2][PART_LEN1]) {
|
||||
const float mu = aec->extended_filter_enabled ? kExtendedMu : aec->normal_mu;
|
||||
const float error_threshold = aec->extended_filter_enabled ?
|
||||
kExtendedErrorThreshold : aec->normal_error_threshold;
|
||||
const float32x4_t k1e_10f = vdupq_n_f32(1e-10f);
|
||||
const float32x4_t kMu = vmovq_n_f32(mu);
|
||||
const float32x4_t kThresh = vmovq_n_f32(error_threshold);
|
||||
int i;
|
||||
// vectorized code (four at once)
|
||||
for (i = 0; i + 3 < PART_LEN1; i += 4) {
|
||||
const float32x4_t xPow = vld1q_f32(&aec->xPow[i]);
|
||||
const float32x4_t ef_re_base = vld1q_f32(&ef[0][i]);
|
||||
const float32x4_t ef_im_base = vld1q_f32(&ef[1][i]);
|
||||
const float32x4_t xPowPlus = vaddq_f32(xPow, k1e_10f);
|
||||
float32x4_t ef_re = vdivq_f32(ef_re_base, xPowPlus);
|
||||
float32x4_t ef_im = vdivq_f32(ef_im_base, xPowPlus);
|
||||
const float32x4_t ef_re2 = vmulq_f32(ef_re, ef_re);
|
||||
const float32x4_t ef_sum2 = vmlaq_f32(ef_re2, ef_im, ef_im);
|
||||
const float32x4_t absEf = vsqrtq_f32(ef_sum2);
|
||||
const uint32x4_t bigger = vcgtq_f32(absEf, kThresh);
|
||||
const float32x4_t absEfPlus = vaddq_f32(absEf, k1e_10f);
|
||||
const float32x4_t absEfInv = vdivq_f32(kThresh, absEfPlus);
|
||||
uint32x4_t ef_re_if = vreinterpretq_u32_f32(vmulq_f32(ef_re, absEfInv));
|
||||
uint32x4_t ef_im_if = vreinterpretq_u32_f32(vmulq_f32(ef_im, absEfInv));
|
||||
uint32x4_t ef_re_u32 = vandq_u32(vmvnq_u32(bigger),
|
||||
vreinterpretq_u32_f32(ef_re));
|
||||
uint32x4_t ef_im_u32 = vandq_u32(vmvnq_u32(bigger),
|
||||
vreinterpretq_u32_f32(ef_im));
|
||||
ef_re_if = vandq_u32(bigger, ef_re_if);
|
||||
ef_im_if = vandq_u32(bigger, ef_im_if);
|
||||
ef_re_u32 = vorrq_u32(ef_re_u32, ef_re_if);
|
||||
ef_im_u32 = vorrq_u32(ef_im_u32, ef_im_if);
|
||||
ef_re = vmulq_f32(vreinterpretq_f32_u32(ef_re_u32), kMu);
|
||||
ef_im = vmulq_f32(vreinterpretq_f32_u32(ef_im_u32), kMu);
|
||||
vst1q_f32(&ef[0][i], ef_re);
|
||||
vst1q_f32(&ef[1][i], ef_im);
|
||||
}
|
||||
// scalar code for the remaining items.
|
||||
for (; i < PART_LEN1; i++) {
|
||||
float abs_ef;
|
||||
ef[0][i] /= (aec->xPow[i] + 1e-10f);
|
||||
ef[1][i] /= (aec->xPow[i] + 1e-10f);
|
||||
abs_ef = sqrtf(ef[0][i] * ef[0][i] + ef[1][i] * ef[1][i]);
|
||||
|
||||
if (abs_ef > error_threshold) {
|
||||
abs_ef = error_threshold / (abs_ef + 1e-10f);
|
||||
ef[0][i] *= abs_ef;
|
||||
ef[1][i] *= abs_ef;
|
||||
}
|
||||
|
||||
// Stepsize factor
|
||||
ef[0][i] *= mu;
|
||||
ef[1][i] *= mu;
|
||||
}
|
||||
}
|
||||
|
||||
static void FilterAdaptationNEON(AecCore* aec,
|
||||
float* fft,
|
||||
float ef[2][PART_LEN1]) {
|
||||
int i;
|
||||
const int num_partitions = aec->num_partitions;
|
||||
for (i = 0; i < num_partitions; i++) {
|
||||
int xPos = (i + aec->xfBufBlockPos) * PART_LEN1;
|
||||
int pos = i * PART_LEN1;
|
||||
int j;
|
||||
// Check for wrap
|
||||
if (i + aec->xfBufBlockPos >= num_partitions) {
|
||||
xPos -= num_partitions * PART_LEN1;
|
||||
}
|
||||
|
||||
// Process the whole array...
|
||||
for (j = 0; j < PART_LEN; j += 4) {
|
||||
// Load xfBuf and ef.
|
||||
const float32x4_t xfBuf_re = vld1q_f32(&aec->xfBuf[0][xPos + j]);
|
||||
const float32x4_t xfBuf_im = vld1q_f32(&aec->xfBuf[1][xPos + j]);
|
||||
const float32x4_t ef_re = vld1q_f32(&ef[0][j]);
|
||||
const float32x4_t ef_im = vld1q_f32(&ef[1][j]);
|
||||
// Calculate the product of conjugate(xfBuf) by ef.
|
||||
// re(conjugate(a) * b) = aRe * bRe + aIm * bIm
|
||||
// im(conjugate(a) * b)= aRe * bIm - aIm * bRe
|
||||
const float32x4_t a = vmulq_f32(xfBuf_re, ef_re);
|
||||
const float32x4_t e = vmlaq_f32(a, xfBuf_im, ef_im);
|
||||
const float32x4_t c = vmulq_f32(xfBuf_re, ef_im);
|
||||
const float32x4_t f = vmlsq_f32(c, xfBuf_im, ef_re);
|
||||
// Interleave real and imaginary parts.
|
||||
const float32x4x2_t g_n_h = vzipq_f32(e, f);
|
||||
// Store
|
||||
vst1q_f32(&fft[2 * j + 0], g_n_h.val[0]);
|
||||
vst1q_f32(&fft[2 * j + 4], g_n_h.val[1]);
|
||||
}
|
||||
// ... and fixup the first imaginary entry.
|
||||
fft[1] = MulRe(aec->xfBuf[0][xPos + PART_LEN],
|
||||
-aec->xfBuf[1][xPos + PART_LEN],
|
||||
ef[0][PART_LEN],
|
||||
ef[1][PART_LEN]);
|
||||
|
||||
aec_rdft_inverse_128(fft);
|
||||
memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN);
|
||||
|
||||
// fft scaling
|
||||
{
|
||||
const float scale = 2.0f / PART_LEN2;
|
||||
const float32x4_t scale_ps = vmovq_n_f32(scale);
|
||||
for (j = 0; j < PART_LEN; j += 4) {
|
||||
const float32x4_t fft_ps = vld1q_f32(&fft[j]);
|
||||
const float32x4_t fft_scale = vmulq_f32(fft_ps, scale_ps);
|
||||
vst1q_f32(&fft[j], fft_scale);
|
||||
}
|
||||
}
|
||||
aec_rdft_forward_128(fft);
|
||||
|
||||
{
|
||||
const float wt1 = aec->wfBuf[1][pos];
|
||||
aec->wfBuf[0][pos + PART_LEN] += fft[1];
|
||||
for (j = 0; j < PART_LEN; j += 4) {
|
||||
float32x4_t wtBuf_re = vld1q_f32(&aec->wfBuf[0][pos + j]);
|
||||
float32x4_t wtBuf_im = vld1q_f32(&aec->wfBuf[1][pos + j]);
|
||||
const float32x4_t fft0 = vld1q_f32(&fft[2 * j + 0]);
|
||||
const float32x4_t fft4 = vld1q_f32(&fft[2 * j + 4]);
|
||||
const float32x4x2_t fft_re_im = vuzpq_f32(fft0, fft4);
|
||||
wtBuf_re = vaddq_f32(wtBuf_re, fft_re_im.val[0]);
|
||||
wtBuf_im = vaddq_f32(wtBuf_im, fft_re_im.val[1]);
|
||||
|
||||
vst1q_f32(&aec->wfBuf[0][pos + j], wtBuf_re);
|
||||
vst1q_f32(&aec->wfBuf[1][pos + j], wtBuf_im);
|
||||
}
|
||||
aec->wfBuf[1][pos] = wt1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static float32x4_t vpowq_f32(float32x4_t a, float32x4_t b) {
|
||||
// a^b = exp2(b * log2(a))
|
||||
// exp2(x) and log2(x) are calculated using polynomial approximations.
|
||||
float32x4_t log2_a, b_log2_a, a_exp_b;
|
||||
|
||||
// Calculate log2(x), x = a.
|
||||
{
|
||||
// To calculate log2(x), we decompose x like this:
|
||||
// x = y * 2^n
|
||||
// n is an integer
|
||||
// y is in the [1.0, 2.0) range
|
||||
//
|
||||
// log2(x) = log2(y) + n
|
||||
// n can be evaluated by playing with float representation.
|
||||
// log2(y) in a small range can be approximated, this code uses an order
|
||||
// five polynomial approximation. The coefficients have been
|
||||
// estimated with the Remez algorithm and the resulting
|
||||
// polynomial has a maximum relative error of 0.00086%.
|
||||
|
||||
// Compute n.
|
||||
// This is done by masking the exponent, shifting it into the top bit of
|
||||
// the mantissa, putting eight into the biased exponent (to shift/
|
||||
// compensate the fact that the exponent has been shifted in the top/
|
||||
// fractional part and finally getting rid of the implicit leading one
|
||||
// from the mantissa by substracting it out.
|
||||
const uint32x4_t vec_float_exponent_mask = vdupq_n_u32(0x7F800000);
|
||||
const uint32x4_t vec_eight_biased_exponent = vdupq_n_u32(0x43800000);
|
||||
const uint32x4_t vec_implicit_leading_one = vdupq_n_u32(0x43BF8000);
|
||||
const uint32x4_t two_n = vandq_u32(vreinterpretq_u32_f32(a),
|
||||
vec_float_exponent_mask);
|
||||
const uint32x4_t n_1 = vshrq_n_u32(two_n, kShiftExponentIntoTopMantissa);
|
||||
const uint32x4_t n_0 = vorrq_u32(n_1, vec_eight_biased_exponent);
|
||||
const float32x4_t n =
|
||||
vsubq_f32(vreinterpretq_f32_u32(n_0),
|
||||
vreinterpretq_f32_u32(vec_implicit_leading_one));
|
||||
// Compute y.
|
||||
const uint32x4_t vec_mantissa_mask = vdupq_n_u32(0x007FFFFF);
|
||||
const uint32x4_t vec_zero_biased_exponent_is_one = vdupq_n_u32(0x3F800000);
|
||||
const uint32x4_t mantissa = vandq_u32(vreinterpretq_u32_f32(a),
|
||||
vec_mantissa_mask);
|
||||
const float32x4_t y =
|
||||
vreinterpretq_f32_u32(vorrq_u32(mantissa,
|
||||
vec_zero_biased_exponent_is_one));
|
||||
// Approximate log2(y) ~= (y - 1) * pol5(y).
|
||||
// pol5(y) = C5 * y^5 + C4 * y^4 + C3 * y^3 + C2 * y^2 + C1 * y + C0
|
||||
const float32x4_t C5 = vdupq_n_f32(-3.4436006e-2f);
|
||||
const float32x4_t C4 = vdupq_n_f32(3.1821337e-1f);
|
||||
const float32x4_t C3 = vdupq_n_f32(-1.2315303f);
|
||||
const float32x4_t C2 = vdupq_n_f32(2.5988452f);
|
||||
const float32x4_t C1 = vdupq_n_f32(-3.3241990f);
|
||||
const float32x4_t C0 = vdupq_n_f32(3.1157899f);
|
||||
float32x4_t pol5_y = C5;
|
||||
pol5_y = vmlaq_f32(C4, y, pol5_y);
|
||||
pol5_y = vmlaq_f32(C3, y, pol5_y);
|
||||
pol5_y = vmlaq_f32(C2, y, pol5_y);
|
||||
pol5_y = vmlaq_f32(C1, y, pol5_y);
|
||||
pol5_y = vmlaq_f32(C0, y, pol5_y);
|
||||
const float32x4_t y_minus_one =
|
||||
vsubq_f32(y, vreinterpretq_f32_u32(vec_zero_biased_exponent_is_one));
|
||||
const float32x4_t log2_y = vmulq_f32(y_minus_one, pol5_y);
|
||||
|
||||
// Combine parts.
|
||||
log2_a = vaddq_f32(n, log2_y);
|
||||
}
|
||||
|
||||
// b * log2(a)
|
||||
b_log2_a = vmulq_f32(b, log2_a);
|
||||
|
||||
// Calculate exp2(x), x = b * log2(a).
|
||||
{
|
||||
// To calculate 2^x, we decompose x like this:
|
||||
// x = n + y
|
||||
// n is an integer, the value of x - 0.5 rounded down, therefore
|
||||
// y is in the [0.5, 1.5) range
|
||||
//
|
||||
// 2^x = 2^n * 2^y
|
||||
// 2^n can be evaluated by playing with float representation.
|
||||
// 2^y in a small range can be approximated, this code uses an order two
|
||||
// polynomial approximation. The coefficients have been estimated
|
||||
// with the Remez algorithm and the resulting polynomial has a
|
||||
// maximum relative error of 0.17%.
|
||||
// To avoid over/underflow, we reduce the range of input to ]-127, 129].
|
||||
const float32x4_t max_input = vdupq_n_f32(129.f);
|
||||
const float32x4_t min_input = vdupq_n_f32(-126.99999f);
|
||||
const float32x4_t x_min = vminq_f32(b_log2_a, max_input);
|
||||
const float32x4_t x_max = vmaxq_f32(x_min, min_input);
|
||||
// Compute n.
|
||||
const float32x4_t half = vdupq_n_f32(0.5f);
|
||||
const float32x4_t x_minus_half = vsubq_f32(x_max, half);
|
||||
const int32x4_t x_minus_half_floor = vcvtq_s32_f32(x_minus_half);
|
||||
|
||||
// Compute 2^n.
|
||||
const int32x4_t float_exponent_bias = vdupq_n_s32(127);
|
||||
const int32x4_t two_n_exponent =
|
||||
vaddq_s32(x_minus_half_floor, float_exponent_bias);
|
||||
const float32x4_t two_n =
|
||||
vreinterpretq_f32_s32(vshlq_n_s32(two_n_exponent, kFloatExponentShift));
|
||||
// Compute y.
|
||||
const float32x4_t y = vsubq_f32(x_max, vcvtq_f32_s32(x_minus_half_floor));
|
||||
|
||||
// Approximate 2^y ~= C2 * y^2 + C1 * y + C0.
|
||||
const float32x4_t C2 = vdupq_n_f32(3.3718944e-1f);
|
||||
const float32x4_t C1 = vdupq_n_f32(6.5763628e-1f);
|
||||
const float32x4_t C0 = vdupq_n_f32(1.0017247f);
|
||||
float32x4_t exp2_y = C2;
|
||||
exp2_y = vmlaq_f32(C1, y, exp2_y);
|
||||
exp2_y = vmlaq_f32(C0, y, exp2_y);
|
||||
|
||||
// Combine parts.
|
||||
a_exp_b = vmulq_f32(exp2_y, two_n);
|
||||
}
|
||||
|
||||
return a_exp_b;
|
||||
}
|
||||
|
||||
static void OverdriveAndSuppressNEON(AecCore* aec,
|
||||
float hNl[PART_LEN1],
|
||||
const float hNlFb,
|
||||
float efw[2][PART_LEN1]) {
|
||||
int i;
|
||||
const float32x4_t vec_hNlFb = vmovq_n_f32(hNlFb);
|
||||
const float32x4_t vec_one = vdupq_n_f32(1.0f);
|
||||
const float32x4_t vec_minus_one = vdupq_n_f32(-1.0f);
|
||||
const float32x4_t vec_overDriveSm = vmovq_n_f32(aec->overDriveSm);
|
||||
|
||||
// vectorized code (four at once)
|
||||
for (i = 0; i + 3 < PART_LEN1; i += 4) {
|
||||
// Weight subbands
|
||||
float32x4_t vec_hNl = vld1q_f32(&hNl[i]);
|
||||
const float32x4_t vec_weightCurve = vld1q_f32(&WebRtcAec_weightCurve[i]);
|
||||
const uint32x4_t bigger = vcgtq_f32(vec_hNl, vec_hNlFb);
|
||||
const float32x4_t vec_weightCurve_hNlFb = vmulq_f32(vec_weightCurve,
|
||||
vec_hNlFb);
|
||||
const float32x4_t vec_one_weightCurve = vsubq_f32(vec_one, vec_weightCurve);
|
||||
const float32x4_t vec_one_weightCurve_hNl = vmulq_f32(vec_one_weightCurve,
|
||||
vec_hNl);
|
||||
const uint32x4_t vec_if0 = vandq_u32(vmvnq_u32(bigger),
|
||||
vreinterpretq_u32_f32(vec_hNl));
|
||||
const float32x4_t vec_one_weightCurve_add =
|
||||
vaddq_f32(vec_weightCurve_hNlFb, vec_one_weightCurve_hNl);
|
||||
const uint32x4_t vec_if1 =
|
||||
vandq_u32(bigger, vreinterpretq_u32_f32(vec_one_weightCurve_add));
|
||||
|
||||
vec_hNl = vreinterpretq_f32_u32(vorrq_u32(vec_if0, vec_if1));
|
||||
|
||||
{
|
||||
const float32x4_t vec_overDriveCurve =
|
||||
vld1q_f32(&WebRtcAec_overDriveCurve[i]);
|
||||
const float32x4_t vec_overDriveSm_overDriveCurve =
|
||||
vmulq_f32(vec_overDriveSm, vec_overDriveCurve);
|
||||
vec_hNl = vpowq_f32(vec_hNl, vec_overDriveSm_overDriveCurve);
|
||||
vst1q_f32(&hNl[i], vec_hNl);
|
||||
}
|
||||
|
||||
// Suppress error signal
|
||||
{
|
||||
float32x4_t vec_efw_re = vld1q_f32(&efw[0][i]);
|
||||
float32x4_t vec_efw_im = vld1q_f32(&efw[1][i]);
|
||||
vec_efw_re = vmulq_f32(vec_efw_re, vec_hNl);
|
||||
vec_efw_im = vmulq_f32(vec_efw_im, vec_hNl);
|
||||
|
||||
// Ooura fft returns incorrect sign on imaginary component. It matters
|
||||
// here because we are making an additive change with comfort noise.
|
||||
vec_efw_im = vmulq_f32(vec_efw_im, vec_minus_one);
|
||||
vst1q_f32(&efw[0][i], vec_efw_re);
|
||||
vst1q_f32(&efw[1][i], vec_efw_im);
|
||||
}
|
||||
}
|
||||
|
||||
// scalar code for the remaining items.
|
||||
for (; i < PART_LEN1; i++) {
|
||||
// Weight subbands
|
||||
if (hNl[i] > hNlFb) {
|
||||
hNl[i] = WebRtcAec_weightCurve[i] * hNlFb +
|
||||
(1 - WebRtcAec_weightCurve[i]) * hNl[i];
|
||||
}
|
||||
|
||||
hNl[i] = powf(hNl[i], aec->overDriveSm * WebRtcAec_overDriveCurve[i]);
|
||||
|
||||
// Suppress error signal
|
||||
efw[0][i] *= hNl[i];
|
||||
efw[1][i] *= hNl[i];
|
||||
|
||||
// Ooura fft returns incorrect sign on imaginary component. It matters
|
||||
// here because we are making an additive change with comfort noise.
|
||||
efw[1][i] *= -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int PartitionDelay(const AecCore* aec) {
|
||||
// Measures the energy in each filter partition and returns the partition with
|
||||
// highest energy.
|
||||
// TODO(bjornv): Spread computational cost by computing one partition per
|
||||
// block?
|
||||
float wfEnMax = 0;
|
||||
int i;
|
||||
int delay = 0;
|
||||
|
||||
for (i = 0; i < aec->num_partitions; i++) {
|
||||
int j;
|
||||
int pos = i * PART_LEN1;
|
||||
float wfEn = 0;
|
||||
float32x4_t vec_wfEn = vdupq_n_f32(0.0f);
|
||||
// vectorized code (four at once)
|
||||
for (j = 0; j + 3 < PART_LEN1; j += 4) {
|
||||
const float32x4_t vec_wfBuf0 = vld1q_f32(&aec->wfBuf[0][pos + j]);
|
||||
const float32x4_t vec_wfBuf1 = vld1q_f32(&aec->wfBuf[1][pos + j]);
|
||||
vec_wfEn = vmlaq_f32(vec_wfEn, vec_wfBuf0, vec_wfBuf0);
|
||||
vec_wfEn = vmlaq_f32(vec_wfEn, vec_wfBuf1, vec_wfBuf1);
|
||||
}
|
||||
{
|
||||
float32x2_t vec_total;
|
||||
// A B C D
|
||||
vec_total = vpadd_f32(vget_low_f32(vec_wfEn), vget_high_f32(vec_wfEn));
|
||||
// A+B C+D
|
||||
vec_total = vpadd_f32(vec_total, vec_total);
|
||||
// A+B+C+D A+B+C+D
|
||||
wfEn = vget_lane_f32(vec_total, 0);
|
||||
}
|
||||
|
||||
// scalar code for the remaining items.
|
||||
for (; j < PART_LEN1; j++) {
|
||||
wfEn += aec->wfBuf[0][pos + j] * aec->wfBuf[0][pos + j] +
|
||||
aec->wfBuf[1][pos + j] * aec->wfBuf[1][pos + j];
|
||||
}
|
||||
|
||||
if (wfEn > wfEnMax) {
|
||||
wfEnMax = wfEn;
|
||||
delay = i;
|
||||
}
|
||||
}
|
||||
return delay;
|
||||
}
|
||||
|
||||
// Updates the following smoothed Power Spectral Densities (PSD):
|
||||
// - sd : near-end
|
||||
// - se : residual echo
|
||||
// - sx : far-end
|
||||
// - sde : cross-PSD of near-end and residual echo
|
||||
// - sxd : cross-PSD of near-end and far-end
|
||||
//
|
||||
// In addition to updating the PSDs, also the filter diverge state is determined
|
||||
// upon actions are taken.
|
||||
static void SmoothedPSD(AecCore* aec,
|
||||
float efw[2][PART_LEN1],
|
||||
float dfw[2][PART_LEN1],
|
||||
float xfw[2][PART_LEN1]) {
|
||||
// Power estimate smoothing coefficients.
|
||||
const float* ptrGCoh = aec->extended_filter_enabled
|
||||
? WebRtcAec_kExtendedSmoothingCoefficients[aec->mult - 1]
|
||||
: WebRtcAec_kNormalSmoothingCoefficients[aec->mult - 1];
|
||||
int i;
|
||||
float sdSum = 0, seSum = 0;
|
||||
const float32x4_t vec_15 = vdupq_n_f32(WebRtcAec_kMinFarendPSD);
|
||||
float32x4_t vec_sdSum = vdupq_n_f32(0.0f);
|
||||
float32x4_t vec_seSum = vdupq_n_f32(0.0f);
|
||||
|
||||
for (i = 0; i + 3 < PART_LEN1; i += 4) {
|
||||
const float32x4_t vec_dfw0 = vld1q_f32(&dfw[0][i]);
|
||||
const float32x4_t vec_dfw1 = vld1q_f32(&dfw[1][i]);
|
||||
const float32x4_t vec_efw0 = vld1q_f32(&efw[0][i]);
|
||||
const float32x4_t vec_efw1 = vld1q_f32(&efw[1][i]);
|
||||
const float32x4_t vec_xfw0 = vld1q_f32(&xfw[0][i]);
|
||||
const float32x4_t vec_xfw1 = vld1q_f32(&xfw[1][i]);
|
||||
float32x4_t vec_sd = vmulq_n_f32(vld1q_f32(&aec->sd[i]), ptrGCoh[0]);
|
||||
float32x4_t vec_se = vmulq_n_f32(vld1q_f32(&aec->se[i]), ptrGCoh[0]);
|
||||
float32x4_t vec_sx = vmulq_n_f32(vld1q_f32(&aec->sx[i]), ptrGCoh[0]);
|
||||
float32x4_t vec_dfw_sumsq = vmulq_f32(vec_dfw0, vec_dfw0);
|
||||
float32x4_t vec_efw_sumsq = vmulq_f32(vec_efw0, vec_efw0);
|
||||
float32x4_t vec_xfw_sumsq = vmulq_f32(vec_xfw0, vec_xfw0);
|
||||
|
||||
vec_dfw_sumsq = vmlaq_f32(vec_dfw_sumsq, vec_dfw1, vec_dfw1);
|
||||
vec_efw_sumsq = vmlaq_f32(vec_efw_sumsq, vec_efw1, vec_efw1);
|
||||
vec_xfw_sumsq = vmlaq_f32(vec_xfw_sumsq, vec_xfw1, vec_xfw1);
|
||||
vec_xfw_sumsq = vmaxq_f32(vec_xfw_sumsq, vec_15);
|
||||
vec_sd = vmlaq_n_f32(vec_sd, vec_dfw_sumsq, ptrGCoh[1]);
|
||||
vec_se = vmlaq_n_f32(vec_se, vec_efw_sumsq, ptrGCoh[1]);
|
||||
vec_sx = vmlaq_n_f32(vec_sx, vec_xfw_sumsq, ptrGCoh[1]);
|
||||
|
||||
vst1q_f32(&aec->sd[i], vec_sd);
|
||||
vst1q_f32(&aec->se[i], vec_se);
|
||||
vst1q_f32(&aec->sx[i], vec_sx);
|
||||
|
||||
{
|
||||
float32x4x2_t vec_sde = vld2q_f32(&aec->sde[i][0]);
|
||||
float32x4_t vec_dfwefw0011 = vmulq_f32(vec_dfw0, vec_efw0);
|
||||
float32x4_t vec_dfwefw0110 = vmulq_f32(vec_dfw0, vec_efw1);
|
||||
vec_sde.val[0] = vmulq_n_f32(vec_sde.val[0], ptrGCoh[0]);
|
||||
vec_sde.val[1] = vmulq_n_f32(vec_sde.val[1], ptrGCoh[0]);
|
||||
vec_dfwefw0011 = vmlaq_f32(vec_dfwefw0011, vec_dfw1, vec_efw1);
|
||||
vec_dfwefw0110 = vmlsq_f32(vec_dfwefw0110, vec_dfw1, vec_efw0);
|
||||
vec_sde.val[0] = vmlaq_n_f32(vec_sde.val[0], vec_dfwefw0011, ptrGCoh[1]);
|
||||
vec_sde.val[1] = vmlaq_n_f32(vec_sde.val[1], vec_dfwefw0110, ptrGCoh[1]);
|
||||
vst2q_f32(&aec->sde[i][0], vec_sde);
|
||||
}
|
||||
|
||||
{
|
||||
float32x4x2_t vec_sxd = vld2q_f32(&aec->sxd[i][0]);
|
||||
float32x4_t vec_dfwxfw0011 = vmulq_f32(vec_dfw0, vec_xfw0);
|
||||
float32x4_t vec_dfwxfw0110 = vmulq_f32(vec_dfw0, vec_xfw1);
|
||||
vec_sxd.val[0] = vmulq_n_f32(vec_sxd.val[0], ptrGCoh[0]);
|
||||
vec_sxd.val[1] = vmulq_n_f32(vec_sxd.val[1], ptrGCoh[0]);
|
||||
vec_dfwxfw0011 = vmlaq_f32(vec_dfwxfw0011, vec_dfw1, vec_xfw1);
|
||||
vec_dfwxfw0110 = vmlsq_f32(vec_dfwxfw0110, vec_dfw1, vec_xfw0);
|
||||
vec_sxd.val[0] = vmlaq_n_f32(vec_sxd.val[0], vec_dfwxfw0011, ptrGCoh[1]);
|
||||
vec_sxd.val[1] = vmlaq_n_f32(vec_sxd.val[1], vec_dfwxfw0110, ptrGCoh[1]);
|
||||
vst2q_f32(&aec->sxd[i][0], vec_sxd);
|
||||
}
|
||||
|
||||
vec_sdSum = vaddq_f32(vec_sdSum, vec_sd);
|
||||
vec_seSum = vaddq_f32(vec_seSum, vec_se);
|
||||
}
|
||||
{
|
||||
float32x2_t vec_sdSum_total;
|
||||
float32x2_t vec_seSum_total;
|
||||
// A B C D
|
||||
vec_sdSum_total = vpadd_f32(vget_low_f32(vec_sdSum),
|
||||
vget_high_f32(vec_sdSum));
|
||||
vec_seSum_total = vpadd_f32(vget_low_f32(vec_seSum),
|
||||
vget_high_f32(vec_seSum));
|
||||
// A+B C+D
|
||||
vec_sdSum_total = vpadd_f32(vec_sdSum_total, vec_sdSum_total);
|
||||
vec_seSum_total = vpadd_f32(vec_seSum_total, vec_seSum_total);
|
||||
// A+B+C+D A+B+C+D
|
||||
sdSum = vget_lane_f32(vec_sdSum_total, 0);
|
||||
seSum = vget_lane_f32(vec_seSum_total, 0);
|
||||
}
|
||||
|
||||
// scalar code for the remaining items.
|
||||
for (; i < PART_LEN1; i++) {
|
||||
aec->sd[i] = ptrGCoh[0] * aec->sd[i] +
|
||||
ptrGCoh[1] * (dfw[0][i] * dfw[0][i] + dfw[1][i] * dfw[1][i]);
|
||||
aec->se[i] = ptrGCoh[0] * aec->se[i] +
|
||||
ptrGCoh[1] * (efw[0][i] * efw[0][i] + efw[1][i] * efw[1][i]);
|
||||
// We threshold here to protect against the ill-effects of a zero farend.
|
||||
// The threshold is not arbitrarily chosen, but balances protection and
|
||||
// adverse interaction with the algorithm's tuning.
|
||||
// TODO(bjornv): investigate further why this is so sensitive.
|
||||
aec->sx[i] =
|
||||
ptrGCoh[0] * aec->sx[i] +
|
||||
ptrGCoh[1] * WEBRTC_SPL_MAX(
|
||||
xfw[0][i] * xfw[0][i] + xfw[1][i] * xfw[1][i],
|
||||
WebRtcAec_kMinFarendPSD);
|
||||
|
||||
aec->sde[i][0] =
|
||||
ptrGCoh[0] * aec->sde[i][0] +
|
||||
ptrGCoh[1] * (dfw[0][i] * efw[0][i] + dfw[1][i] * efw[1][i]);
|
||||
aec->sde[i][1] =
|
||||
ptrGCoh[0] * aec->sde[i][1] +
|
||||
ptrGCoh[1] * (dfw[0][i] * efw[1][i] - dfw[1][i] * efw[0][i]);
|
||||
|
||||
aec->sxd[i][0] =
|
||||
ptrGCoh[0] * aec->sxd[i][0] +
|
||||
ptrGCoh[1] * (dfw[0][i] * xfw[0][i] + dfw[1][i] * xfw[1][i]);
|
||||
aec->sxd[i][1] =
|
||||
ptrGCoh[0] * aec->sxd[i][1] +
|
||||
ptrGCoh[1] * (dfw[0][i] * xfw[1][i] - dfw[1][i] * xfw[0][i]);
|
||||
|
||||
sdSum += aec->sd[i];
|
||||
seSum += aec->se[i];
|
||||
}
|
||||
|
||||
// Divergent filter safeguard.
|
||||
aec->divergeState = (aec->divergeState ? 1.05f : 1.0f) * seSum > sdSum;
|
||||
|
||||
if (aec->divergeState)
|
||||
memcpy(efw, dfw, sizeof(efw[0][0]) * 2 * PART_LEN1);
|
||||
|
||||
// Reset if error is significantly larger than nearend (13 dB).
|
||||
if (!aec->extended_filter_enabled && seSum > (19.95f * sdSum))
|
||||
memset(aec->wfBuf, 0, sizeof(aec->wfBuf));
|
||||
}
|
||||
|
||||
// Window time domain data to be used by the fft.
|
||||
__inline static void WindowData(float* x_windowed, const float* x) {
|
||||
int i;
|
||||
for (i = 0; i < PART_LEN; i += 4) {
|
||||
const float32x4_t vec_Buf1 = vld1q_f32(&x[i]);
|
||||
const float32x4_t vec_Buf2 = vld1q_f32(&x[PART_LEN + i]);
|
||||
const float32x4_t vec_sqrtHanning = vld1q_f32(&WebRtcAec_sqrtHanning[i]);
|
||||
// A B C D
|
||||
float32x4_t vec_sqrtHanning_rev =
|
||||
vld1q_f32(&WebRtcAec_sqrtHanning[PART_LEN - i - 3]);
|
||||
// B A D C
|
||||
vec_sqrtHanning_rev = vrev64q_f32(vec_sqrtHanning_rev);
|
||||
// D C B A
|
||||
vec_sqrtHanning_rev = vcombine_f32(vget_high_f32(vec_sqrtHanning_rev),
|
||||
vget_low_f32(vec_sqrtHanning_rev));
|
||||
vst1q_f32(&x_windowed[i], vmulq_f32(vec_Buf1, vec_sqrtHanning));
|
||||
vst1q_f32(&x_windowed[PART_LEN + i],
|
||||
vmulq_f32(vec_Buf2, vec_sqrtHanning_rev));
|
||||
}
|
||||
}
|
||||
|
||||
// Puts fft output data into a complex valued array.
|
||||
__inline static void StoreAsComplex(const float* data,
|
||||
float data_complex[2][PART_LEN1]) {
|
||||
int i;
|
||||
for (i = 0; i < PART_LEN; i += 4) {
|
||||
const float32x4x2_t vec_data = vld2q_f32(&data[2 * i]);
|
||||
vst1q_f32(&data_complex[0][i], vec_data.val[0]);
|
||||
vst1q_f32(&data_complex[1][i], vec_data.val[1]);
|
||||
}
|
||||
// fix beginning/end values
|
||||
data_complex[1][0] = 0;
|
||||
data_complex[1][PART_LEN] = 0;
|
||||
data_complex[0][0] = data[0];
|
||||
data_complex[0][PART_LEN] = data[1];
|
||||
}
|
||||
|
||||
static void SubbandCoherenceNEON(AecCore* aec,
|
||||
float efw[2][PART_LEN1],
|
||||
float xfw[2][PART_LEN1],
|
||||
float* fft,
|
||||
float* cohde,
|
||||
float* cohxd) {
|
||||
float dfw[2][PART_LEN1];
|
||||
int i;
|
||||
|
||||
if (aec->delayEstCtr == 0)
|
||||
aec->delayIdx = PartitionDelay(aec);
|
||||
|
||||
// Use delayed far.
|
||||
memcpy(xfw,
|
||||
aec->xfwBuf + aec->delayIdx * PART_LEN1,
|
||||
sizeof(xfw[0][0]) * 2 * PART_LEN1);
|
||||
|
||||
// Windowed near fft
|
||||
WindowData(fft, aec->dBuf);
|
||||
aec_rdft_forward_128(fft);
|
||||
StoreAsComplex(fft, dfw);
|
||||
|
||||
// Windowed error fft
|
||||
WindowData(fft, aec->eBuf);
|
||||
aec_rdft_forward_128(fft);
|
||||
StoreAsComplex(fft, efw);
|
||||
|
||||
SmoothedPSD(aec, efw, dfw, xfw);
|
||||
|
||||
{
|
||||
const float32x4_t vec_1eminus10 = vdupq_n_f32(1e-10f);
|
||||
|
||||
// Subband coherence
|
||||
for (i = 0; i + 3 < PART_LEN1; i += 4) {
|
||||
const float32x4_t vec_sd = vld1q_f32(&aec->sd[i]);
|
||||
const float32x4_t vec_se = vld1q_f32(&aec->se[i]);
|
||||
const float32x4_t vec_sx = vld1q_f32(&aec->sx[i]);
|
||||
const float32x4_t vec_sdse = vmlaq_f32(vec_1eminus10, vec_sd, vec_se);
|
||||
const float32x4_t vec_sdsx = vmlaq_f32(vec_1eminus10, vec_sd, vec_sx);
|
||||
float32x4x2_t vec_sde = vld2q_f32(&aec->sde[i][0]);
|
||||
float32x4x2_t vec_sxd = vld2q_f32(&aec->sxd[i][0]);
|
||||
float32x4_t vec_cohde = vmulq_f32(vec_sde.val[0], vec_sde.val[0]);
|
||||
float32x4_t vec_cohxd = vmulq_f32(vec_sxd.val[0], vec_sxd.val[0]);
|
||||
vec_cohde = vmlaq_f32(vec_cohde, vec_sde.val[1], vec_sde.val[1]);
|
||||
vec_cohde = vdivq_f32(vec_cohde, vec_sdse);
|
||||
vec_cohxd = vmlaq_f32(vec_cohxd, vec_sxd.val[1], vec_sxd.val[1]);
|
||||
vec_cohxd = vdivq_f32(vec_cohxd, vec_sdsx);
|
||||
|
||||
vst1q_f32(&cohde[i], vec_cohde);
|
||||
vst1q_f32(&cohxd[i], vec_cohxd);
|
||||
}
|
||||
}
|
||||
// scalar code for the remaining items.
|
||||
for (; i < PART_LEN1; i++) {
|
||||
cohde[i] =
|
||||
(aec->sde[i][0] * aec->sde[i][0] + aec->sde[i][1] * aec->sde[i][1]) /
|
||||
(aec->sd[i] * aec->se[i] + 1e-10f);
|
||||
cohxd[i] =
|
||||
(aec->sxd[i][0] * aec->sxd[i][0] + aec->sxd[i][1] * aec->sxd[i][1]) /
|
||||
(aec->sx[i] * aec->sd[i] + 1e-10f);
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcAec_InitAec_neon(void) {
|
||||
WebRtcAec_FilterFar = FilterFarNEON;
|
||||
WebRtcAec_ScaleErrorSignal = ScaleErrorSignalNEON;
|
||||
WebRtcAec_FilterAdaptation = FilterAdaptationNEON;
|
||||
WebRtcAec_OverdriveAndSuppress = OverdriveAndSuppressNEON;
|
||||
WebRtcAec_SubbandCoherence = SubbandCoherenceNEON;
|
||||
}
|
||||
|
||||
@@ -12,35 +12,33 @@
|
||||
* The core AEC algorithm, SSE2 version of speed-critical functions.
|
||||
*/
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
#if defined(WEBRTC_USE_SSE2)
|
||||
#include <emmintrin.h>
|
||||
#include <math.h>
|
||||
#include <string.h> // memset
|
||||
|
||||
#include "aec_core.h"
|
||||
#include "aec_rdft.h"
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_common.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_core_internal.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_rdft.h"
|
||||
|
||||
__inline static float MulRe(float aRe, float aIm, float bRe, float bIm)
|
||||
{
|
||||
__inline static float MulRe(float aRe, float aIm, float bRe, float bIm) {
|
||||
return aRe * bRe - aIm * bIm;
|
||||
}
|
||||
|
||||
__inline static float MulIm(float aRe, float aIm, float bRe, float bIm)
|
||||
{
|
||||
__inline static float MulIm(float aRe, float aIm, float bRe, float bIm) {
|
||||
return aRe * bIm + aIm * bRe;
|
||||
}
|
||||
|
||||
static void FilterFarSSE2(aec_t *aec, float yf[2][PART_LEN1])
|
||||
{
|
||||
static void FilterFarSSE2(AecCore* aec, float yf[2][PART_LEN1]) {
|
||||
int i;
|
||||
for (i = 0; i < NR_PART; i++) {
|
||||
const int num_partitions = aec->num_partitions;
|
||||
for (i = 0; i < num_partitions; i++) {
|
||||
int j;
|
||||
int xPos = (i + aec->xfBufBlockPos) * PART_LEN1;
|
||||
int pos = i * PART_LEN1;
|
||||
// Check for wrap
|
||||
if (i + aec->xfBufBlockPos >= NR_PART) {
|
||||
xPos -= NR_PART*(PART_LEN1);
|
||||
if (i + aec->xfBufBlockPos >= num_partitions) {
|
||||
xPos -= num_partitions * (PART_LEN1);
|
||||
}
|
||||
|
||||
// vectorized code (four at once)
|
||||
@@ -64,19 +62,25 @@ static void FilterFarSSE2(aec_t *aec, float yf[2][PART_LEN1])
|
||||
}
|
||||
// scalar code for the remaining items.
|
||||
for (; j < PART_LEN1; j++) {
|
||||
yf[0][j] += MulRe(aec->xfBuf[0][xPos + j], aec->xfBuf[1][xPos + j],
|
||||
aec->wfBuf[0][ pos + j], aec->wfBuf[1][ pos + j]);
|
||||
yf[1][j] += MulIm(aec->xfBuf[0][xPos + j], aec->xfBuf[1][xPos + j],
|
||||
aec->wfBuf[0][ pos + j], aec->wfBuf[1][ pos + j]);
|
||||
yf[0][j] += MulRe(aec->xfBuf[0][xPos + j],
|
||||
aec->xfBuf[1][xPos + j],
|
||||
aec->wfBuf[0][pos + j],
|
||||
aec->wfBuf[1][pos + j]);
|
||||
yf[1][j] += MulIm(aec->xfBuf[0][xPos + j],
|
||||
aec->xfBuf[1][xPos + j],
|
||||
aec->wfBuf[0][pos + j],
|
||||
aec->wfBuf[1][pos + j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ScaleErrorSignalSSE2(aec_t *aec, float ef[2][PART_LEN1])
|
||||
{
|
||||
static void ScaleErrorSignalSSE2(AecCore* aec, float ef[2][PART_LEN1]) {
|
||||
const __m128 k1e_10f = _mm_set1_ps(1e-10f);
|
||||
const __m128 kThresh = _mm_set1_ps(aec->errThresh);
|
||||
const __m128 kMu = _mm_set1_ps(aec->mu);
|
||||
const __m128 kMu = aec->extended_filter_enabled ? _mm_set1_ps(kExtendedMu)
|
||||
: _mm_set1_ps(aec->normal_mu);
|
||||
const __m128 kThresh = aec->extended_filter_enabled
|
||||
? _mm_set1_ps(kExtendedErrorThreshold)
|
||||
: _mm_set1_ps(aec->normal_error_threshold);
|
||||
|
||||
int i;
|
||||
// vectorized code (four at once)
|
||||
@@ -110,36 +114,46 @@ static void ScaleErrorSignalSSE2(aec_t *aec, float ef[2][PART_LEN1])
|
||||
_mm_storeu_ps(&ef[1][i], ef_im);
|
||||
}
|
||||
// scalar code for the remaining items.
|
||||
for (; i < (PART_LEN1); i++) {
|
||||
float absEf;
|
||||
ef[0][i] /= (aec->xPow[i] + 1e-10f);
|
||||
ef[1][i] /= (aec->xPow[i] + 1e-10f);
|
||||
absEf = sqrtf(ef[0][i] * ef[0][i] + ef[1][i] * ef[1][i]);
|
||||
{
|
||||
const float mu =
|
||||
aec->extended_filter_enabled ? kExtendedMu : aec->normal_mu;
|
||||
const float error_threshold = aec->extended_filter_enabled
|
||||
? kExtendedErrorThreshold
|
||||
: aec->normal_error_threshold;
|
||||
for (; i < (PART_LEN1); i++) {
|
||||
float abs_ef;
|
||||
ef[0][i] /= (aec->xPow[i] + 1e-10f);
|
||||
ef[1][i] /= (aec->xPow[i] + 1e-10f);
|
||||
abs_ef = sqrtf(ef[0][i] * ef[0][i] + ef[1][i] * ef[1][i]);
|
||||
|
||||
if (absEf > aec->errThresh) {
|
||||
absEf = aec->errThresh / (absEf + 1e-10f);
|
||||
ef[0][i] *= absEf;
|
||||
ef[1][i] *= absEf;
|
||||
if (abs_ef > error_threshold) {
|
||||
abs_ef = error_threshold / (abs_ef + 1e-10f);
|
||||
ef[0][i] *= abs_ef;
|
||||
ef[1][i] *= abs_ef;
|
||||
}
|
||||
|
||||
// Stepsize factor
|
||||
ef[0][i] *= mu;
|
||||
ef[1][i] *= mu;
|
||||
}
|
||||
|
||||
// Stepsize factor
|
||||
ef[0][i] *= aec->mu;
|
||||
ef[1][i] *= aec->mu;
|
||||
}
|
||||
}
|
||||
|
||||
static void FilterAdaptationSSE2(aec_t *aec, float *fft, float ef[2][PART_LEN1]) {
|
||||
static void FilterAdaptationSSE2(AecCore* aec,
|
||||
float* fft,
|
||||
float ef[2][PART_LEN1]) {
|
||||
int i, j;
|
||||
for (i = 0; i < NR_PART; i++) {
|
||||
int xPos = (i + aec->xfBufBlockPos)*(PART_LEN1);
|
||||
const int num_partitions = aec->num_partitions;
|
||||
for (i = 0; i < num_partitions; i++) {
|
||||
int xPos = (i + aec->xfBufBlockPos) * (PART_LEN1);
|
||||
int pos = i * PART_LEN1;
|
||||
// Check for wrap
|
||||
if (i + aec->xfBufBlockPos >= NR_PART) {
|
||||
xPos -= NR_PART * PART_LEN1;
|
||||
if (i + aec->xfBufBlockPos >= num_partitions) {
|
||||
xPos -= num_partitions * PART_LEN1;
|
||||
}
|
||||
|
||||
// Process the whole array...
|
||||
for (j = 0; j < PART_LEN; j+= 4) {
|
||||
for (j = 0; j < PART_LEN; j += 4) {
|
||||
// Load xfBuf and ef.
|
||||
const __m128 xfBuf_re = _mm_loadu_ps(&aec->xfBuf[0][xPos + j]);
|
||||
const __m128 xfBuf_im = _mm_loadu_ps(&aec->xfBuf[1][xPos + j]);
|
||||
@@ -158,22 +172,23 @@ static void FilterAdaptationSSE2(aec_t *aec, float *fft, float ef[2][PART_LEN1])
|
||||
const __m128 g = _mm_unpacklo_ps(e, f);
|
||||
const __m128 h = _mm_unpackhi_ps(e, f);
|
||||
// Store
|
||||
_mm_storeu_ps(&fft[2*j + 0], g);
|
||||
_mm_storeu_ps(&fft[2*j + 4], h);
|
||||
_mm_storeu_ps(&fft[2 * j + 0], g);
|
||||
_mm_storeu_ps(&fft[2 * j + 4], h);
|
||||
}
|
||||
// ... and fixup the first imaginary entry.
|
||||
fft[1] = MulRe(aec->xfBuf[0][xPos + PART_LEN],
|
||||
-aec->xfBuf[1][xPos + PART_LEN],
|
||||
ef[0][PART_LEN], ef[1][PART_LEN]);
|
||||
ef[0][PART_LEN],
|
||||
ef[1][PART_LEN]);
|
||||
|
||||
aec_rdft_inverse_128(fft);
|
||||
memset(fft + PART_LEN, 0, sizeof(float)*PART_LEN);
|
||||
memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN);
|
||||
|
||||
// fft scaling
|
||||
{
|
||||
float scale = 2.0f / PART_LEN2;
|
||||
const __m128 scale_ps = _mm_load_ps1(&scale);
|
||||
for (j = 0; j < PART_LEN; j+=4) {
|
||||
for (j = 0; j < PART_LEN; j += 4) {
|
||||
const __m128 fft_ps = _mm_loadu_ps(&fft[j]);
|
||||
const __m128 fft_scale = _mm_mul_ps(fft_ps, scale_ps);
|
||||
_mm_storeu_ps(&fft[j], fft_scale);
|
||||
@@ -184,13 +199,15 @@ static void FilterAdaptationSSE2(aec_t *aec, float *fft, float ef[2][PART_LEN1])
|
||||
{
|
||||
float wt1 = aec->wfBuf[1][pos];
|
||||
aec->wfBuf[0][pos + PART_LEN] += fft[1];
|
||||
for (j = 0; j < PART_LEN; j+= 4) {
|
||||
for (j = 0; j < PART_LEN; j += 4) {
|
||||
__m128 wtBuf_re = _mm_loadu_ps(&aec->wfBuf[0][pos + j]);
|
||||
__m128 wtBuf_im = _mm_loadu_ps(&aec->wfBuf[1][pos + j]);
|
||||
const __m128 fft0 = _mm_loadu_ps(&fft[2 * j + 0]);
|
||||
const __m128 fft4 = _mm_loadu_ps(&fft[2 * j + 4]);
|
||||
const __m128 fft_re = _mm_shuffle_ps(fft0, fft4, _MM_SHUFFLE(2, 0, 2 ,0));
|
||||
const __m128 fft_im = _mm_shuffle_ps(fft0, fft4, _MM_SHUFFLE(3, 1, 3 ,1));
|
||||
const __m128 fft_re =
|
||||
_mm_shuffle_ps(fft0, fft4, _MM_SHUFFLE(2, 0, 2, 0));
|
||||
const __m128 fft_im =
|
||||
_mm_shuffle_ps(fft0, fft4, _MM_SHUFFLE(3, 1, 3, 1));
|
||||
wtBuf_re = _mm_add_ps(wtBuf_re, fft_re);
|
||||
wtBuf_im = _mm_add_ps(wtBuf_im, fft_im);
|
||||
_mm_storeu_ps(&aec->wfBuf[0][pos + j], wtBuf_re);
|
||||
@@ -201,8 +218,7 @@ static void FilterAdaptationSSE2(aec_t *aec, float *fft, float ef[2][PART_LEN1])
|
||||
}
|
||||
}
|
||||
|
||||
static __m128 mm_pow_ps(__m128 a, __m128 b)
|
||||
{
|
||||
static __m128 mm_pow_ps(__m128 a, __m128 b) {
|
||||
// a^b = exp2(b * log2(a))
|
||||
// exp2(x) and log2(x) are calculated using polynomial approximations.
|
||||
__m128 log2_a, b_log2_a, a_exp_b;
|
||||
@@ -227,55 +243,55 @@ static __m128 mm_pow_ps(__m128 a, __m128 b)
|
||||
// compensate the fact that the exponent has been shifted in the top/
|
||||
// fractional part and finally getting rid of the implicit leading one
|
||||
// from the mantissa by substracting it out.
|
||||
static const ALIGN16_BEG int float_exponent_mask[4] ALIGN16_END =
|
||||
{0x7F800000, 0x7F800000, 0x7F800000, 0x7F800000};
|
||||
static const ALIGN16_BEG int eight_biased_exponent[4] ALIGN16_END =
|
||||
{0x43800000, 0x43800000, 0x43800000, 0x43800000};
|
||||
static const ALIGN16_BEG int implicit_leading_one[4] ALIGN16_END =
|
||||
{0x43BF8000, 0x43BF8000, 0x43BF8000, 0x43BF8000};
|
||||
static const ALIGN16_BEG int float_exponent_mask[4] ALIGN16_END = {
|
||||
0x7F800000, 0x7F800000, 0x7F800000, 0x7F800000};
|
||||
static const ALIGN16_BEG int eight_biased_exponent[4] ALIGN16_END = {
|
||||
0x43800000, 0x43800000, 0x43800000, 0x43800000};
|
||||
static const ALIGN16_BEG int implicit_leading_one[4] ALIGN16_END = {
|
||||
0x43BF8000, 0x43BF8000, 0x43BF8000, 0x43BF8000};
|
||||
static const int shift_exponent_into_top_mantissa = 8;
|
||||
const __m128 two_n = _mm_and_ps(a, *((__m128 *)float_exponent_mask));
|
||||
const __m128 n_1 = _mm_castsi128_ps(_mm_srli_epi32(_mm_castps_si128(two_n),
|
||||
shift_exponent_into_top_mantissa));
|
||||
const __m128 n_0 = _mm_or_ps(n_1, *((__m128 *)eight_biased_exponent));
|
||||
const __m128 n = _mm_sub_ps(n_0, *((__m128 *)implicit_leading_one));
|
||||
const __m128 two_n = _mm_and_ps(a, *((__m128*)float_exponent_mask));
|
||||
const __m128 n_1 = _mm_castsi128_ps(_mm_srli_epi32(
|
||||
_mm_castps_si128(two_n), shift_exponent_into_top_mantissa));
|
||||
const __m128 n_0 = _mm_or_ps(n_1, *((__m128*)eight_biased_exponent));
|
||||
const __m128 n = _mm_sub_ps(n_0, *((__m128*)implicit_leading_one));
|
||||
|
||||
// Compute y.
|
||||
static const ALIGN16_BEG int mantissa_mask[4] ALIGN16_END =
|
||||
{0x007FFFFF, 0x007FFFFF, 0x007FFFFF, 0x007FFFFF};
|
||||
static const ALIGN16_BEG int zero_biased_exponent_is_one[4] ALIGN16_END =
|
||||
{0x3F800000, 0x3F800000, 0x3F800000, 0x3F800000};
|
||||
const __m128 mantissa = _mm_and_ps(a, *((__m128 *)mantissa_mask));
|
||||
const __m128 y = _mm_or_ps(
|
||||
mantissa, *((__m128 *)zero_biased_exponent_is_one));
|
||||
static const ALIGN16_BEG int mantissa_mask[4] ALIGN16_END = {
|
||||
0x007FFFFF, 0x007FFFFF, 0x007FFFFF, 0x007FFFFF};
|
||||
static const ALIGN16_BEG int zero_biased_exponent_is_one[4] ALIGN16_END = {
|
||||
0x3F800000, 0x3F800000, 0x3F800000, 0x3F800000};
|
||||
const __m128 mantissa = _mm_and_ps(a, *((__m128*)mantissa_mask));
|
||||
const __m128 y =
|
||||
_mm_or_ps(mantissa, *((__m128*)zero_biased_exponent_is_one));
|
||||
|
||||
// Approximate log2(y) ~= (y - 1) * pol5(y).
|
||||
// pol5(y) = C5 * y^5 + C4 * y^4 + C3 * y^3 + C2 * y^2 + C1 * y + C0
|
||||
static const ALIGN16_BEG float ALIGN16_END C5[4] =
|
||||
{-3.4436006e-2f, -3.4436006e-2f, -3.4436006e-2f, -3.4436006e-2f};
|
||||
static const ALIGN16_BEG float ALIGN16_END C4[4] =
|
||||
{3.1821337e-1f, 3.1821337e-1f, 3.1821337e-1f, 3.1821337e-1f};
|
||||
static const ALIGN16_BEG float ALIGN16_END C3[4] =
|
||||
{-1.2315303f, -1.2315303f, -1.2315303f, -1.2315303f};
|
||||
static const ALIGN16_BEG float ALIGN16_END C2[4] =
|
||||
{2.5988452f, 2.5988452f, 2.5988452f, 2.5988452f};
|
||||
static const ALIGN16_BEG float ALIGN16_END C1[4] =
|
||||
{-3.3241990f, -3.3241990f, -3.3241990f, -3.3241990f};
|
||||
static const ALIGN16_BEG float ALIGN16_END C0[4] =
|
||||
{3.1157899f, 3.1157899f, 3.1157899f, 3.1157899f};
|
||||
const __m128 pol5_y_0 = _mm_mul_ps(y, *((__m128 *)C5));
|
||||
const __m128 pol5_y_1 = _mm_add_ps(pol5_y_0, *((__m128 *)C4));
|
||||
static const ALIGN16_BEG float ALIGN16_END C5[4] = {
|
||||
-3.4436006e-2f, -3.4436006e-2f, -3.4436006e-2f, -3.4436006e-2f};
|
||||
static const ALIGN16_BEG float ALIGN16_END
|
||||
C4[4] = {3.1821337e-1f, 3.1821337e-1f, 3.1821337e-1f, 3.1821337e-1f};
|
||||
static const ALIGN16_BEG float ALIGN16_END
|
||||
C3[4] = {-1.2315303f, -1.2315303f, -1.2315303f, -1.2315303f};
|
||||
static const ALIGN16_BEG float ALIGN16_END
|
||||
C2[4] = {2.5988452f, 2.5988452f, 2.5988452f, 2.5988452f};
|
||||
static const ALIGN16_BEG float ALIGN16_END
|
||||
C1[4] = {-3.3241990f, -3.3241990f, -3.3241990f, -3.3241990f};
|
||||
static const ALIGN16_BEG float ALIGN16_END
|
||||
C0[4] = {3.1157899f, 3.1157899f, 3.1157899f, 3.1157899f};
|
||||
const __m128 pol5_y_0 = _mm_mul_ps(y, *((__m128*)C5));
|
||||
const __m128 pol5_y_1 = _mm_add_ps(pol5_y_0, *((__m128*)C4));
|
||||
const __m128 pol5_y_2 = _mm_mul_ps(pol5_y_1, y);
|
||||
const __m128 pol5_y_3 = _mm_add_ps(pol5_y_2, *((__m128 *)C3));
|
||||
const __m128 pol5_y_3 = _mm_add_ps(pol5_y_2, *((__m128*)C3));
|
||||
const __m128 pol5_y_4 = _mm_mul_ps(pol5_y_3, y);
|
||||
const __m128 pol5_y_5 = _mm_add_ps(pol5_y_4, *((__m128 *)C2));
|
||||
const __m128 pol5_y_5 = _mm_add_ps(pol5_y_4, *((__m128*)C2));
|
||||
const __m128 pol5_y_6 = _mm_mul_ps(pol5_y_5, y);
|
||||
const __m128 pol5_y_7 = _mm_add_ps(pol5_y_6, *((__m128 *)C1));
|
||||
const __m128 pol5_y_7 = _mm_add_ps(pol5_y_6, *((__m128*)C1));
|
||||
const __m128 pol5_y_8 = _mm_mul_ps(pol5_y_7, y);
|
||||
const __m128 pol5_y = _mm_add_ps(pol5_y_8, *((__m128 *)C0));
|
||||
const __m128 y_minus_one = _mm_sub_ps(
|
||||
y, *((__m128 *)zero_biased_exponent_is_one));
|
||||
const __m128 log2_y = _mm_mul_ps(y_minus_one , pol5_y);
|
||||
const __m128 pol5_y = _mm_add_ps(pol5_y_8, *((__m128*)C0));
|
||||
const __m128 y_minus_one =
|
||||
_mm_sub_ps(y, *((__m128*)zero_biased_exponent_is_one));
|
||||
const __m128 log2_y = _mm_mul_ps(y_minus_one, pol5_y);
|
||||
|
||||
// Combine parts.
|
||||
log2_a = _mm_add_ps(n, log2_y);
|
||||
@@ -299,38 +315,38 @@ static __m128 mm_pow_ps(__m128 a, __m128 b)
|
||||
// maximum relative error of 0.17%.
|
||||
|
||||
// To avoid over/underflow, we reduce the range of input to ]-127, 129].
|
||||
static const ALIGN16_BEG float max_input[4] ALIGN16_END =
|
||||
{129.f, 129.f, 129.f, 129.f};
|
||||
static const ALIGN16_BEG float min_input[4] ALIGN16_END =
|
||||
{-126.99999f, -126.99999f, -126.99999f, -126.99999f};
|
||||
const __m128 x_min = _mm_min_ps(b_log2_a, *((__m128 *)max_input));
|
||||
const __m128 x_max = _mm_max_ps(x_min, *((__m128 *)min_input));
|
||||
static const ALIGN16_BEG float max_input[4] ALIGN16_END = {129.f, 129.f,
|
||||
129.f, 129.f};
|
||||
static const ALIGN16_BEG float min_input[4] ALIGN16_END = {
|
||||
-126.99999f, -126.99999f, -126.99999f, -126.99999f};
|
||||
const __m128 x_min = _mm_min_ps(b_log2_a, *((__m128*)max_input));
|
||||
const __m128 x_max = _mm_max_ps(x_min, *((__m128*)min_input));
|
||||
// Compute n.
|
||||
static const ALIGN16_BEG float half[4] ALIGN16_END =
|
||||
{0.5f, 0.5f, 0.5f, 0.5f};
|
||||
const __m128 x_minus_half = _mm_sub_ps(x_max, *((__m128 *)half));
|
||||
static const ALIGN16_BEG float half[4] ALIGN16_END = {0.5f, 0.5f,
|
||||
0.5f, 0.5f};
|
||||
const __m128 x_minus_half = _mm_sub_ps(x_max, *((__m128*)half));
|
||||
const __m128i x_minus_half_floor = _mm_cvtps_epi32(x_minus_half);
|
||||
// Compute 2^n.
|
||||
static const ALIGN16_BEG int float_exponent_bias[4] ALIGN16_END =
|
||||
{127, 127, 127, 127};
|
||||
static const ALIGN16_BEG int float_exponent_bias[4] ALIGN16_END = {
|
||||
127, 127, 127, 127};
|
||||
static const int float_exponent_shift = 23;
|
||||
const __m128i two_n_exponent = _mm_add_epi32(
|
||||
x_minus_half_floor, *((__m128i *)float_exponent_bias));
|
||||
const __m128 two_n = _mm_castsi128_ps(_mm_slli_epi32(
|
||||
two_n_exponent, float_exponent_shift));
|
||||
const __m128i two_n_exponent =
|
||||
_mm_add_epi32(x_minus_half_floor, *((__m128i*)float_exponent_bias));
|
||||
const __m128 two_n =
|
||||
_mm_castsi128_ps(_mm_slli_epi32(two_n_exponent, float_exponent_shift));
|
||||
// Compute y.
|
||||
const __m128 y = _mm_sub_ps(x_max, _mm_cvtepi32_ps(x_minus_half_floor));
|
||||
// Approximate 2^y ~= C2 * y^2 + C1 * y + C0.
|
||||
static const ALIGN16_BEG float C2[4] ALIGN16_END =
|
||||
{3.3718944e-1f, 3.3718944e-1f, 3.3718944e-1f, 3.3718944e-1f};
|
||||
static const ALIGN16_BEG float C1[4] ALIGN16_END =
|
||||
{6.5763628e-1f, 6.5763628e-1f, 6.5763628e-1f, 6.5763628e-1f};
|
||||
static const ALIGN16_BEG float C0[4] ALIGN16_END =
|
||||
{1.0017247f, 1.0017247f, 1.0017247f, 1.0017247f};
|
||||
const __m128 exp2_y_0 = _mm_mul_ps(y, *((__m128 *)C2));
|
||||
const __m128 exp2_y_1 = _mm_add_ps(exp2_y_0, *((__m128 *)C1));
|
||||
static const ALIGN16_BEG float C2[4] ALIGN16_END = {
|
||||
3.3718944e-1f, 3.3718944e-1f, 3.3718944e-1f, 3.3718944e-1f};
|
||||
static const ALIGN16_BEG float C1[4] ALIGN16_END = {
|
||||
6.5763628e-1f, 6.5763628e-1f, 6.5763628e-1f, 6.5763628e-1f};
|
||||
static const ALIGN16_BEG float C0[4] ALIGN16_END = {1.0017247f, 1.0017247f,
|
||||
1.0017247f, 1.0017247f};
|
||||
const __m128 exp2_y_0 = _mm_mul_ps(y, *((__m128*)C2));
|
||||
const __m128 exp2_y_1 = _mm_add_ps(exp2_y_0, *((__m128*)C1));
|
||||
const __m128 exp2_y_2 = _mm_mul_ps(exp2_y_1, y);
|
||||
const __m128 exp2_y = _mm_add_ps(exp2_y_2, *((__m128 *)C0));
|
||||
const __m128 exp2_y = _mm_add_ps(exp2_y_2, *((__m128*)C0));
|
||||
|
||||
// Combine parts.
|
||||
a_exp_b = _mm_mul_ps(exp2_y, two_n);
|
||||
@@ -338,10 +354,8 @@ static __m128 mm_pow_ps(__m128 a, __m128 b)
|
||||
return a_exp_b;
|
||||
}
|
||||
|
||||
extern const float WebRtcAec_weightCurve[65];
|
||||
extern const float WebRtcAec_overDriveCurve[65];
|
||||
|
||||
static void OverdriveAndSuppressSSE2(aec_t *aec, float hNl[PART_LEN1],
|
||||
static void OverdriveAndSuppressSSE2(AecCore* aec,
|
||||
float hNl[PART_LEN1],
|
||||
const float hNlFb,
|
||||
float efw[2][PART_LEN1]) {
|
||||
int i;
|
||||
@@ -350,26 +364,25 @@ static void OverdriveAndSuppressSSE2(aec_t *aec, float hNl[PART_LEN1],
|
||||
const __m128 vec_minus_one = _mm_set1_ps(-1.0f);
|
||||
const __m128 vec_overDriveSm = _mm_set1_ps(aec->overDriveSm);
|
||||
// vectorized code (four at once)
|
||||
for (i = 0; i + 3 < PART_LEN1; i+=4) {
|
||||
for (i = 0; i + 3 < PART_LEN1; i += 4) {
|
||||
// Weight subbands
|
||||
__m128 vec_hNl = _mm_loadu_ps(&hNl[i]);
|
||||
const __m128 vec_weightCurve = _mm_loadu_ps(&WebRtcAec_weightCurve[i]);
|
||||
const __m128 bigger = _mm_cmpgt_ps(vec_hNl, vec_hNlFb);
|
||||
const __m128 vec_weightCurve_hNlFb = _mm_mul_ps(
|
||||
vec_weightCurve, vec_hNlFb);
|
||||
const __m128 vec_weightCurve_hNlFb = _mm_mul_ps(vec_weightCurve, vec_hNlFb);
|
||||
const __m128 vec_one_weightCurve = _mm_sub_ps(vec_one, vec_weightCurve);
|
||||
const __m128 vec_one_weightCurve_hNl = _mm_mul_ps(
|
||||
vec_one_weightCurve, vec_hNl);
|
||||
const __m128 vec_one_weightCurve_hNl =
|
||||
_mm_mul_ps(vec_one_weightCurve, vec_hNl);
|
||||
const __m128 vec_if0 = _mm_andnot_ps(bigger, vec_hNl);
|
||||
const __m128 vec_if1 = _mm_and_ps(
|
||||
bigger, _mm_add_ps(vec_weightCurve_hNlFb, vec_one_weightCurve_hNl));
|
||||
vec_hNl = _mm_or_ps(vec_if0, vec_if1);
|
||||
|
||||
{
|
||||
const __m128 vec_overDriveCurve = _mm_loadu_ps(
|
||||
&WebRtcAec_overDriveCurve[i]);
|
||||
const __m128 vec_overDriveSm_overDriveCurve = _mm_mul_ps(
|
||||
vec_overDriveSm, vec_overDriveCurve);
|
||||
const __m128 vec_overDriveCurve =
|
||||
_mm_loadu_ps(&WebRtcAec_overDriveCurve[i]);
|
||||
const __m128 vec_overDriveSm_overDriveCurve =
|
||||
_mm_mul_ps(vec_overDriveSm, vec_overDriveCurve);
|
||||
vec_hNl = mm_pow_ps(vec_hNl, vec_overDriveSm_overDriveCurve);
|
||||
_mm_storeu_ps(&hNl[i], vec_hNl);
|
||||
}
|
||||
@@ -393,7 +406,7 @@ static void OverdriveAndSuppressSSE2(aec_t *aec, float hNl[PART_LEN1],
|
||||
// Weight subbands
|
||||
if (hNl[i] > hNlFb) {
|
||||
hNl[i] = WebRtcAec_weightCurve[i] * hNlFb +
|
||||
(1 - WebRtcAec_weightCurve[i]) * hNl[i];
|
||||
(1 - WebRtcAec_weightCurve[i]) * hNl[i];
|
||||
}
|
||||
hNl[i] = powf(hNl[i], aec->overDriveSm * WebRtcAec_overDriveCurve[i]);
|
||||
|
||||
@@ -407,11 +420,312 @@ static void OverdriveAndSuppressSSE2(aec_t *aec, float hNl[PART_LEN1],
|
||||
}
|
||||
}
|
||||
|
||||
__inline static void _mm_add_ps_4x1(__m128 sum, float *dst) {
|
||||
// A+B C+D
|
||||
sum = _mm_add_ps(sum, _mm_shuffle_ps(sum, sum, _MM_SHUFFLE(0, 0, 3, 2)));
|
||||
// A+B+C+D A+B+C+D
|
||||
sum = _mm_add_ps(sum, _mm_shuffle_ps(sum, sum, _MM_SHUFFLE(1, 1, 1, 1)));
|
||||
_mm_store_ss(dst, sum);
|
||||
}
|
||||
static int PartitionDelay(const AecCore* aec) {
|
||||
// Measures the energy in each filter partition and returns the partition with
|
||||
// highest energy.
|
||||
// TODO(bjornv): Spread computational cost by computing one partition per
|
||||
// block?
|
||||
float wfEnMax = 0;
|
||||
int i;
|
||||
int delay = 0;
|
||||
|
||||
for (i = 0; i < aec->num_partitions; i++) {
|
||||
int j;
|
||||
int pos = i * PART_LEN1;
|
||||
float wfEn = 0;
|
||||
__m128 vec_wfEn = _mm_set1_ps(0.0f);
|
||||
// vectorized code (four at once)
|
||||
for (j = 0; j + 3 < PART_LEN1; j += 4) {
|
||||
const __m128 vec_wfBuf0 = _mm_loadu_ps(&aec->wfBuf[0][pos + j]);
|
||||
const __m128 vec_wfBuf1 = _mm_loadu_ps(&aec->wfBuf[1][pos + j]);
|
||||
vec_wfEn = _mm_add_ps(vec_wfEn, _mm_mul_ps(vec_wfBuf0, vec_wfBuf0));
|
||||
vec_wfEn = _mm_add_ps(vec_wfEn, _mm_mul_ps(vec_wfBuf1, vec_wfBuf1));
|
||||
}
|
||||
_mm_add_ps_4x1(vec_wfEn, &wfEn);
|
||||
|
||||
// scalar code for the remaining items.
|
||||
for (; j < PART_LEN1; j++) {
|
||||
wfEn += aec->wfBuf[0][pos + j] * aec->wfBuf[0][pos + j] +
|
||||
aec->wfBuf[1][pos + j] * aec->wfBuf[1][pos + j];
|
||||
}
|
||||
|
||||
if (wfEn > wfEnMax) {
|
||||
wfEnMax = wfEn;
|
||||
delay = i;
|
||||
}
|
||||
}
|
||||
return delay;
|
||||
}
|
||||
|
||||
// Updates the following smoothed Power Spectral Densities (PSD):
|
||||
// - sd : near-end
|
||||
// - se : residual echo
|
||||
// - sx : far-end
|
||||
// - sde : cross-PSD of near-end and residual echo
|
||||
// - sxd : cross-PSD of near-end and far-end
|
||||
//
|
||||
// In addition to updating the PSDs, also the filter diverge state is determined
|
||||
// upon actions are taken.
|
||||
static void SmoothedPSD(AecCore* aec,
|
||||
float efw[2][PART_LEN1],
|
||||
float dfw[2][PART_LEN1],
|
||||
float xfw[2][PART_LEN1]) {
|
||||
// Power estimate smoothing coefficients.
|
||||
const float* ptrGCoh = aec->extended_filter_enabled
|
||||
? WebRtcAec_kExtendedSmoothingCoefficients[aec->mult - 1]
|
||||
: WebRtcAec_kNormalSmoothingCoefficients[aec->mult - 1];
|
||||
int i;
|
||||
float sdSum = 0, seSum = 0;
|
||||
const __m128 vec_15 = _mm_set1_ps(WebRtcAec_kMinFarendPSD);
|
||||
const __m128 vec_GCoh0 = _mm_set1_ps(ptrGCoh[0]);
|
||||
const __m128 vec_GCoh1 = _mm_set1_ps(ptrGCoh[1]);
|
||||
__m128 vec_sdSum = _mm_set1_ps(0.0f);
|
||||
__m128 vec_seSum = _mm_set1_ps(0.0f);
|
||||
|
||||
for (i = 0; i + 3 < PART_LEN1; i += 4) {
|
||||
const __m128 vec_dfw0 = _mm_loadu_ps(&dfw[0][i]);
|
||||
const __m128 vec_dfw1 = _mm_loadu_ps(&dfw[1][i]);
|
||||
const __m128 vec_efw0 = _mm_loadu_ps(&efw[0][i]);
|
||||
const __m128 vec_efw1 = _mm_loadu_ps(&efw[1][i]);
|
||||
const __m128 vec_xfw0 = _mm_loadu_ps(&xfw[0][i]);
|
||||
const __m128 vec_xfw1 = _mm_loadu_ps(&xfw[1][i]);
|
||||
__m128 vec_sd = _mm_mul_ps(_mm_loadu_ps(&aec->sd[i]), vec_GCoh0);
|
||||
__m128 vec_se = _mm_mul_ps(_mm_loadu_ps(&aec->se[i]), vec_GCoh0);
|
||||
__m128 vec_sx = _mm_mul_ps(_mm_loadu_ps(&aec->sx[i]), vec_GCoh0);
|
||||
__m128 vec_dfw_sumsq = _mm_mul_ps(vec_dfw0, vec_dfw0);
|
||||
__m128 vec_efw_sumsq = _mm_mul_ps(vec_efw0, vec_efw0);
|
||||
__m128 vec_xfw_sumsq = _mm_mul_ps(vec_xfw0, vec_xfw0);
|
||||
vec_dfw_sumsq = _mm_add_ps(vec_dfw_sumsq, _mm_mul_ps(vec_dfw1, vec_dfw1));
|
||||
vec_efw_sumsq = _mm_add_ps(vec_efw_sumsq, _mm_mul_ps(vec_efw1, vec_efw1));
|
||||
vec_xfw_sumsq = _mm_add_ps(vec_xfw_sumsq, _mm_mul_ps(vec_xfw1, vec_xfw1));
|
||||
vec_xfw_sumsq = _mm_max_ps(vec_xfw_sumsq, vec_15);
|
||||
vec_sd = _mm_add_ps(vec_sd, _mm_mul_ps(vec_dfw_sumsq, vec_GCoh1));
|
||||
vec_se = _mm_add_ps(vec_se, _mm_mul_ps(vec_efw_sumsq, vec_GCoh1));
|
||||
vec_sx = _mm_add_ps(vec_sx, _mm_mul_ps(vec_xfw_sumsq, vec_GCoh1));
|
||||
_mm_storeu_ps(&aec->sd[i], vec_sd);
|
||||
_mm_storeu_ps(&aec->se[i], vec_se);
|
||||
_mm_storeu_ps(&aec->sx[i], vec_sx);
|
||||
|
||||
{
|
||||
const __m128 vec_3210 = _mm_loadu_ps(&aec->sde[i][0]);
|
||||
const __m128 vec_7654 = _mm_loadu_ps(&aec->sde[i + 2][0]);
|
||||
__m128 vec_a = _mm_shuffle_ps(vec_3210, vec_7654,
|
||||
_MM_SHUFFLE(2, 0, 2, 0));
|
||||
__m128 vec_b = _mm_shuffle_ps(vec_3210, vec_7654,
|
||||
_MM_SHUFFLE(3, 1, 3, 1));
|
||||
__m128 vec_dfwefw0011 = _mm_mul_ps(vec_dfw0, vec_efw0);
|
||||
__m128 vec_dfwefw0110 = _mm_mul_ps(vec_dfw0, vec_efw1);
|
||||
vec_a = _mm_mul_ps(vec_a, vec_GCoh0);
|
||||
vec_b = _mm_mul_ps(vec_b, vec_GCoh0);
|
||||
vec_dfwefw0011 = _mm_add_ps(vec_dfwefw0011,
|
||||
_mm_mul_ps(vec_dfw1, vec_efw1));
|
||||
vec_dfwefw0110 = _mm_sub_ps(vec_dfwefw0110,
|
||||
_mm_mul_ps(vec_dfw1, vec_efw0));
|
||||
vec_a = _mm_add_ps(vec_a, _mm_mul_ps(vec_dfwefw0011, vec_GCoh1));
|
||||
vec_b = _mm_add_ps(vec_b, _mm_mul_ps(vec_dfwefw0110, vec_GCoh1));
|
||||
_mm_storeu_ps(&aec->sde[i][0], _mm_unpacklo_ps(vec_a, vec_b));
|
||||
_mm_storeu_ps(&aec->sde[i + 2][0], _mm_unpackhi_ps(vec_a, vec_b));
|
||||
}
|
||||
|
||||
{
|
||||
const __m128 vec_3210 = _mm_loadu_ps(&aec->sxd[i][0]);
|
||||
const __m128 vec_7654 = _mm_loadu_ps(&aec->sxd[i + 2][0]);
|
||||
__m128 vec_a = _mm_shuffle_ps(vec_3210, vec_7654,
|
||||
_MM_SHUFFLE(2, 0, 2, 0));
|
||||
__m128 vec_b = _mm_shuffle_ps(vec_3210, vec_7654,
|
||||
_MM_SHUFFLE(3, 1, 3, 1));
|
||||
__m128 vec_dfwxfw0011 = _mm_mul_ps(vec_dfw0, vec_xfw0);
|
||||
__m128 vec_dfwxfw0110 = _mm_mul_ps(vec_dfw0, vec_xfw1);
|
||||
vec_a = _mm_mul_ps(vec_a, vec_GCoh0);
|
||||
vec_b = _mm_mul_ps(vec_b, vec_GCoh0);
|
||||
vec_dfwxfw0011 = _mm_add_ps(vec_dfwxfw0011,
|
||||
_mm_mul_ps(vec_dfw1, vec_xfw1));
|
||||
vec_dfwxfw0110 = _mm_sub_ps(vec_dfwxfw0110,
|
||||
_mm_mul_ps(vec_dfw1, vec_xfw0));
|
||||
vec_a = _mm_add_ps(vec_a, _mm_mul_ps(vec_dfwxfw0011, vec_GCoh1));
|
||||
vec_b = _mm_add_ps(vec_b, _mm_mul_ps(vec_dfwxfw0110, vec_GCoh1));
|
||||
_mm_storeu_ps(&aec->sxd[i][0], _mm_unpacklo_ps(vec_a, vec_b));
|
||||
_mm_storeu_ps(&aec->sxd[i + 2][0], _mm_unpackhi_ps(vec_a, vec_b));
|
||||
}
|
||||
|
||||
vec_sdSum = _mm_add_ps(vec_sdSum, vec_sd);
|
||||
vec_seSum = _mm_add_ps(vec_seSum, vec_se);
|
||||
}
|
||||
|
||||
_mm_add_ps_4x1(vec_sdSum, &sdSum);
|
||||
_mm_add_ps_4x1(vec_seSum, &seSum);
|
||||
|
||||
for (; i < PART_LEN1; i++) {
|
||||
aec->sd[i] = ptrGCoh[0] * aec->sd[i] +
|
||||
ptrGCoh[1] * (dfw[0][i] * dfw[0][i] + dfw[1][i] * dfw[1][i]);
|
||||
aec->se[i] = ptrGCoh[0] * aec->se[i] +
|
||||
ptrGCoh[1] * (efw[0][i] * efw[0][i] + efw[1][i] * efw[1][i]);
|
||||
// We threshold here to protect against the ill-effects of a zero farend.
|
||||
// The threshold is not arbitrarily chosen, but balances protection and
|
||||
// adverse interaction with the algorithm's tuning.
|
||||
// TODO(bjornv): investigate further why this is so sensitive.
|
||||
aec->sx[i] =
|
||||
ptrGCoh[0] * aec->sx[i] +
|
||||
ptrGCoh[1] * WEBRTC_SPL_MAX(
|
||||
xfw[0][i] * xfw[0][i] + xfw[1][i] * xfw[1][i],
|
||||
WebRtcAec_kMinFarendPSD);
|
||||
|
||||
aec->sde[i][0] =
|
||||
ptrGCoh[0] * aec->sde[i][0] +
|
||||
ptrGCoh[1] * (dfw[0][i] * efw[0][i] + dfw[1][i] * efw[1][i]);
|
||||
aec->sde[i][1] =
|
||||
ptrGCoh[0] * aec->sde[i][1] +
|
||||
ptrGCoh[1] * (dfw[0][i] * efw[1][i] - dfw[1][i] * efw[0][i]);
|
||||
|
||||
aec->sxd[i][0] =
|
||||
ptrGCoh[0] * aec->sxd[i][0] +
|
||||
ptrGCoh[1] * (dfw[0][i] * xfw[0][i] + dfw[1][i] * xfw[1][i]);
|
||||
aec->sxd[i][1] =
|
||||
ptrGCoh[0] * aec->sxd[i][1] +
|
||||
ptrGCoh[1] * (dfw[0][i] * xfw[1][i] - dfw[1][i] * xfw[0][i]);
|
||||
|
||||
sdSum += aec->sd[i];
|
||||
seSum += aec->se[i];
|
||||
}
|
||||
|
||||
// Divergent filter safeguard.
|
||||
aec->divergeState = (aec->divergeState ? 1.05f : 1.0f) * seSum > sdSum;
|
||||
|
||||
if (aec->divergeState)
|
||||
memcpy(efw, dfw, sizeof(efw[0][0]) * 2 * PART_LEN1);
|
||||
|
||||
// Reset if error is significantly larger than nearend (13 dB).
|
||||
if (!aec->extended_filter_enabled && seSum > (19.95f * sdSum))
|
||||
memset(aec->wfBuf, 0, sizeof(aec->wfBuf));
|
||||
}
|
||||
|
||||
// Window time domain data to be used by the fft.
|
||||
__inline static void WindowData(float* x_windowed, const float* x) {
|
||||
int i;
|
||||
for (i = 0; i < PART_LEN; i += 4) {
|
||||
const __m128 vec_Buf1 = _mm_loadu_ps(&x[i]);
|
||||
const __m128 vec_Buf2 = _mm_loadu_ps(&x[PART_LEN + i]);
|
||||
const __m128 vec_sqrtHanning = _mm_load_ps(&WebRtcAec_sqrtHanning[i]);
|
||||
// A B C D
|
||||
__m128 vec_sqrtHanning_rev =
|
||||
_mm_loadu_ps(&WebRtcAec_sqrtHanning[PART_LEN - i - 3]);
|
||||
// D C B A
|
||||
vec_sqrtHanning_rev =
|
||||
_mm_shuffle_ps(vec_sqrtHanning_rev, vec_sqrtHanning_rev,
|
||||
_MM_SHUFFLE(0, 1, 2, 3));
|
||||
_mm_storeu_ps(&x_windowed[i], _mm_mul_ps(vec_Buf1, vec_sqrtHanning));
|
||||
_mm_storeu_ps(&x_windowed[PART_LEN + i],
|
||||
_mm_mul_ps(vec_Buf2, vec_sqrtHanning_rev));
|
||||
}
|
||||
}
|
||||
|
||||
// Puts fft output data into a complex valued array.
|
||||
__inline static void StoreAsComplex(const float* data,
|
||||
float data_complex[2][PART_LEN1]) {
|
||||
int i;
|
||||
for (i = 0; i < PART_LEN; i += 4) {
|
||||
const __m128 vec_fft0 = _mm_loadu_ps(&data[2 * i]);
|
||||
const __m128 vec_fft4 = _mm_loadu_ps(&data[2 * i + 4]);
|
||||
const __m128 vec_a = _mm_shuffle_ps(vec_fft0, vec_fft4,
|
||||
_MM_SHUFFLE(2, 0, 2, 0));
|
||||
const __m128 vec_b = _mm_shuffle_ps(vec_fft0, vec_fft4,
|
||||
_MM_SHUFFLE(3, 1, 3, 1));
|
||||
_mm_storeu_ps(&data_complex[0][i], vec_a);
|
||||
_mm_storeu_ps(&data_complex[1][i], vec_b);
|
||||
}
|
||||
// fix beginning/end values
|
||||
data_complex[1][0] = 0;
|
||||
data_complex[1][PART_LEN] = 0;
|
||||
data_complex[0][0] = data[0];
|
||||
data_complex[0][PART_LEN] = data[1];
|
||||
}
|
||||
|
||||
static void SubbandCoherenceSSE2(AecCore* aec,
|
||||
float efw[2][PART_LEN1],
|
||||
float xfw[2][PART_LEN1],
|
||||
float* fft,
|
||||
float* cohde,
|
||||
float* cohxd) {
|
||||
float dfw[2][PART_LEN1];
|
||||
int i;
|
||||
|
||||
if (aec->delayEstCtr == 0)
|
||||
aec->delayIdx = PartitionDelay(aec);
|
||||
|
||||
// Use delayed far.
|
||||
memcpy(xfw,
|
||||
aec->xfwBuf + aec->delayIdx * PART_LEN1,
|
||||
sizeof(xfw[0][0]) * 2 * PART_LEN1);
|
||||
|
||||
// Windowed near fft
|
||||
WindowData(fft, aec->dBuf);
|
||||
aec_rdft_forward_128(fft);
|
||||
StoreAsComplex(fft, dfw);
|
||||
|
||||
// Windowed error fft
|
||||
WindowData(fft, aec->eBuf);
|
||||
aec_rdft_forward_128(fft);
|
||||
StoreAsComplex(fft, efw);
|
||||
|
||||
SmoothedPSD(aec, efw, dfw, xfw);
|
||||
|
||||
{
|
||||
const __m128 vec_1eminus10 = _mm_set1_ps(1e-10f);
|
||||
|
||||
// Subband coherence
|
||||
for (i = 0; i + 3 < PART_LEN1; i += 4) {
|
||||
const __m128 vec_sd = _mm_loadu_ps(&aec->sd[i]);
|
||||
const __m128 vec_se = _mm_loadu_ps(&aec->se[i]);
|
||||
const __m128 vec_sx = _mm_loadu_ps(&aec->sx[i]);
|
||||
const __m128 vec_sdse = _mm_add_ps(vec_1eminus10,
|
||||
_mm_mul_ps(vec_sd, vec_se));
|
||||
const __m128 vec_sdsx = _mm_add_ps(vec_1eminus10,
|
||||
_mm_mul_ps(vec_sd, vec_sx));
|
||||
const __m128 vec_sde_3210 = _mm_loadu_ps(&aec->sde[i][0]);
|
||||
const __m128 vec_sde_7654 = _mm_loadu_ps(&aec->sde[i + 2][0]);
|
||||
const __m128 vec_sxd_3210 = _mm_loadu_ps(&aec->sxd[i][0]);
|
||||
const __m128 vec_sxd_7654 = _mm_loadu_ps(&aec->sxd[i + 2][0]);
|
||||
const __m128 vec_sde_0 = _mm_shuffle_ps(vec_sde_3210, vec_sde_7654,
|
||||
_MM_SHUFFLE(2, 0, 2, 0));
|
||||
const __m128 vec_sde_1 = _mm_shuffle_ps(vec_sde_3210, vec_sde_7654,
|
||||
_MM_SHUFFLE(3, 1, 3, 1));
|
||||
const __m128 vec_sxd_0 = _mm_shuffle_ps(vec_sxd_3210, vec_sxd_7654,
|
||||
_MM_SHUFFLE(2, 0, 2, 0));
|
||||
const __m128 vec_sxd_1 = _mm_shuffle_ps(vec_sxd_3210, vec_sxd_7654,
|
||||
_MM_SHUFFLE(3, 1, 3, 1));
|
||||
__m128 vec_cohde = _mm_mul_ps(vec_sde_0, vec_sde_0);
|
||||
__m128 vec_cohxd = _mm_mul_ps(vec_sxd_0, vec_sxd_0);
|
||||
vec_cohde = _mm_add_ps(vec_cohde, _mm_mul_ps(vec_sde_1, vec_sde_1));
|
||||
vec_cohde = _mm_div_ps(vec_cohde, vec_sdse);
|
||||
vec_cohxd = _mm_add_ps(vec_cohxd, _mm_mul_ps(vec_sxd_1, vec_sxd_1));
|
||||
vec_cohxd = _mm_div_ps(vec_cohxd, vec_sdsx);
|
||||
_mm_storeu_ps(&cohde[i], vec_cohde);
|
||||
_mm_storeu_ps(&cohxd[i], vec_cohxd);
|
||||
}
|
||||
|
||||
// scalar code for the remaining items.
|
||||
for (; i < PART_LEN1; i++) {
|
||||
cohde[i] =
|
||||
(aec->sde[i][0] * aec->sde[i][0] + aec->sde[i][1] * aec->sde[i][1]) /
|
||||
(aec->sd[i] * aec->se[i] + 1e-10f);
|
||||
cohxd[i] =
|
||||
(aec->sxd[i][0] * aec->sxd[i][0] + aec->sxd[i][1] * aec->sxd[i][1]) /
|
||||
(aec->sx[i] * aec->sd[i] + 1e-10f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcAec_InitAec_SSE2(void) {
|
||||
WebRtcAec_FilterFar = FilterFarSSE2;
|
||||
WebRtcAec_ScaleErrorSignal = ScaleErrorSignalSSE2;
|
||||
WebRtcAec_FilterAdaptation = FilterAdaptationSSE2;
|
||||
WebRtcAec_OverdriveAndSuppress = OverdriveAndSuppressSSE2;
|
||||
WebRtcAec_SubbandCoherence = SubbandCoherenceSSE2;
|
||||
}
|
||||
|
||||
#endif // WEBRTC_USE_SSE2
|
||||
|
||||
@@ -19,200 +19,193 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "aec_rdft.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_rdft.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "system_wrappers/interface/cpu_features_wrapper.h"
|
||||
#include "typedefs.h"
|
||||
#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// constants shared by all paths (C, SSE2).
|
||||
float rdft_w[64];
|
||||
// constants used by the C path.
|
||||
float rdft_wk3ri_first[32];
|
||||
float rdft_wk3ri_second[32];
|
||||
// constants used by SSE2 but initialized in C path.
|
||||
ALIGN16_BEG float ALIGN16_END rdft_wk1r[32];
|
||||
ALIGN16_BEG float ALIGN16_END rdft_wk2r[32];
|
||||
ALIGN16_BEG float ALIGN16_END rdft_wk3r[32];
|
||||
ALIGN16_BEG float ALIGN16_END rdft_wk1i[32];
|
||||
ALIGN16_BEG float ALIGN16_END rdft_wk2i[32];
|
||||
ALIGN16_BEG float ALIGN16_END rdft_wk3i[32];
|
||||
ALIGN16_BEG float ALIGN16_END cftmdl_wk1r[4];
|
||||
// These tables used to be computed at run-time. For example, refer to:
|
||||
// https://code.google.com/p/webrtc/source/browse/trunk/webrtc/modules/audio_processing/aec/aec_rdft.c?r=6564
|
||||
// to see the initialization code.
|
||||
const float rdft_w[64] = {
|
||||
1.0000000000f, 0.0000000000f, 0.7071067691f, 0.7071067691f,
|
||||
0.9238795638f, 0.3826834559f, 0.3826834559f, 0.9238795638f,
|
||||
0.9807852507f, 0.1950903237f, 0.5555702448f, 0.8314695954f,
|
||||
0.8314695954f, 0.5555702448f, 0.1950903237f, 0.9807852507f,
|
||||
0.9951847196f, 0.0980171412f, 0.6343933344f, 0.7730104327f,
|
||||
0.8819212914f, 0.4713967443f, 0.2902846634f, 0.9569403529f,
|
||||
0.9569403529f, 0.2902846634f, 0.4713967443f, 0.8819212914f,
|
||||
0.7730104327f, 0.6343933344f, 0.0980171412f, 0.9951847196f,
|
||||
0.7071067691f, 0.4993977249f, 0.4975923598f, 0.4945882559f,
|
||||
0.4903926253f, 0.4850156307f, 0.4784701765f, 0.4707720280f,
|
||||
0.4619397819f, 0.4519946277f, 0.4409606457f, 0.4288643003f,
|
||||
0.4157347977f, 0.4016037583f, 0.3865052164f, 0.3704755902f,
|
||||
0.3535533845f, 0.3357794881f, 0.3171966672f, 0.2978496552f,
|
||||
0.2777851224f, 0.2570513785f, 0.2356983721f, 0.2137775421f,
|
||||
0.1913417280f, 0.1684449315f, 0.1451423317f, 0.1214900985f,
|
||||
0.0975451618f, 0.0733652338f, 0.0490085706f, 0.0245338380f,
|
||||
};
|
||||
const float rdft_wk3ri_first[16] = {
|
||||
1.000000000f, 0.000000000f, 0.382683456f, 0.923879564f,
|
||||
0.831469536f, 0.555570245f, -0.195090353f, 0.980785251f,
|
||||
0.956940353f, 0.290284693f, 0.098017156f, 0.995184720f,
|
||||
0.634393334f, 0.773010492f, -0.471396863f, 0.881921172f,
|
||||
};
|
||||
const float rdft_wk3ri_second[16] = {
|
||||
-0.707106769f, 0.707106769f, -0.923879564f, -0.382683456f,
|
||||
-0.980785251f, 0.195090353f, -0.555570245f, -0.831469536f,
|
||||
-0.881921172f, 0.471396863f, -0.773010492f, -0.634393334f,
|
||||
-0.995184720f, -0.098017156f, -0.290284693f, -0.956940353f,
|
||||
};
|
||||
ALIGN16_BEG const float ALIGN16_END rdft_wk1r[32] = {
|
||||
1.000000000f, 1.000000000f, 0.707106769f, 0.707106769f,
|
||||
0.923879564f, 0.923879564f, 0.382683456f, 0.382683456f,
|
||||
0.980785251f, 0.980785251f, 0.555570245f, 0.555570245f,
|
||||
0.831469595f, 0.831469595f, 0.195090324f, 0.195090324f,
|
||||
0.995184720f, 0.995184720f, 0.634393334f, 0.634393334f,
|
||||
0.881921291f, 0.881921291f, 0.290284663f, 0.290284663f,
|
||||
0.956940353f, 0.956940353f, 0.471396744f, 0.471396744f,
|
||||
0.773010433f, 0.773010433f, 0.098017141f, 0.098017141f,
|
||||
};
|
||||
ALIGN16_BEG const float ALIGN16_END rdft_wk2r[32] = {
|
||||
1.000000000f, 1.000000000f, -0.000000000f, -0.000000000f,
|
||||
0.707106769f, 0.707106769f, -0.707106769f, -0.707106769f,
|
||||
0.923879564f, 0.923879564f, -0.382683456f, -0.382683456f,
|
||||
0.382683456f, 0.382683456f, -0.923879564f, -0.923879564f,
|
||||
0.980785251f, 0.980785251f, -0.195090324f, -0.195090324f,
|
||||
0.555570245f, 0.555570245f, -0.831469595f, -0.831469595f,
|
||||
0.831469595f, 0.831469595f, -0.555570245f, -0.555570245f,
|
||||
0.195090324f, 0.195090324f, -0.980785251f, -0.980785251f,
|
||||
};
|
||||
ALIGN16_BEG const float ALIGN16_END rdft_wk3r[32] = {
|
||||
1.000000000f, 1.000000000f, -0.707106769f, -0.707106769f,
|
||||
0.382683456f, 0.382683456f, -0.923879564f, -0.923879564f,
|
||||
0.831469536f, 0.831469536f, -0.980785251f, -0.980785251f,
|
||||
-0.195090353f, -0.195090353f, -0.555570245f, -0.555570245f,
|
||||
0.956940353f, 0.956940353f, -0.881921172f, -0.881921172f,
|
||||
0.098017156f, 0.098017156f, -0.773010492f, -0.773010492f,
|
||||
0.634393334f, 0.634393334f, -0.995184720f, -0.995184720f,
|
||||
-0.471396863f, -0.471396863f, -0.290284693f, -0.290284693f,
|
||||
};
|
||||
ALIGN16_BEG const float ALIGN16_END rdft_wk1i[32] = {
|
||||
-0.000000000f, 0.000000000f, -0.707106769f, 0.707106769f,
|
||||
-0.382683456f, 0.382683456f, -0.923879564f, 0.923879564f,
|
||||
-0.195090324f, 0.195090324f, -0.831469595f, 0.831469595f,
|
||||
-0.555570245f, 0.555570245f, -0.980785251f, 0.980785251f,
|
||||
-0.098017141f, 0.098017141f, -0.773010433f, 0.773010433f,
|
||||
-0.471396744f, 0.471396744f, -0.956940353f, 0.956940353f,
|
||||
-0.290284663f, 0.290284663f, -0.881921291f, 0.881921291f,
|
||||
-0.634393334f, 0.634393334f, -0.995184720f, 0.995184720f,
|
||||
};
|
||||
ALIGN16_BEG const float ALIGN16_END rdft_wk2i[32] = {
|
||||
-0.000000000f, 0.000000000f, -1.000000000f, 1.000000000f,
|
||||
-0.707106769f, 0.707106769f, -0.707106769f, 0.707106769f,
|
||||
-0.382683456f, 0.382683456f, -0.923879564f, 0.923879564f,
|
||||
-0.923879564f, 0.923879564f, -0.382683456f, 0.382683456f,
|
||||
-0.195090324f, 0.195090324f, -0.980785251f, 0.980785251f,
|
||||
-0.831469595f, 0.831469595f, -0.555570245f, 0.555570245f,
|
||||
-0.555570245f, 0.555570245f, -0.831469595f, 0.831469595f,
|
||||
-0.980785251f, 0.980785251f, -0.195090324f, 0.195090324f,
|
||||
};
|
||||
ALIGN16_BEG const float ALIGN16_END rdft_wk3i[32] = {
|
||||
-0.000000000f, 0.000000000f, -0.707106769f, 0.707106769f,
|
||||
-0.923879564f, 0.923879564f, 0.382683456f, -0.382683456f,
|
||||
-0.555570245f, 0.555570245f, -0.195090353f, 0.195090353f,
|
||||
-0.980785251f, 0.980785251f, 0.831469536f, -0.831469536f,
|
||||
-0.290284693f, 0.290284693f, -0.471396863f, 0.471396863f,
|
||||
-0.995184720f, 0.995184720f, 0.634393334f, -0.634393334f,
|
||||
-0.773010492f, 0.773010492f, 0.098017156f, -0.098017156f,
|
||||
-0.881921172f, 0.881921172f, 0.956940353f, -0.956940353f,
|
||||
};
|
||||
ALIGN16_BEG const float ALIGN16_END cftmdl_wk1r[4] = {
|
||||
0.707106769f, 0.707106769f, 0.707106769f, -0.707106769f,
|
||||
};
|
||||
|
||||
static int ip[16];
|
||||
static void bitrv2_128_C(float* a) {
|
||||
/*
|
||||
Following things have been attempted but are no faster:
|
||||
(a) Storing the swap indexes in a LUT (index calculations are done
|
||||
for 'free' while waiting on memory/L1).
|
||||
(b) Consolidate the load/store of two consecutive floats by a 64 bit
|
||||
integer (execution is memory/L1 bound).
|
||||
(c) Do a mix of floats and 64 bit integer to maximize register
|
||||
utilization (execution is memory/L1 bound).
|
||||
(d) Replacing ip[i] by ((k<<31)>>25) + ((k >> 1)<<5).
|
||||
(e) Hard-coding of the offsets to completely eliminates index
|
||||
calculations.
|
||||
*/
|
||||
|
||||
static void bitrv2_32or128(int n, int *ip, float *a) {
|
||||
// n is 32 or 128
|
||||
int j, j1, k, k1, m, m2;
|
||||
unsigned int j, j1, k, k1;
|
||||
float xr, xi, yr, yi;
|
||||
|
||||
ip[0] = 0;
|
||||
{
|
||||
int l = n;
|
||||
m = 1;
|
||||
while ((m << 3) < l) {
|
||||
l >>= 1;
|
||||
for (j = 0; j < m; j++) {
|
||||
ip[m + j] = ip[j] + l;
|
||||
}
|
||||
m <<= 1;
|
||||
}
|
||||
}
|
||||
m2 = 2 * m;
|
||||
for (k = 0; k < m; k++) {
|
||||
static const int ip[4] = {0, 64, 32, 96};
|
||||
for (k = 0; k < 4; k++) {
|
||||
for (j = 0; j < k; j++) {
|
||||
j1 = 2 * j + ip[k];
|
||||
k1 = 2 * k + ip[j];
|
||||
xr = a[j1];
|
||||
xr = a[j1 + 0];
|
||||
xi = a[j1 + 1];
|
||||
yr = a[k1];
|
||||
yr = a[k1 + 0];
|
||||
yi = a[k1 + 1];
|
||||
a[j1] = yr;
|
||||
a[j1 + 0] = yr;
|
||||
a[j1 + 1] = yi;
|
||||
a[k1] = xr;
|
||||
a[k1 + 0] = xr;
|
||||
a[k1 + 1] = xi;
|
||||
j1 += m2;
|
||||
k1 += 2 * m2;
|
||||
xr = a[j1];
|
||||
j1 += 8;
|
||||
k1 += 16;
|
||||
xr = a[j1 + 0];
|
||||
xi = a[j1 + 1];
|
||||
yr = a[k1];
|
||||
yr = a[k1 + 0];
|
||||
yi = a[k1 + 1];
|
||||
a[j1] = yr;
|
||||
a[j1 + 0] = yr;
|
||||
a[j1 + 1] = yi;
|
||||
a[k1] = xr;
|
||||
a[k1 + 0] = xr;
|
||||
a[k1 + 1] = xi;
|
||||
j1 += m2;
|
||||
k1 -= m2;
|
||||
xr = a[j1];
|
||||
j1 += 8;
|
||||
k1 -= 8;
|
||||
xr = a[j1 + 0];
|
||||
xi = a[j1 + 1];
|
||||
yr = a[k1];
|
||||
yr = a[k1 + 0];
|
||||
yi = a[k1 + 1];
|
||||
a[j1] = yr;
|
||||
a[j1 + 0] = yr;
|
||||
a[j1 + 1] = yi;
|
||||
a[k1] = xr;
|
||||
a[k1 + 0] = xr;
|
||||
a[k1 + 1] = xi;
|
||||
j1 += m2;
|
||||
k1 += 2 * m2;
|
||||
xr = a[j1];
|
||||
j1 += 8;
|
||||
k1 += 16;
|
||||
xr = a[j1 + 0];
|
||||
xi = a[j1 + 1];
|
||||
yr = a[k1];
|
||||
yr = a[k1 + 0];
|
||||
yi = a[k1 + 1];
|
||||
a[j1] = yr;
|
||||
a[j1 + 0] = yr;
|
||||
a[j1 + 1] = yi;
|
||||
a[k1] = xr;
|
||||
a[k1 + 0] = xr;
|
||||
a[k1 + 1] = xi;
|
||||
}
|
||||
j1 = 2 * k + m2 + ip[k];
|
||||
k1 = j1 + m2;
|
||||
xr = a[j1];
|
||||
j1 = 2 * k + 8 + ip[k];
|
||||
k1 = j1 + 8;
|
||||
xr = a[j1 + 0];
|
||||
xi = a[j1 + 1];
|
||||
yr = a[k1];
|
||||
yr = a[k1 + 0];
|
||||
yi = a[k1 + 1];
|
||||
a[j1] = yr;
|
||||
a[j1 + 0] = yr;
|
||||
a[j1 + 1] = yi;
|
||||
a[k1] = xr;
|
||||
a[k1 + 0] = xr;
|
||||
a[k1 + 1] = xi;
|
||||
}
|
||||
}
|
||||
|
||||
static void makewt_32(void) {
|
||||
const int nw = 32;
|
||||
int j, nwh;
|
||||
float delta, x, y;
|
||||
|
||||
ip[0] = nw;
|
||||
ip[1] = 1;
|
||||
nwh = nw >> 1;
|
||||
delta = atanf(1.0f) / nwh;
|
||||
rdft_w[0] = 1;
|
||||
rdft_w[1] = 0;
|
||||
rdft_w[nwh] = cosf(delta * nwh);
|
||||
rdft_w[nwh + 1] = rdft_w[nwh];
|
||||
for (j = 2; j < nwh; j += 2) {
|
||||
x = cosf(delta * j);
|
||||
y = sinf(delta * j);
|
||||
rdft_w[j] = x;
|
||||
rdft_w[j + 1] = y;
|
||||
rdft_w[nw - j] = y;
|
||||
rdft_w[nw - j + 1] = x;
|
||||
}
|
||||
bitrv2_32or128(nw, ip + 2, rdft_w);
|
||||
|
||||
// pre-calculate constants used by cft1st_128 and cftmdl_128...
|
||||
cftmdl_wk1r[0] = rdft_w[2];
|
||||
cftmdl_wk1r[1] = rdft_w[2];
|
||||
cftmdl_wk1r[2] = rdft_w[2];
|
||||
cftmdl_wk1r[3] = -rdft_w[2];
|
||||
{
|
||||
int k1;
|
||||
|
||||
for (k1 = 0, j = 0; j < 128; j += 16, k1 += 2) {
|
||||
const int k2 = 2 * k1;
|
||||
const float wk2r = rdft_w[k1 + 0];
|
||||
const float wk2i = rdft_w[k1 + 1];
|
||||
float wk1r, wk1i;
|
||||
// ... scalar version.
|
||||
wk1r = rdft_w[k2 + 0];
|
||||
wk1i = rdft_w[k2 + 1];
|
||||
rdft_wk3ri_first[k1 + 0] = wk1r - 2 * wk2i * wk1i;
|
||||
rdft_wk3ri_first[k1 + 1] = 2 * wk2i * wk1r - wk1i;
|
||||
wk1r = rdft_w[k2 + 2];
|
||||
wk1i = rdft_w[k2 + 3];
|
||||
rdft_wk3ri_second[k1 + 0] = wk1r - 2 * wk2r * wk1i;
|
||||
rdft_wk3ri_second[k1 + 1] = 2 * wk2r * wk1r - wk1i;
|
||||
// ... vector version.
|
||||
rdft_wk1r[k2 + 0] = rdft_w[k2 + 0];
|
||||
rdft_wk1r[k2 + 1] = rdft_w[k2 + 0];
|
||||
rdft_wk1r[k2 + 2] = rdft_w[k2 + 2];
|
||||
rdft_wk1r[k2 + 3] = rdft_w[k2 + 2];
|
||||
rdft_wk2r[k2 + 0] = rdft_w[k1 + 0];
|
||||
rdft_wk2r[k2 + 1] = rdft_w[k1 + 0];
|
||||
rdft_wk2r[k2 + 2] = -rdft_w[k1 + 1];
|
||||
rdft_wk2r[k2 + 3] = -rdft_w[k1 + 1];
|
||||
rdft_wk3r[k2 + 0] = rdft_wk3ri_first[k1 + 0];
|
||||
rdft_wk3r[k2 + 1] = rdft_wk3ri_first[k1 + 0];
|
||||
rdft_wk3r[k2 + 2] = rdft_wk3ri_second[k1 + 0];
|
||||
rdft_wk3r[k2 + 3] = rdft_wk3ri_second[k1 + 0];
|
||||
rdft_wk1i[k2 + 0] = -rdft_w[k2 + 1];
|
||||
rdft_wk1i[k2 + 1] = rdft_w[k2 + 1];
|
||||
rdft_wk1i[k2 + 2] = -rdft_w[k2 + 3];
|
||||
rdft_wk1i[k2 + 3] = rdft_w[k2 + 3];
|
||||
rdft_wk2i[k2 + 0] = -rdft_w[k1 + 1];
|
||||
rdft_wk2i[k2 + 1] = rdft_w[k1 + 1];
|
||||
rdft_wk2i[k2 + 2] = -rdft_w[k1 + 0];
|
||||
rdft_wk2i[k2 + 3] = rdft_w[k1 + 0];
|
||||
rdft_wk3i[k2 + 0] = -rdft_wk3ri_first[k1 + 1];
|
||||
rdft_wk3i[k2 + 1] = rdft_wk3ri_first[k1 + 1];
|
||||
rdft_wk3i[k2 + 2] = -rdft_wk3ri_second[k1 + 1];
|
||||
rdft_wk3i[k2 + 3] = rdft_wk3ri_second[k1 + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void makect_32(void) {
|
||||
float *c = rdft_w + 32;
|
||||
const int nc = 32;
|
||||
int j, nch;
|
||||
float delta;
|
||||
|
||||
ip[1] = nc;
|
||||
nch = nc >> 1;
|
||||
delta = atanf(1.0f) / nch;
|
||||
c[0] = cosf(delta * nch);
|
||||
c[nch] = 0.5f * c[0];
|
||||
for (j = 1; j < nch; j++) {
|
||||
c[j] = 0.5f * cosf(delta * j);
|
||||
c[nc - j] = 0.5f * sinf(delta * j);
|
||||
}
|
||||
}
|
||||
|
||||
static void cft1st_128_C(float *a) {
|
||||
static void cft1st_128_C(float* a) {
|
||||
const int n = 128;
|
||||
int j, k1, k2;
|
||||
float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i;
|
||||
float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
|
||||
|
||||
// The processing of the first set of elements was simplified in C to avoid
|
||||
// some operations (multiplication by zero or one, addition of two elements
|
||||
// multiplied by the same weight, ...).
|
||||
x0r = a[0] + a[2];
|
||||
x0i = a[1] + a[3];
|
||||
x1r = a[0] - a[2];
|
||||
@@ -311,7 +304,7 @@ static void cft1st_128_C(float *a) {
|
||||
}
|
||||
}
|
||||
|
||||
static void cftmdl_128_C(float *a) {
|
||||
static void cftmdl_128_C(float* a) {
|
||||
const int l = 8;
|
||||
const int n = 128;
|
||||
const int m = 32;
|
||||
@@ -320,7 +313,7 @@ static void cftmdl_128_C(float *a) {
|
||||
float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
|
||||
|
||||
for (j0 = 0; j0 < l; j0 += 2) {
|
||||
j1 = j0 + 8;
|
||||
j1 = j0 + 8;
|
||||
j2 = j0 + 16;
|
||||
j3 = j0 + 24;
|
||||
x0r = a[j0 + 0] + a[j1 + 0];
|
||||
@@ -342,7 +335,7 @@ static void cftmdl_128_C(float *a) {
|
||||
}
|
||||
wk1r = rdft_w[2];
|
||||
for (j0 = m; j0 < l + m; j0 += 2) {
|
||||
j1 = j0 + 8;
|
||||
j1 = j0 + 8;
|
||||
j2 = j0 + 16;
|
||||
j3 = j0 + 24;
|
||||
x0r = a[j0 + 0] + a[j1 + 0];
|
||||
@@ -378,7 +371,7 @@ static void cftmdl_128_C(float *a) {
|
||||
wk3r = rdft_wk3ri_first[k1 + 0];
|
||||
wk3i = rdft_wk3ri_first[k1 + 1];
|
||||
for (j0 = k; j0 < l + k; j0 += 2) {
|
||||
j1 = j0 + 8;
|
||||
j1 = j0 + 8;
|
||||
j2 = j0 + 16;
|
||||
j3 = j0 + 24;
|
||||
x0r = a[j0 + 0] + a[j1 + 0];
|
||||
@@ -409,7 +402,7 @@ static void cftmdl_128_C(float *a) {
|
||||
wk3r = rdft_wk3ri_second[k1 + 0];
|
||||
wk3i = rdft_wk3ri_second[k1 + 1];
|
||||
for (j0 = k + m; j0 < l + (k + m); j0 += 2) {
|
||||
j1 = j0 + 8;
|
||||
j1 = j0 + 8;
|
||||
j2 = j0 + 16;
|
||||
j3 = j0 + 24;
|
||||
x0r = a[j0 + 0] + a[j1 + 0];
|
||||
@@ -438,7 +431,7 @@ static void cftmdl_128_C(float *a) {
|
||||
}
|
||||
}
|
||||
|
||||
static void cftfsub_128(float *a) {
|
||||
static void cftfsub_128_C(float* a) {
|
||||
int j, j1, j2, j3, l;
|
||||
float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
|
||||
|
||||
@@ -468,7 +461,7 @@ static void cftfsub_128(float *a) {
|
||||
}
|
||||
}
|
||||
|
||||
static void cftbsub_128(float *a) {
|
||||
static void cftbsub_128_C(float* a) {
|
||||
int j, j1, j2, j3, l;
|
||||
float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
|
||||
|
||||
@@ -499,14 +492,14 @@ static void cftbsub_128(float *a) {
|
||||
}
|
||||
}
|
||||
|
||||
static void rftfsub_128_C(float *a) {
|
||||
const float *c = rdft_w + 32;
|
||||
static void rftfsub_128_C(float* a) {
|
||||
const float* c = rdft_w + 32;
|
||||
int j1, j2, k1, k2;
|
||||
float wkr, wki, xr, xi, yr, yi;
|
||||
|
||||
for (j1 = 1, j2 = 2; j2 < 64; j1 += 1, j2 += 2) {
|
||||
k2 = 128 - j2;
|
||||
k1 = 32 - j1;
|
||||
k1 = 32 - j1;
|
||||
wkr = 0.5f - c[k1];
|
||||
wki = c[j1];
|
||||
xr = a[j2 + 0] - a[k2 + 0];
|
||||
@@ -520,15 +513,15 @@ static void rftfsub_128_C(float *a) {
|
||||
}
|
||||
}
|
||||
|
||||
static void rftbsub_128_C(float *a) {
|
||||
const float *c = rdft_w + 32;
|
||||
static void rftbsub_128_C(float* a) {
|
||||
const float* c = rdft_w + 32;
|
||||
int j1, j2, k1, k2;
|
||||
float wkr, wki, xr, xi, yr, yi;
|
||||
|
||||
a[1] = -a[1];
|
||||
for (j1 = 1, j2 = 2; j2 < 64; j1 += 1, j2 += 2) {
|
||||
k2 = 128 - j2;
|
||||
k1 = 32 - j1;
|
||||
k1 = 32 - j1;
|
||||
wkr = 0.5f - c[k1];
|
||||
wki = c[j1];
|
||||
xr = a[j2 + 0] - a[k2 + 0];
|
||||
@@ -543,11 +536,9 @@ static void rftbsub_128_C(float *a) {
|
||||
a[65] = -a[65];
|
||||
}
|
||||
|
||||
void aec_rdft_forward_128(float *a) {
|
||||
const int n = 128;
|
||||
void aec_rdft_forward_128(float* a) {
|
||||
float xi;
|
||||
|
||||
bitrv2_32or128(n, ip + 2, a);
|
||||
bitrv2_128(a);
|
||||
cftfsub_128(a);
|
||||
rftfsub_128(a);
|
||||
xi = a[0] - a[1];
|
||||
@@ -555,33 +546,44 @@ void aec_rdft_forward_128(float *a) {
|
||||
a[1] = xi;
|
||||
}
|
||||
|
||||
void aec_rdft_inverse_128(float *a) {
|
||||
const int n = 128;
|
||||
|
||||
void aec_rdft_inverse_128(float* a) {
|
||||
a[1] = 0.5f * (a[0] - a[1]);
|
||||
a[0] -= a[1];
|
||||
rftbsub_128(a);
|
||||
bitrv2_32or128(n, ip + 2, a);
|
||||
bitrv2_128(a);
|
||||
cftbsub_128(a);
|
||||
}
|
||||
|
||||
// code path selection
|
||||
rft_sub_128_t cft1st_128;
|
||||
rft_sub_128_t cftmdl_128;
|
||||
rft_sub_128_t rftfsub_128;
|
||||
rft_sub_128_t rftbsub_128;
|
||||
RftSub128 cft1st_128;
|
||||
RftSub128 cftmdl_128;
|
||||
RftSub128 rftfsub_128;
|
||||
RftSub128 rftbsub_128;
|
||||
RftSub128 cftfsub_128;
|
||||
RftSub128 cftbsub_128;
|
||||
RftSub128 bitrv2_128;
|
||||
|
||||
void aec_rdft_init(void) {
|
||||
cft1st_128 = cft1st_128_C;
|
||||
cftmdl_128 = cftmdl_128_C;
|
||||
rftfsub_128 = rftfsub_128_C;
|
||||
rftbsub_128 = rftbsub_128_C;
|
||||
cftfsub_128 = cftfsub_128_C;
|
||||
cftbsub_128 = cftbsub_128_C;
|
||||
bitrv2_128 = bitrv2_128_C;
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
if (WebRtc_GetCPUInfo(kSSE2)) {
|
||||
#if defined(WEBRTC_USE_SSE2)
|
||||
aec_rdft_init_sse2();
|
||||
#endif
|
||||
}
|
||||
// init library constants.
|
||||
makewt_32();
|
||||
makect_32();
|
||||
#endif
|
||||
#if defined(MIPS_FPU_LE)
|
||||
aec_rdft_init_mips();
|
||||
#endif
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
aec_rdft_init_neon();
|
||||
#elif defined(WEBRTC_DETECT_NEON)
|
||||
if ((WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) != 0) {
|
||||
aec_rdft_init_neon();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_RDFT_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_RDFT_H_
|
||||
|
||||
#include "webrtc/modules/audio_processing/aec/aec_common.h"
|
||||
|
||||
// These intrinsics were unavailable before VS 2008.
|
||||
// TODO(andrew): move to a common file.
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1500
|
||||
@@ -19,39 +21,41 @@ static __inline __m128 _mm_castsi128_ps(__m128i a) { return *(__m128*)&a; }
|
||||
static __inline __m128i _mm_castps_si128(__m128 a) { return *(__m128i*)&a; }
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER /* visual c++ */
|
||||
# define ALIGN16_BEG __declspec(align(16))
|
||||
# define ALIGN16_END
|
||||
#else /* gcc or icc */
|
||||
# define ALIGN16_BEG
|
||||
# define ALIGN16_END __attribute__((aligned(16)))
|
||||
#endif
|
||||
|
||||
// constants shared by all paths (C, SSE2).
|
||||
extern float rdft_w[64];
|
||||
// constants used by the C path.
|
||||
extern float rdft_wk3ri_first[32];
|
||||
extern float rdft_wk3ri_second[32];
|
||||
// constants used by SSE2 but initialized in C path.
|
||||
extern float rdft_wk1r[32];
|
||||
extern float rdft_wk2r[32];
|
||||
extern float rdft_wk3r[32];
|
||||
extern float rdft_wk1i[32];
|
||||
extern float rdft_wk2i[32];
|
||||
extern float rdft_wk3i[32];
|
||||
extern float cftmdl_wk1r[4];
|
||||
// Constants shared by all paths (C, SSE2, NEON).
|
||||
extern const float rdft_w[64];
|
||||
// Constants used by the C path.
|
||||
extern const float rdft_wk3ri_first[16];
|
||||
extern const float rdft_wk3ri_second[16];
|
||||
// Constants used by SSE2 and NEON but initialized in the C path.
|
||||
extern ALIGN16_BEG const float ALIGN16_END rdft_wk1r[32];
|
||||
extern ALIGN16_BEG const float ALIGN16_END rdft_wk2r[32];
|
||||
extern ALIGN16_BEG const float ALIGN16_END rdft_wk3r[32];
|
||||
extern ALIGN16_BEG const float ALIGN16_END rdft_wk1i[32];
|
||||
extern ALIGN16_BEG const float ALIGN16_END rdft_wk2i[32];
|
||||
extern ALIGN16_BEG const float ALIGN16_END rdft_wk3i[32];
|
||||
extern ALIGN16_BEG const float ALIGN16_END cftmdl_wk1r[4];
|
||||
|
||||
// code path selection function pointers
|
||||
typedef void (*rft_sub_128_t)(float *a);
|
||||
extern rft_sub_128_t rftfsub_128;
|
||||
extern rft_sub_128_t rftbsub_128;
|
||||
extern rft_sub_128_t cft1st_128;
|
||||
extern rft_sub_128_t cftmdl_128;
|
||||
typedef void (*RftSub128)(float* a);
|
||||
extern RftSub128 rftfsub_128;
|
||||
extern RftSub128 rftbsub_128;
|
||||
extern RftSub128 cft1st_128;
|
||||
extern RftSub128 cftmdl_128;
|
||||
extern RftSub128 cftfsub_128;
|
||||
extern RftSub128 cftbsub_128;
|
||||
extern RftSub128 bitrv2_128;
|
||||
|
||||
// entry points
|
||||
void aec_rdft_init(void);
|
||||
void aec_rdft_init_sse2(void);
|
||||
void aec_rdft_forward_128(float *a);
|
||||
void aec_rdft_inverse_128(float *a);
|
||||
void aec_rdft_forward_128(float* a);
|
||||
void aec_rdft_inverse_128(float* a);
|
||||
|
||||
#if defined(MIPS_FPU_LE)
|
||||
void aec_rdft_init_mips(void);
|
||||
#endif
|
||||
#if defined(WEBRTC_DETECT_NEON) || defined(WEBRTC_HAS_NEON)
|
||||
void aec_rdft_init_neon(void);
|
||||
#endif
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_RDFT_H_
|
||||
|
||||
1187
webrtc/modules/audio_processing/aec/aec_rdft_mips.c
Normal file
1187
webrtc/modules/audio_processing/aec/aec_rdft_mips.c
Normal file
File diff suppressed because it is too large
Load Diff
355
webrtc/modules/audio_processing/aec/aec_rdft_neon.c
Normal file
355
webrtc/modules/audio_processing/aec/aec_rdft_neon.c
Normal file
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The rdft AEC algorithm, neon version of speed-critical functions.
|
||||
*
|
||||
* Based on the sse2 version.
|
||||
*/
|
||||
|
||||
|
||||
#include "webrtc/modules/audio_processing/aec/aec_rdft.h"
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
static const ALIGN16_BEG float ALIGN16_END
|
||||
k_swap_sign[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
|
||||
static void cft1st_128_neon(float* a) {
|
||||
const float32x4_t vec_swap_sign = vld1q_f32((float32_t*)k_swap_sign);
|
||||
int j, k2;
|
||||
|
||||
for (k2 = 0, j = 0; j < 128; j += 16, k2 += 4) {
|
||||
float32x4_t a00v = vld1q_f32(&a[j + 0]);
|
||||
float32x4_t a04v = vld1q_f32(&a[j + 4]);
|
||||
float32x4_t a08v = vld1q_f32(&a[j + 8]);
|
||||
float32x4_t a12v = vld1q_f32(&a[j + 12]);
|
||||
float32x4_t a01v = vcombine_f32(vget_low_f32(a00v), vget_low_f32(a08v));
|
||||
float32x4_t a23v = vcombine_f32(vget_high_f32(a00v), vget_high_f32(a08v));
|
||||
float32x4_t a45v = vcombine_f32(vget_low_f32(a04v), vget_low_f32(a12v));
|
||||
float32x4_t a67v = vcombine_f32(vget_high_f32(a04v), vget_high_f32(a12v));
|
||||
const float32x4_t wk1rv = vld1q_f32(&rdft_wk1r[k2]);
|
||||
const float32x4_t wk1iv = vld1q_f32(&rdft_wk1i[k2]);
|
||||
const float32x4_t wk2rv = vld1q_f32(&rdft_wk2r[k2]);
|
||||
const float32x4_t wk2iv = vld1q_f32(&rdft_wk2i[k2]);
|
||||
const float32x4_t wk3rv = vld1q_f32(&rdft_wk3r[k2]);
|
||||
const float32x4_t wk3iv = vld1q_f32(&rdft_wk3i[k2]);
|
||||
float32x4_t x0v = vaddq_f32(a01v, a23v);
|
||||
const float32x4_t x1v = vsubq_f32(a01v, a23v);
|
||||
const float32x4_t x2v = vaddq_f32(a45v, a67v);
|
||||
const float32x4_t x3v = vsubq_f32(a45v, a67v);
|
||||
const float32x4_t x3w = vrev64q_f32(x3v);
|
||||
float32x4_t x0w;
|
||||
a01v = vaddq_f32(x0v, x2v);
|
||||
x0v = vsubq_f32(x0v, x2v);
|
||||
x0w = vrev64q_f32(x0v);
|
||||
a45v = vmulq_f32(wk2rv, x0v);
|
||||
a45v = vmlaq_f32(a45v, wk2iv, x0w);
|
||||
x0v = vmlaq_f32(x1v, x3w, vec_swap_sign);
|
||||
x0w = vrev64q_f32(x0v);
|
||||
a23v = vmulq_f32(wk1rv, x0v);
|
||||
a23v = vmlaq_f32(a23v, wk1iv, x0w);
|
||||
x0v = vmlsq_f32(x1v, x3w, vec_swap_sign);
|
||||
x0w = vrev64q_f32(x0v);
|
||||
a67v = vmulq_f32(wk3rv, x0v);
|
||||
a67v = vmlaq_f32(a67v, wk3iv, x0w);
|
||||
a00v = vcombine_f32(vget_low_f32(a01v), vget_low_f32(a23v));
|
||||
a04v = vcombine_f32(vget_low_f32(a45v), vget_low_f32(a67v));
|
||||
a08v = vcombine_f32(vget_high_f32(a01v), vget_high_f32(a23v));
|
||||
a12v = vcombine_f32(vget_high_f32(a45v), vget_high_f32(a67v));
|
||||
vst1q_f32(&a[j + 0], a00v);
|
||||
vst1q_f32(&a[j + 4], a04v);
|
||||
vst1q_f32(&a[j + 8], a08v);
|
||||
vst1q_f32(&a[j + 12], a12v);
|
||||
}
|
||||
}
|
||||
|
||||
static void cftmdl_128_neon(float* a) {
|
||||
int j;
|
||||
const int l = 8;
|
||||
const float32x4_t vec_swap_sign = vld1q_f32((float32_t*)k_swap_sign);
|
||||
float32x4_t wk1rv = vld1q_f32(cftmdl_wk1r);
|
||||
|
||||
for (j = 0; j < l; j += 2) {
|
||||
const float32x2_t a_00 = vld1_f32(&a[j + 0]);
|
||||
const float32x2_t a_08 = vld1_f32(&a[j + 8]);
|
||||
const float32x2_t a_32 = vld1_f32(&a[j + 32]);
|
||||
const float32x2_t a_40 = vld1_f32(&a[j + 40]);
|
||||
const float32x4_t a_00_32 = vcombine_f32(a_00, a_32);
|
||||
const float32x4_t a_08_40 = vcombine_f32(a_08, a_40);
|
||||
const float32x4_t x0r0_0i0_0r1_x0i1 = vaddq_f32(a_00_32, a_08_40);
|
||||
const float32x4_t x1r0_1i0_1r1_x1i1 = vsubq_f32(a_00_32, a_08_40);
|
||||
const float32x2_t a_16 = vld1_f32(&a[j + 16]);
|
||||
const float32x2_t a_24 = vld1_f32(&a[j + 24]);
|
||||
const float32x2_t a_48 = vld1_f32(&a[j + 48]);
|
||||
const float32x2_t a_56 = vld1_f32(&a[j + 56]);
|
||||
const float32x4_t a_16_48 = vcombine_f32(a_16, a_48);
|
||||
const float32x4_t a_24_56 = vcombine_f32(a_24, a_56);
|
||||
const float32x4_t x2r0_2i0_2r1_x2i1 = vaddq_f32(a_16_48, a_24_56);
|
||||
const float32x4_t x3r0_3i0_3r1_x3i1 = vsubq_f32(a_16_48, a_24_56);
|
||||
const float32x4_t xx0 = vaddq_f32(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
const float32x4_t xx1 = vsubq_f32(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
const float32x4_t x3i0_3r0_3i1_x3r1 = vrev64q_f32(x3r0_3i0_3r1_x3i1);
|
||||
const float32x4_t x1_x3_add =
|
||||
vmlaq_f32(x1r0_1i0_1r1_x1i1, vec_swap_sign, x3i0_3r0_3i1_x3r1);
|
||||
const float32x4_t x1_x3_sub =
|
||||
vmlsq_f32(x1r0_1i0_1r1_x1i1, vec_swap_sign, x3i0_3r0_3i1_x3r1);
|
||||
const float32x2_t yy0_a = vdup_lane_f32(vget_high_f32(x1_x3_add), 0);
|
||||
const float32x2_t yy0_s = vdup_lane_f32(vget_high_f32(x1_x3_sub), 0);
|
||||
const float32x4_t yy0_as = vcombine_f32(yy0_a, yy0_s);
|
||||
const float32x2_t yy1_a = vdup_lane_f32(vget_high_f32(x1_x3_add), 1);
|
||||
const float32x2_t yy1_s = vdup_lane_f32(vget_high_f32(x1_x3_sub), 1);
|
||||
const float32x4_t yy1_as = vcombine_f32(yy1_a, yy1_s);
|
||||
const float32x4_t yy0 = vmlaq_f32(yy0_as, vec_swap_sign, yy1_as);
|
||||
const float32x4_t yy4 = vmulq_f32(wk1rv, yy0);
|
||||
const float32x4_t xx1_rev = vrev64q_f32(xx1);
|
||||
const float32x4_t yy4_rev = vrev64q_f32(yy4);
|
||||
|
||||
vst1_f32(&a[j + 0], vget_low_f32(xx0));
|
||||
vst1_f32(&a[j + 32], vget_high_f32(xx0));
|
||||
vst1_f32(&a[j + 16], vget_low_f32(xx1));
|
||||
vst1_f32(&a[j + 48], vget_high_f32(xx1_rev));
|
||||
|
||||
a[j + 48] = -a[j + 48];
|
||||
|
||||
vst1_f32(&a[j + 8], vget_low_f32(x1_x3_add));
|
||||
vst1_f32(&a[j + 24], vget_low_f32(x1_x3_sub));
|
||||
vst1_f32(&a[j + 40], vget_low_f32(yy4));
|
||||
vst1_f32(&a[j + 56], vget_high_f32(yy4_rev));
|
||||
}
|
||||
|
||||
{
|
||||
const int k = 64;
|
||||
const int k1 = 2;
|
||||
const int k2 = 2 * k1;
|
||||
const float32x4_t wk2rv = vld1q_f32(&rdft_wk2r[k2 + 0]);
|
||||
const float32x4_t wk2iv = vld1q_f32(&rdft_wk2i[k2 + 0]);
|
||||
const float32x4_t wk1iv = vld1q_f32(&rdft_wk1i[k2 + 0]);
|
||||
const float32x4_t wk3rv = vld1q_f32(&rdft_wk3r[k2 + 0]);
|
||||
const float32x4_t wk3iv = vld1q_f32(&rdft_wk3i[k2 + 0]);
|
||||
wk1rv = vld1q_f32(&rdft_wk1r[k2 + 0]);
|
||||
for (j = k; j < l + k; j += 2) {
|
||||
const float32x2_t a_00 = vld1_f32(&a[j + 0]);
|
||||
const float32x2_t a_08 = vld1_f32(&a[j + 8]);
|
||||
const float32x2_t a_32 = vld1_f32(&a[j + 32]);
|
||||
const float32x2_t a_40 = vld1_f32(&a[j + 40]);
|
||||
const float32x4_t a_00_32 = vcombine_f32(a_00, a_32);
|
||||
const float32x4_t a_08_40 = vcombine_f32(a_08, a_40);
|
||||
const float32x4_t x0r0_0i0_0r1_x0i1 = vaddq_f32(a_00_32, a_08_40);
|
||||
const float32x4_t x1r0_1i0_1r1_x1i1 = vsubq_f32(a_00_32, a_08_40);
|
||||
const float32x2_t a_16 = vld1_f32(&a[j + 16]);
|
||||
const float32x2_t a_24 = vld1_f32(&a[j + 24]);
|
||||
const float32x2_t a_48 = vld1_f32(&a[j + 48]);
|
||||
const float32x2_t a_56 = vld1_f32(&a[j + 56]);
|
||||
const float32x4_t a_16_48 = vcombine_f32(a_16, a_48);
|
||||
const float32x4_t a_24_56 = vcombine_f32(a_24, a_56);
|
||||
const float32x4_t x2r0_2i0_2r1_x2i1 = vaddq_f32(a_16_48, a_24_56);
|
||||
const float32x4_t x3r0_3i0_3r1_x3i1 = vsubq_f32(a_16_48, a_24_56);
|
||||
const float32x4_t xx = vaddq_f32(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
const float32x4_t xx1 = vsubq_f32(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
const float32x4_t x3i0_3r0_3i1_x3r1 = vrev64q_f32(x3r0_3i0_3r1_x3i1);
|
||||
const float32x4_t x1_x3_add =
|
||||
vmlaq_f32(x1r0_1i0_1r1_x1i1, vec_swap_sign, x3i0_3r0_3i1_x3r1);
|
||||
const float32x4_t x1_x3_sub =
|
||||
vmlsq_f32(x1r0_1i0_1r1_x1i1, vec_swap_sign, x3i0_3r0_3i1_x3r1);
|
||||
float32x4_t xx4 = vmulq_f32(wk2rv, xx1);
|
||||
float32x4_t xx12 = vmulq_f32(wk1rv, x1_x3_add);
|
||||
float32x4_t xx22 = vmulq_f32(wk3rv, x1_x3_sub);
|
||||
xx4 = vmlaq_f32(xx4, wk2iv, vrev64q_f32(xx1));
|
||||
xx12 = vmlaq_f32(xx12, wk1iv, vrev64q_f32(x1_x3_add));
|
||||
xx22 = vmlaq_f32(xx22, wk3iv, vrev64q_f32(x1_x3_sub));
|
||||
|
||||
vst1_f32(&a[j + 0], vget_low_f32(xx));
|
||||
vst1_f32(&a[j + 32], vget_high_f32(xx));
|
||||
vst1_f32(&a[j + 16], vget_low_f32(xx4));
|
||||
vst1_f32(&a[j + 48], vget_high_f32(xx4));
|
||||
vst1_f32(&a[j + 8], vget_low_f32(xx12));
|
||||
vst1_f32(&a[j + 40], vget_high_f32(xx12));
|
||||
vst1_f32(&a[j + 24], vget_low_f32(xx22));
|
||||
vst1_f32(&a[j + 56], vget_high_f32(xx22));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__inline static float32x4_t reverse_order_f32x4(float32x4_t in) {
|
||||
// A B C D -> C D A B
|
||||
const float32x4_t rev = vcombine_f32(vget_high_f32(in), vget_low_f32(in));
|
||||
// C D A B -> D C B A
|
||||
return vrev64q_f32(rev);
|
||||
}
|
||||
|
||||
static void rftfsub_128_neon(float* a) {
|
||||
const float* c = rdft_w + 32;
|
||||
int j1, j2;
|
||||
const float32x4_t mm_half = vdupq_n_f32(0.5f);
|
||||
|
||||
// Vectorized code (four at once).
|
||||
// Note: commented number are indexes for the first iteration of the loop.
|
||||
for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) {
|
||||
// Load 'wk'.
|
||||
const float32x4_t c_j1 = vld1q_f32(&c[j1]); // 1, 2, 3, 4,
|
||||
const float32x4_t c_k1 = vld1q_f32(&c[29 - j1]); // 28, 29, 30, 31,
|
||||
const float32x4_t wkrt = vsubq_f32(mm_half, c_k1); // 28, 29, 30, 31,
|
||||
const float32x4_t wkr_ = reverse_order_f32x4(wkrt); // 31, 30, 29, 28,
|
||||
const float32x4_t wki_ = c_j1; // 1, 2, 3, 4,
|
||||
// Load and shuffle 'a'.
|
||||
// 2, 4, 6, 8, 3, 5, 7, 9
|
||||
float32x4x2_t a_j2_p = vld2q_f32(&a[0 + j2]);
|
||||
// 120, 122, 124, 126, 121, 123, 125, 127,
|
||||
const float32x4x2_t k2_0_4 = vld2q_f32(&a[122 - j2]);
|
||||
// 126, 124, 122, 120
|
||||
const float32x4_t a_k2_p0 = reverse_order_f32x4(k2_0_4.val[0]);
|
||||
// 127, 125, 123, 121
|
||||
const float32x4_t a_k2_p1 = reverse_order_f32x4(k2_0_4.val[1]);
|
||||
// Calculate 'x'.
|
||||
const float32x4_t xr_ = vsubq_f32(a_j2_p.val[0], a_k2_p0);
|
||||
// 2-126, 4-124, 6-122, 8-120,
|
||||
const float32x4_t xi_ = vaddq_f32(a_j2_p.val[1], a_k2_p1);
|
||||
// 3-127, 5-125, 7-123, 9-121,
|
||||
// Calculate product into 'y'.
|
||||
// yr = wkr * xr - wki * xi;
|
||||
// yi = wkr * xi + wki * xr;
|
||||
const float32x4_t a_ = vmulq_f32(wkr_, xr_);
|
||||
const float32x4_t b_ = vmulq_f32(wki_, xi_);
|
||||
const float32x4_t c_ = vmulq_f32(wkr_, xi_);
|
||||
const float32x4_t d_ = vmulq_f32(wki_, xr_);
|
||||
const float32x4_t yr_ = vsubq_f32(a_, b_); // 2-126, 4-124, 6-122, 8-120,
|
||||
const float32x4_t yi_ = vaddq_f32(c_, d_); // 3-127, 5-125, 7-123, 9-121,
|
||||
// Update 'a'.
|
||||
// a[j2 + 0] -= yr;
|
||||
// a[j2 + 1] -= yi;
|
||||
// a[k2 + 0] += yr;
|
||||
// a[k2 + 1] -= yi;
|
||||
// 126, 124, 122, 120,
|
||||
const float32x4_t a_k2_p0n = vaddq_f32(a_k2_p0, yr_);
|
||||
// 127, 125, 123, 121,
|
||||
const float32x4_t a_k2_p1n = vsubq_f32(a_k2_p1, yi_);
|
||||
// Shuffle in right order and store.
|
||||
const float32x4_t a_k2_p0nr = vrev64q_f32(a_k2_p0n);
|
||||
const float32x4_t a_k2_p1nr = vrev64q_f32(a_k2_p1n);
|
||||
// 124, 125, 126, 127, 120, 121, 122, 123
|
||||
const float32x4x2_t a_k2_n = vzipq_f32(a_k2_p0nr, a_k2_p1nr);
|
||||
// 2, 4, 6, 8,
|
||||
a_j2_p.val[0] = vsubq_f32(a_j2_p.val[0], yr_);
|
||||
// 3, 5, 7, 9,
|
||||
a_j2_p.val[1] = vsubq_f32(a_j2_p.val[1], yi_);
|
||||
// 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
vst2q_f32(&a[0 + j2], a_j2_p);
|
||||
|
||||
vst1q_f32(&a[122 - j2], a_k2_n.val[1]);
|
||||
vst1q_f32(&a[126 - j2], a_k2_n.val[0]);
|
||||
}
|
||||
|
||||
// Scalar code for the remaining items.
|
||||
for (; j2 < 64; j1 += 1, j2 += 2) {
|
||||
const int k2 = 128 - j2;
|
||||
const int k1 = 32 - j1;
|
||||
const float wkr = 0.5f - c[k1];
|
||||
const float wki = c[j1];
|
||||
const float xr = a[j2 + 0] - a[k2 + 0];
|
||||
const float xi = a[j2 + 1] + a[k2 + 1];
|
||||
const float yr = wkr * xr - wki * xi;
|
||||
const float yi = wkr * xi + wki * xr;
|
||||
a[j2 + 0] -= yr;
|
||||
a[j2 + 1] -= yi;
|
||||
a[k2 + 0] += yr;
|
||||
a[k2 + 1] -= yi;
|
||||
}
|
||||
}
|
||||
|
||||
static void rftbsub_128_neon(float* a) {
|
||||
const float* c = rdft_w + 32;
|
||||
int j1, j2;
|
||||
const float32x4_t mm_half = vdupq_n_f32(0.5f);
|
||||
|
||||
a[1] = -a[1];
|
||||
// Vectorized code (four at once).
|
||||
// Note: commented number are indexes for the first iteration of the loop.
|
||||
for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) {
|
||||
// Load 'wk'.
|
||||
const float32x4_t c_j1 = vld1q_f32(&c[j1]); // 1, 2, 3, 4,
|
||||
const float32x4_t c_k1 = vld1q_f32(&c[29 - j1]); // 28, 29, 30, 31,
|
||||
const float32x4_t wkrt = vsubq_f32(mm_half, c_k1); // 28, 29, 30, 31,
|
||||
const float32x4_t wkr_ = reverse_order_f32x4(wkrt); // 31, 30, 29, 28,
|
||||
const float32x4_t wki_ = c_j1; // 1, 2, 3, 4,
|
||||
// Load and shuffle 'a'.
|
||||
// 2, 4, 6, 8, 3, 5, 7, 9
|
||||
float32x4x2_t a_j2_p = vld2q_f32(&a[0 + j2]);
|
||||
// 120, 122, 124, 126, 121, 123, 125, 127,
|
||||
const float32x4x2_t k2_0_4 = vld2q_f32(&a[122 - j2]);
|
||||
// 126, 124, 122, 120
|
||||
const float32x4_t a_k2_p0 = reverse_order_f32x4(k2_0_4.val[0]);
|
||||
// 127, 125, 123, 121
|
||||
const float32x4_t a_k2_p1 = reverse_order_f32x4(k2_0_4.val[1]);
|
||||
// Calculate 'x'.
|
||||
const float32x4_t xr_ = vsubq_f32(a_j2_p.val[0], a_k2_p0);
|
||||
// 2-126, 4-124, 6-122, 8-120,
|
||||
const float32x4_t xi_ = vaddq_f32(a_j2_p.val[1], a_k2_p1);
|
||||
// 3-127, 5-125, 7-123, 9-121,
|
||||
// Calculate product into 'y'.
|
||||
// yr = wkr * xr - wki * xi;
|
||||
// yi = wkr * xi + wki * xr;
|
||||
const float32x4_t a_ = vmulq_f32(wkr_, xr_);
|
||||
const float32x4_t b_ = vmulq_f32(wki_, xi_);
|
||||
const float32x4_t c_ = vmulq_f32(wkr_, xi_);
|
||||
const float32x4_t d_ = vmulq_f32(wki_, xr_);
|
||||
const float32x4_t yr_ = vaddq_f32(a_, b_); // 2-126, 4-124, 6-122, 8-120,
|
||||
const float32x4_t yi_ = vsubq_f32(c_, d_); // 3-127, 5-125, 7-123, 9-121,
|
||||
// Update 'a'.
|
||||
// a[j2 + 0] -= yr;
|
||||
// a[j2 + 1] -= yi;
|
||||
// a[k2 + 0] += yr;
|
||||
// a[k2 + 1] -= yi;
|
||||
// 126, 124, 122, 120,
|
||||
const float32x4_t a_k2_p0n = vaddq_f32(a_k2_p0, yr_);
|
||||
// 127, 125, 123, 121,
|
||||
const float32x4_t a_k2_p1n = vsubq_f32(yi_, a_k2_p1);
|
||||
// Shuffle in right order and store.
|
||||
// 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
const float32x4_t a_k2_p0nr = vrev64q_f32(a_k2_p0n);
|
||||
const float32x4_t a_k2_p1nr = vrev64q_f32(a_k2_p1n);
|
||||
// 124, 125, 126, 127, 120, 121, 122, 123
|
||||
const float32x4x2_t a_k2_n = vzipq_f32(a_k2_p0nr, a_k2_p1nr);
|
||||
// 2, 4, 6, 8,
|
||||
a_j2_p.val[0] = vsubq_f32(a_j2_p.val[0], yr_);
|
||||
// 3, 5, 7, 9,
|
||||
a_j2_p.val[1] = vsubq_f32(yi_, a_j2_p.val[1]);
|
||||
// 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
vst2q_f32(&a[0 + j2], a_j2_p);
|
||||
|
||||
vst1q_f32(&a[122 - j2], a_k2_n.val[1]);
|
||||
vst1q_f32(&a[126 - j2], a_k2_n.val[0]);
|
||||
}
|
||||
|
||||
// Scalar code for the remaining items.
|
||||
for (; j2 < 64; j1 += 1, j2 += 2) {
|
||||
const int k2 = 128 - j2;
|
||||
const int k1 = 32 - j1;
|
||||
const float wkr = 0.5f - c[k1];
|
||||
const float wki = c[j1];
|
||||
const float xr = a[j2 + 0] - a[k2 + 0];
|
||||
const float xi = a[j2 + 1] + a[k2 + 1];
|
||||
const float yr = wkr * xr + wki * xi;
|
||||
const float yi = wkr * xi - wki * xr;
|
||||
a[j2 + 0] = a[j2 + 0] - yr;
|
||||
a[j2 + 1] = yi - a[j2 + 1];
|
||||
a[k2 + 0] = yr + a[k2 + 0];
|
||||
a[k2 + 1] = yi - a[k2 + 1];
|
||||
}
|
||||
a[65] = -a[65];
|
||||
}
|
||||
|
||||
void aec_rdft_init_neon(void) {
|
||||
cft1st_128 = cft1st_128_neon;
|
||||
cftmdl_128 = cftmdl_128_neon;
|
||||
rftfsub_128 = rftfsub_128_neon;
|
||||
rftbsub_128 = rftbsub_128_neon;
|
||||
}
|
||||
|
||||
@@ -8,172 +8,168 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_rdft.h"
|
||||
|
||||
#if defined(WEBRTC_USE_SSE2)
|
||||
#include <emmintrin.h>
|
||||
|
||||
#include "aec_rdft.h"
|
||||
static const ALIGN16_BEG float ALIGN16_END
|
||||
k_swap_sign[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
|
||||
static const ALIGN16_BEG float ALIGN16_END k_swap_sign[4] =
|
||||
{-1.f, 1.f, -1.f, 1.f};
|
||||
|
||||
static void cft1st_128_SSE2(float *a) {
|
||||
static void cft1st_128_SSE2(float* a) {
|
||||
const __m128 mm_swap_sign = _mm_load_ps(k_swap_sign);
|
||||
int j, k2;
|
||||
|
||||
for (k2 = 0, j = 0; j < 128; j += 16, k2 += 4) {
|
||||
__m128 a00v = _mm_loadu_ps(&a[j + 0]);
|
||||
__m128 a04v = _mm_loadu_ps(&a[j + 4]);
|
||||
__m128 a08v = _mm_loadu_ps(&a[j + 8]);
|
||||
__m128 a12v = _mm_loadu_ps(&a[j + 12]);
|
||||
__m128 a01v = _mm_shuffle_ps(a00v, a08v, _MM_SHUFFLE(1, 0, 1 ,0));
|
||||
__m128 a23v = _mm_shuffle_ps(a00v, a08v, _MM_SHUFFLE(3, 2, 3 ,2));
|
||||
__m128 a45v = _mm_shuffle_ps(a04v, a12v, _MM_SHUFFLE(1, 0, 1 ,0));
|
||||
__m128 a67v = _mm_shuffle_ps(a04v, a12v, _MM_SHUFFLE(3, 2, 3 ,2));
|
||||
__m128 a00v = _mm_loadu_ps(&a[j + 0]);
|
||||
__m128 a04v = _mm_loadu_ps(&a[j + 4]);
|
||||
__m128 a08v = _mm_loadu_ps(&a[j + 8]);
|
||||
__m128 a12v = _mm_loadu_ps(&a[j + 12]);
|
||||
__m128 a01v = _mm_shuffle_ps(a00v, a08v, _MM_SHUFFLE(1, 0, 1, 0));
|
||||
__m128 a23v = _mm_shuffle_ps(a00v, a08v, _MM_SHUFFLE(3, 2, 3, 2));
|
||||
__m128 a45v = _mm_shuffle_ps(a04v, a12v, _MM_SHUFFLE(1, 0, 1, 0));
|
||||
__m128 a67v = _mm_shuffle_ps(a04v, a12v, _MM_SHUFFLE(3, 2, 3, 2));
|
||||
|
||||
const __m128 wk1rv = _mm_load_ps(&rdft_wk1r[k2]);
|
||||
const __m128 wk1iv = _mm_load_ps(&rdft_wk1i[k2]);
|
||||
const __m128 wk2rv = _mm_load_ps(&rdft_wk2r[k2]);
|
||||
const __m128 wk2iv = _mm_load_ps(&rdft_wk2i[k2]);
|
||||
const __m128 wk3rv = _mm_load_ps(&rdft_wk3r[k2]);
|
||||
const __m128 wk3iv = _mm_load_ps(&rdft_wk3i[k2]);
|
||||
__m128 x0v = _mm_add_ps(a01v, a23v);
|
||||
const __m128 x1v = _mm_sub_ps(a01v, a23v);
|
||||
const __m128 x2v = _mm_add_ps(a45v, a67v);
|
||||
const __m128 x3v = _mm_sub_ps(a45v, a67v);
|
||||
__m128 x0w;
|
||||
a01v = _mm_add_ps(x0v, x2v);
|
||||
x0v = _mm_sub_ps(x0v, x2v);
|
||||
x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0 ,1));
|
||||
const __m128 wk1rv = _mm_load_ps(&rdft_wk1r[k2]);
|
||||
const __m128 wk1iv = _mm_load_ps(&rdft_wk1i[k2]);
|
||||
const __m128 wk2rv = _mm_load_ps(&rdft_wk2r[k2]);
|
||||
const __m128 wk2iv = _mm_load_ps(&rdft_wk2i[k2]);
|
||||
const __m128 wk3rv = _mm_load_ps(&rdft_wk3r[k2]);
|
||||
const __m128 wk3iv = _mm_load_ps(&rdft_wk3i[k2]);
|
||||
__m128 x0v = _mm_add_ps(a01v, a23v);
|
||||
const __m128 x1v = _mm_sub_ps(a01v, a23v);
|
||||
const __m128 x2v = _mm_add_ps(a45v, a67v);
|
||||
const __m128 x3v = _mm_sub_ps(a45v, a67v);
|
||||
__m128 x0w;
|
||||
a01v = _mm_add_ps(x0v, x2v);
|
||||
x0v = _mm_sub_ps(x0v, x2v);
|
||||
x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
{
|
||||
const __m128 a45_0v = _mm_mul_ps(wk2rv, x0v);
|
||||
const __m128 a45_1v = _mm_mul_ps(wk2iv, x0w);
|
||||
a45v = _mm_add_ps(a45_0v, a45_1v);
|
||||
a45v = _mm_add_ps(a45_0v, a45_1v);
|
||||
}
|
||||
{
|
||||
__m128 a23_0v, a23_1v;
|
||||
const __m128 x3w = _mm_shuffle_ps(x3v, x3v, _MM_SHUFFLE(2, 3, 0 ,1));
|
||||
const __m128 x3s = _mm_mul_ps(mm_swap_sign, x3w);
|
||||
x0v = _mm_add_ps(x1v, x3s);
|
||||
x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0 ,1));
|
||||
a23_0v = _mm_mul_ps(wk1rv, x0v);
|
||||
a23_1v = _mm_mul_ps(wk1iv, x0w);
|
||||
a23v = _mm_add_ps(a23_0v, a23_1v);
|
||||
__m128 a23_0v, a23_1v;
|
||||
const __m128 x3w = _mm_shuffle_ps(x3v, x3v, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
const __m128 x3s = _mm_mul_ps(mm_swap_sign, x3w);
|
||||
x0v = _mm_add_ps(x1v, x3s);
|
||||
x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
a23_0v = _mm_mul_ps(wk1rv, x0v);
|
||||
a23_1v = _mm_mul_ps(wk1iv, x0w);
|
||||
a23v = _mm_add_ps(a23_0v, a23_1v);
|
||||
|
||||
x0v = _mm_sub_ps(x1v, x3s);
|
||||
x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0 ,1));
|
||||
x0v = _mm_sub_ps(x1v, x3s);
|
||||
x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
}
|
||||
{
|
||||
const __m128 a67_0v = _mm_mul_ps(wk3rv, x0v);
|
||||
const __m128 a67_1v = _mm_mul_ps(wk3iv, x0w);
|
||||
a67v = _mm_add_ps(a67_0v, a67_1v);
|
||||
a67v = _mm_add_ps(a67_0v, a67_1v);
|
||||
}
|
||||
|
||||
a00v = _mm_shuffle_ps(a01v, a23v, _MM_SHUFFLE(1, 0, 1 ,0));
|
||||
a04v = _mm_shuffle_ps(a45v, a67v, _MM_SHUFFLE(1, 0, 1 ,0));
|
||||
a08v = _mm_shuffle_ps(a01v, a23v, _MM_SHUFFLE(3, 2, 3 ,2));
|
||||
a12v = _mm_shuffle_ps(a45v, a67v, _MM_SHUFFLE(3, 2, 3 ,2));
|
||||
_mm_storeu_ps(&a[j + 0], a00v);
|
||||
_mm_storeu_ps(&a[j + 4], a04v);
|
||||
_mm_storeu_ps(&a[j + 8], a08v);
|
||||
a00v = _mm_shuffle_ps(a01v, a23v, _MM_SHUFFLE(1, 0, 1, 0));
|
||||
a04v = _mm_shuffle_ps(a45v, a67v, _MM_SHUFFLE(1, 0, 1, 0));
|
||||
a08v = _mm_shuffle_ps(a01v, a23v, _MM_SHUFFLE(3, 2, 3, 2));
|
||||
a12v = _mm_shuffle_ps(a45v, a67v, _MM_SHUFFLE(3, 2, 3, 2));
|
||||
_mm_storeu_ps(&a[j + 0], a00v);
|
||||
_mm_storeu_ps(&a[j + 4], a04v);
|
||||
_mm_storeu_ps(&a[j + 8], a08v);
|
||||
_mm_storeu_ps(&a[j + 12], a12v);
|
||||
}
|
||||
}
|
||||
|
||||
static void cftmdl_128_SSE2(float *a) {
|
||||
static void cftmdl_128_SSE2(float* a) {
|
||||
const int l = 8;
|
||||
const __m128 mm_swap_sign = _mm_load_ps(k_swap_sign);
|
||||
int j0;
|
||||
|
||||
__m128 wk1rv = _mm_load_ps(cftmdl_wk1r);
|
||||
for (j0 = 0; j0 < l; j0 += 2) {
|
||||
const __m128i a_00 = _mm_loadl_epi64((__m128i*)&a[j0 + 0]);
|
||||
const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]);
|
||||
const __m128i a_00 = _mm_loadl_epi64((__m128i*)&a[j0 + 0]);
|
||||
const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]);
|
||||
const __m128i a_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]);
|
||||
const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]);
|
||||
const __m128 a_00_32 = _mm_shuffle_ps(_mm_castsi128_ps(a_00),
|
||||
_mm_castsi128_ps(a_32),
|
||||
_MM_SHUFFLE(1, 0, 1 ,0));
|
||||
const __m128 a_08_40 = _mm_shuffle_ps(_mm_castsi128_ps(a_08),
|
||||
_mm_castsi128_ps(a_40),
|
||||
_MM_SHUFFLE(1, 0, 1 ,0));
|
||||
__m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40);
|
||||
const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40);
|
||||
const __m128 a_00_32 = _mm_shuffle_ps(_mm_castsi128_ps(a_00),
|
||||
_mm_castsi128_ps(a_32),
|
||||
_MM_SHUFFLE(1, 0, 1, 0));
|
||||
const __m128 a_08_40 = _mm_shuffle_ps(_mm_castsi128_ps(a_08),
|
||||
_mm_castsi128_ps(a_40),
|
||||
_MM_SHUFFLE(1, 0, 1, 0));
|
||||
__m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40);
|
||||
const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40);
|
||||
|
||||
const __m128i a_16 = _mm_loadl_epi64((__m128i*)&a[j0 + 16]);
|
||||
const __m128i a_24 = _mm_loadl_epi64((__m128i*)&a[j0 + 24]);
|
||||
const __m128i a_48 = _mm_loadl_epi64((__m128i*)&a[j0 + 48]);
|
||||
const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]);
|
||||
const __m128 a_16_48 = _mm_shuffle_ps(_mm_castsi128_ps(a_16),
|
||||
_mm_castsi128_ps(a_48),
|
||||
_MM_SHUFFLE(1, 0, 1 ,0));
|
||||
const __m128 a_24_56 = _mm_shuffle_ps(_mm_castsi128_ps(a_24),
|
||||
_mm_castsi128_ps(a_56),
|
||||
_MM_SHUFFLE(1, 0, 1 ,0));
|
||||
const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56);
|
||||
const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56);
|
||||
const __m128 a_16_48 = _mm_shuffle_ps(_mm_castsi128_ps(a_16),
|
||||
_mm_castsi128_ps(a_48),
|
||||
_MM_SHUFFLE(1, 0, 1, 0));
|
||||
const __m128 a_24_56 = _mm_shuffle_ps(_mm_castsi128_ps(a_24),
|
||||
_mm_castsi128_ps(a_56),
|
||||
_MM_SHUFFLE(1, 0, 1, 0));
|
||||
const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56);
|
||||
const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56);
|
||||
|
||||
const __m128 xx0 = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
const __m128 xx0 = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
|
||||
const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps(
|
||||
_mm_shuffle_epi32(_mm_castps_si128(x3r0_3i0_3r1_x3i1),
|
||||
_MM_SHUFFLE(2, 3, 0, 1)));
|
||||
const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1);
|
||||
const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped);
|
||||
const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped);
|
||||
const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps(_mm_shuffle_epi32(
|
||||
_mm_castps_si128(x3r0_3i0_3r1_x3i1), _MM_SHUFFLE(2, 3, 0, 1)));
|
||||
const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1);
|
||||
const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped);
|
||||
const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped);
|
||||
|
||||
const __m128 yy0 = _mm_shuffle_ps(x1_x3_add, x1_x3_sub,
|
||||
_MM_SHUFFLE(2, 2, 2 ,2));
|
||||
const __m128 yy1 = _mm_shuffle_ps(x1_x3_add, x1_x3_sub,
|
||||
_MM_SHUFFLE(3, 3, 3 ,3));
|
||||
const __m128 yy0 =
|
||||
_mm_shuffle_ps(x1_x3_add, x1_x3_sub, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
const __m128 yy1 =
|
||||
_mm_shuffle_ps(x1_x3_add, x1_x3_sub, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
const __m128 yy2 = _mm_mul_ps(mm_swap_sign, yy1);
|
||||
const __m128 yy3 = _mm_add_ps(yy0, yy2);
|
||||
const __m128 yy4 = _mm_mul_ps(wk1rv, yy3);
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx0));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 32],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx0),
|
||||
_MM_SHUFFLE(3, 2, 3, 2)));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx0));
|
||||
_mm_storel_epi64(
|
||||
(__m128i*)&a[j0 + 32],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx0), _MM_SHUFFLE(3, 2, 3, 2)));
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 16], _mm_castps_si128(xx1));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 48],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx1),
|
||||
_MM_SHUFFLE(2, 3, 2, 3)));
|
||||
_mm_storel_epi64(
|
||||
(__m128i*)&a[j0 + 48],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx1), _MM_SHUFFLE(2, 3, 2, 3)));
|
||||
a[j0 + 48] = -a[j0 + 48];
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 8], _mm_castps_si128(x1_x3_add));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 8], _mm_castps_si128(x1_x3_add));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 24], _mm_castps_si128(x1_x3_sub));
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 40], _mm_castps_si128(yy4));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 56],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(yy4),
|
||||
_MM_SHUFFLE(2, 3, 2, 3)));
|
||||
_mm_storel_epi64(
|
||||
(__m128i*)&a[j0 + 56],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(yy4), _MM_SHUFFLE(2, 3, 2, 3)));
|
||||
}
|
||||
|
||||
{
|
||||
int k = 64;
|
||||
int k1 = 2;
|
||||
int k2 = 2 * k1;
|
||||
const __m128 wk2rv = _mm_load_ps(&rdft_wk2r[k2+0]);
|
||||
const __m128 wk2iv = _mm_load_ps(&rdft_wk2i[k2+0]);
|
||||
const __m128 wk1iv = _mm_load_ps(&rdft_wk1i[k2+0]);
|
||||
const __m128 wk3rv = _mm_load_ps(&rdft_wk3r[k2+0]);
|
||||
const __m128 wk3iv = _mm_load_ps(&rdft_wk3i[k2+0]);
|
||||
wk1rv = _mm_load_ps(&rdft_wk1r[k2+0]);
|
||||
const __m128 wk2rv = _mm_load_ps(&rdft_wk2r[k2 + 0]);
|
||||
const __m128 wk2iv = _mm_load_ps(&rdft_wk2i[k2 + 0]);
|
||||
const __m128 wk1iv = _mm_load_ps(&rdft_wk1i[k2 + 0]);
|
||||
const __m128 wk3rv = _mm_load_ps(&rdft_wk3r[k2 + 0]);
|
||||
const __m128 wk3iv = _mm_load_ps(&rdft_wk3i[k2 + 0]);
|
||||
wk1rv = _mm_load_ps(&rdft_wk1r[k2 + 0]);
|
||||
for (j0 = k; j0 < l + k; j0 += 2) {
|
||||
const __m128i a_00 = _mm_loadl_epi64((__m128i*)&a[j0 + 0]);
|
||||
const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]);
|
||||
const __m128i a_00 = _mm_loadl_epi64((__m128i*)&a[j0 + 0]);
|
||||
const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]);
|
||||
const __m128i a_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]);
|
||||
const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]);
|
||||
const __m128 a_00_32 = _mm_shuffle_ps(_mm_castsi128_ps(a_00),
|
||||
_mm_castsi128_ps(a_32),
|
||||
_MM_SHUFFLE(1, 0, 1 ,0));
|
||||
_MM_SHUFFLE(1, 0, 1, 0));
|
||||
const __m128 a_08_40 = _mm_shuffle_ps(_mm_castsi128_ps(a_08),
|
||||
_mm_castsi128_ps(a_40),
|
||||
_MM_SHUFFLE(1, 0, 1 ,0));
|
||||
__m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40);
|
||||
_MM_SHUFFLE(1, 0, 1, 0));
|
||||
__m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40);
|
||||
const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40);
|
||||
|
||||
const __m128i a_16 = _mm_loadl_epi64((__m128i*)&a[j0 + 16]);
|
||||
@@ -182,100 +178,102 @@ static void cftmdl_128_SSE2(float *a) {
|
||||
const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]);
|
||||
const __m128 a_16_48 = _mm_shuffle_ps(_mm_castsi128_ps(a_16),
|
||||
_mm_castsi128_ps(a_48),
|
||||
_MM_SHUFFLE(1, 0, 1 ,0));
|
||||
_MM_SHUFFLE(1, 0, 1, 0));
|
||||
const __m128 a_24_56 = _mm_shuffle_ps(_mm_castsi128_ps(a_24),
|
||||
_mm_castsi128_ps(a_56),
|
||||
_MM_SHUFFLE(1, 0, 1 ,0));
|
||||
_MM_SHUFFLE(1, 0, 1, 0));
|
||||
const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56);
|
||||
const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56);
|
||||
|
||||
const __m128 xx = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
const __m128 xx2 = _mm_mul_ps(xx1 , wk2rv);
|
||||
const __m128 xx3 = _mm_mul_ps(wk2iv,
|
||||
_mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(xx1),
|
||||
_MM_SHUFFLE(2, 3, 0, 1))));
|
||||
const __m128 xx2 = _mm_mul_ps(xx1, wk2rv);
|
||||
const __m128 xx3 =
|
||||
_mm_mul_ps(wk2iv,
|
||||
_mm_castsi128_ps(_mm_shuffle_epi32(
|
||||
_mm_castps_si128(xx1), _MM_SHUFFLE(2, 3, 0, 1))));
|
||||
const __m128 xx4 = _mm_add_ps(xx2, xx3);
|
||||
|
||||
const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps(
|
||||
_mm_shuffle_epi32(_mm_castps_si128(x3r0_3i0_3r1_x3i1),
|
||||
_MM_SHUFFLE(2, 3, 0, 1)));
|
||||
const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1);
|
||||
const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped);
|
||||
const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped);
|
||||
const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps(_mm_shuffle_epi32(
|
||||
_mm_castps_si128(x3r0_3i0_3r1_x3i1), _MM_SHUFFLE(2, 3, 0, 1)));
|
||||
const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1);
|
||||
const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped);
|
||||
const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped);
|
||||
|
||||
const __m128 xx10 = _mm_mul_ps(x1_x3_add, wk1rv);
|
||||
const __m128 xx11 = _mm_mul_ps(wk1iv,
|
||||
const __m128 xx11 = _mm_mul_ps(
|
||||
wk1iv,
|
||||
_mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_add),
|
||||
_MM_SHUFFLE(2, 3, 0, 1))));
|
||||
const __m128 xx12 = _mm_add_ps(xx10, xx11);
|
||||
|
||||
const __m128 xx20 = _mm_mul_ps(x1_x3_sub, wk3rv);
|
||||
const __m128 xx21 = _mm_mul_ps(wk3iv,
|
||||
const __m128 xx21 = _mm_mul_ps(
|
||||
wk3iv,
|
||||
_mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_sub),
|
||||
_MM_SHUFFLE(2, 3, 0, 1))));
|
||||
_MM_SHUFFLE(2, 3, 0, 1))));
|
||||
const __m128 xx22 = _mm_add_ps(xx20, xx21);
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 32],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx),
|
||||
_MM_SHUFFLE(3, 2, 3, 2)));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx));
|
||||
_mm_storel_epi64(
|
||||
(__m128i*)&a[j0 + 32],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx), _MM_SHUFFLE(3, 2, 3, 2)));
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 16], _mm_castps_si128(xx4));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 48],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx4),
|
||||
_MM_SHUFFLE(3, 2, 3, 2)));
|
||||
_mm_storel_epi64(
|
||||
(__m128i*)&a[j0 + 48],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx4), _MM_SHUFFLE(3, 2, 3, 2)));
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 8], _mm_castps_si128(xx12));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 40],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx12),
|
||||
_MM_SHUFFLE(3, 2, 3, 2)));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 8], _mm_castps_si128(xx12));
|
||||
_mm_storel_epi64(
|
||||
(__m128i*)&a[j0 + 40],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx12), _MM_SHUFFLE(3, 2, 3, 2)));
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 24], _mm_castps_si128(xx22));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 56],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx22),
|
||||
_MM_SHUFFLE(3, 2, 3, 2)));
|
||||
_mm_storel_epi64(
|
||||
(__m128i*)&a[j0 + 56],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx22), _MM_SHUFFLE(3, 2, 3, 2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rftfsub_128_SSE2(float *a) {
|
||||
const float *c = rdft_w + 32;
|
||||
static void rftfsub_128_SSE2(float* a) {
|
||||
const float* c = rdft_w + 32;
|
||||
int j1, j2, k1, k2;
|
||||
float wkr, wki, xr, xi, yr, yi;
|
||||
|
||||
static const ALIGN16_BEG float ALIGN16_END k_half[4] =
|
||||
{0.5f, 0.5f, 0.5f, 0.5f};
|
||||
static const ALIGN16_BEG float ALIGN16_END
|
||||
k_half[4] = {0.5f, 0.5f, 0.5f, 0.5f};
|
||||
const __m128 mm_half = _mm_load_ps(k_half);
|
||||
|
||||
// Vectorized code (four at once).
|
||||
// Note: commented number are indexes for the first iteration of the loop.
|
||||
for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) {
|
||||
// Load 'wk'.
|
||||
const __m128 c_j1 = _mm_loadu_ps(&c[ j1]); // 1, 2, 3, 4,
|
||||
const __m128 c_k1 = _mm_loadu_ps(&c[29 - j1]); // 28, 29, 30, 31,
|
||||
const __m128 wkrt = _mm_sub_ps(mm_half, c_k1); // 28, 29, 30, 31,
|
||||
const __m128 c_j1 = _mm_loadu_ps(&c[j1]); // 1, 2, 3, 4,
|
||||
const __m128 c_k1 = _mm_loadu_ps(&c[29 - j1]); // 28, 29, 30, 31,
|
||||
const __m128 wkrt = _mm_sub_ps(mm_half, c_k1); // 28, 29, 30, 31,
|
||||
const __m128 wkr_ =
|
||||
_mm_shuffle_ps(wkrt, wkrt, _MM_SHUFFLE(0, 1, 2, 3)); // 31, 30, 29, 28,
|
||||
const __m128 wki_ = c_j1; // 1, 2, 3, 4,
|
||||
_mm_shuffle_ps(wkrt, wkrt, _MM_SHUFFLE(0, 1, 2, 3)); // 31, 30, 29, 28,
|
||||
const __m128 wki_ = c_j1; // 1, 2, 3, 4,
|
||||
// Load and shuffle 'a'.
|
||||
const __m128 a_j2_0 = _mm_loadu_ps(&a[0 + j2]); // 2, 3, 4, 5,
|
||||
const __m128 a_j2_4 = _mm_loadu_ps(&a[4 + j2]); // 6, 7, 8, 9,
|
||||
const __m128 a_j2_0 = _mm_loadu_ps(&a[0 + j2]); // 2, 3, 4, 5,
|
||||
const __m128 a_j2_4 = _mm_loadu_ps(&a[4 + j2]); // 6, 7, 8, 9,
|
||||
const __m128 a_k2_0 = _mm_loadu_ps(&a[122 - j2]); // 120, 121, 122, 123,
|
||||
const __m128 a_k2_4 = _mm_loadu_ps(&a[126 - j2]); // 124, 125, 126, 127,
|
||||
const __m128 a_j2_p0 = _mm_shuffle_ps(a_j2_0, a_j2_4,
|
||||
_MM_SHUFFLE(2, 0, 2 ,0)); // 2, 4, 6, 8,
|
||||
const __m128 a_j2_p1 = _mm_shuffle_ps(a_j2_0, a_j2_4,
|
||||
_MM_SHUFFLE(3, 1, 3 ,1)); // 3, 5, 7, 9,
|
||||
const __m128 a_k2_p0 = _mm_shuffle_ps(a_k2_4, a_k2_0,
|
||||
_MM_SHUFFLE(0, 2, 0 ,2)); // 126, 124, 122, 120,
|
||||
const __m128 a_k2_p1 = _mm_shuffle_ps(a_k2_4, a_k2_0,
|
||||
_MM_SHUFFLE(1, 3, 1 ,3)); // 127, 125, 123, 121,
|
||||
const __m128 a_j2_p0 = _mm_shuffle_ps(
|
||||
a_j2_0, a_j2_4, _MM_SHUFFLE(2, 0, 2, 0)); // 2, 4, 6, 8,
|
||||
const __m128 a_j2_p1 = _mm_shuffle_ps(
|
||||
a_j2_0, a_j2_4, _MM_SHUFFLE(3, 1, 3, 1)); // 3, 5, 7, 9,
|
||||
const __m128 a_k2_p0 = _mm_shuffle_ps(
|
||||
a_k2_4, a_k2_0, _MM_SHUFFLE(0, 2, 0, 2)); // 126, 124, 122, 120,
|
||||
const __m128 a_k2_p1 = _mm_shuffle_ps(
|
||||
a_k2_4, a_k2_0, _MM_SHUFFLE(1, 3, 1, 3)); // 127, 125, 123, 121,
|
||||
// Calculate 'x'.
|
||||
const __m128 xr_ = _mm_sub_ps(a_j2_p0, a_k2_p0);
|
||||
// 2-126, 4-124, 6-122, 8-120,
|
||||
// 2-126, 4-124, 6-122, 8-120,
|
||||
const __m128 xi_ = _mm_add_ps(a_j2_p1, a_k2_p1);
|
||||
// 3-127, 5-125, 7-123, 9-121,
|
||||
// 3-127, 5-125, 7-123, 9-121,
|
||||
// Calculate product into 'y'.
|
||||
// yr = wkr * xr - wki * xi;
|
||||
// yi = wkr * xi + wki * xr;
|
||||
@@ -283,12 +281,12 @@ static void rftfsub_128_SSE2(float *a) {
|
||||
const __m128 b_ = _mm_mul_ps(wki_, xi_);
|
||||
const __m128 c_ = _mm_mul_ps(wkr_, xi_);
|
||||
const __m128 d_ = _mm_mul_ps(wki_, xr_);
|
||||
const __m128 yr_ = _mm_sub_ps(a_, b_); // 2-126, 4-124, 6-122, 8-120,
|
||||
const __m128 yi_ = _mm_add_ps(c_, d_); // 3-127, 5-125, 7-123, 9-121,
|
||||
// Update 'a'.
|
||||
// a[j2 + 0] -= yr;
|
||||
// a[j2 + 1] -= yi;
|
||||
// a[k2 + 0] += yr;
|
||||
const __m128 yr_ = _mm_sub_ps(a_, b_); // 2-126, 4-124, 6-122, 8-120,
|
||||
const __m128 yi_ = _mm_add_ps(c_, d_); // 3-127, 5-125, 7-123, 9-121,
|
||||
// Update 'a'.
|
||||
// a[j2 + 0] -= yr;
|
||||
// a[j2 + 1] -= yi;
|
||||
// a[k2 + 0] += yr;
|
||||
// a[k2 + 1] -= yi;
|
||||
const __m128 a_j2_p0n = _mm_sub_ps(a_j2_p0, yr_); // 2, 4, 6, 8,
|
||||
const __m128 a_j2_p1n = _mm_sub_ps(a_j2_p1, yi_); // 3, 5, 7, 9,
|
||||
@@ -296,26 +294,26 @@ static void rftfsub_128_SSE2(float *a) {
|
||||
const __m128 a_k2_p1n = _mm_sub_ps(a_k2_p1, yi_); // 127, 125, 123, 121,
|
||||
// Shuffle in right order and store.
|
||||
const __m128 a_j2_0n = _mm_unpacklo_ps(a_j2_p0n, a_j2_p1n);
|
||||
// 2, 3, 4, 5,
|
||||
// 2, 3, 4, 5,
|
||||
const __m128 a_j2_4n = _mm_unpackhi_ps(a_j2_p0n, a_j2_p1n);
|
||||
// 6, 7, 8, 9,
|
||||
// 6, 7, 8, 9,
|
||||
const __m128 a_k2_0nt = _mm_unpackhi_ps(a_k2_p0n, a_k2_p1n);
|
||||
// 122, 123, 120, 121,
|
||||
// 122, 123, 120, 121,
|
||||
const __m128 a_k2_4nt = _mm_unpacklo_ps(a_k2_p0n, a_k2_p1n);
|
||||
// 126, 127, 124, 125,
|
||||
const __m128 a_k2_0n = _mm_shuffle_ps(a_k2_0nt, a_k2_0nt,
|
||||
_MM_SHUFFLE(1, 0, 3 ,2)); // 120, 121, 122, 123,
|
||||
const __m128 a_k2_4n = _mm_shuffle_ps(a_k2_4nt, a_k2_4nt,
|
||||
_MM_SHUFFLE(1, 0, 3 ,2)); // 124, 125, 126, 127,
|
||||
_mm_storeu_ps(&a[0 + j2], a_j2_0n);
|
||||
_mm_storeu_ps(&a[4 + j2], a_j2_4n);
|
||||
// 126, 127, 124, 125,
|
||||
const __m128 a_k2_0n = _mm_shuffle_ps(
|
||||
a_k2_0nt, a_k2_0nt, _MM_SHUFFLE(1, 0, 3, 2)); // 120, 121, 122, 123,
|
||||
const __m128 a_k2_4n = _mm_shuffle_ps(
|
||||
a_k2_4nt, a_k2_4nt, _MM_SHUFFLE(1, 0, 3, 2)); // 124, 125, 126, 127,
|
||||
_mm_storeu_ps(&a[0 + j2], a_j2_0n);
|
||||
_mm_storeu_ps(&a[4 + j2], a_j2_4n);
|
||||
_mm_storeu_ps(&a[122 - j2], a_k2_0n);
|
||||
_mm_storeu_ps(&a[126 - j2], a_k2_4n);
|
||||
}
|
||||
// Scalar code for the remaining items.
|
||||
for (; j2 < 64; j1 += 1, j2 += 2) {
|
||||
k2 = 128 - j2;
|
||||
k1 = 32 - j1;
|
||||
k1 = 32 - j1;
|
||||
wkr = 0.5f - c[k1];
|
||||
wki = c[j1];
|
||||
xr = a[j2 + 0] - a[k2 + 0];
|
||||
@@ -329,13 +327,13 @@ static void rftfsub_128_SSE2(float *a) {
|
||||
}
|
||||
}
|
||||
|
||||
static void rftbsub_128_SSE2(float *a) {
|
||||
const float *c = rdft_w + 32;
|
||||
static void rftbsub_128_SSE2(float* a) {
|
||||
const float* c = rdft_w + 32;
|
||||
int j1, j2, k1, k2;
|
||||
float wkr, wki, xr, xi, yr, yi;
|
||||
|
||||
static const ALIGN16_BEG float ALIGN16_END k_half[4] =
|
||||
{0.5f, 0.5f, 0.5f, 0.5f};
|
||||
static const ALIGN16_BEG float ALIGN16_END
|
||||
k_half[4] = {0.5f, 0.5f, 0.5f, 0.5f};
|
||||
const __m128 mm_half = _mm_load_ps(k_half);
|
||||
|
||||
a[1] = -a[1];
|
||||
@@ -343,30 +341,30 @@ static void rftbsub_128_SSE2(float *a) {
|
||||
// Note: commented number are indexes for the first iteration of the loop.
|
||||
for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) {
|
||||
// Load 'wk'.
|
||||
const __m128 c_j1 = _mm_loadu_ps(&c[ j1]); // 1, 2, 3, 4,
|
||||
const __m128 c_k1 = _mm_loadu_ps(&c[29 - j1]); // 28, 29, 30, 31,
|
||||
const __m128 wkrt = _mm_sub_ps(mm_half, c_k1); // 28, 29, 30, 31,
|
||||
const __m128 c_j1 = _mm_loadu_ps(&c[j1]); // 1, 2, 3, 4,
|
||||
const __m128 c_k1 = _mm_loadu_ps(&c[29 - j1]); // 28, 29, 30, 31,
|
||||
const __m128 wkrt = _mm_sub_ps(mm_half, c_k1); // 28, 29, 30, 31,
|
||||
const __m128 wkr_ =
|
||||
_mm_shuffle_ps(wkrt, wkrt, _MM_SHUFFLE(0, 1, 2, 3)); // 31, 30, 29, 28,
|
||||
const __m128 wki_ = c_j1; // 1, 2, 3, 4,
|
||||
_mm_shuffle_ps(wkrt, wkrt, _MM_SHUFFLE(0, 1, 2, 3)); // 31, 30, 29, 28,
|
||||
const __m128 wki_ = c_j1; // 1, 2, 3, 4,
|
||||
// Load and shuffle 'a'.
|
||||
const __m128 a_j2_0 = _mm_loadu_ps(&a[0 + j2]); // 2, 3, 4, 5,
|
||||
const __m128 a_j2_4 = _mm_loadu_ps(&a[4 + j2]); // 6, 7, 8, 9,
|
||||
const __m128 a_j2_0 = _mm_loadu_ps(&a[0 + j2]); // 2, 3, 4, 5,
|
||||
const __m128 a_j2_4 = _mm_loadu_ps(&a[4 + j2]); // 6, 7, 8, 9,
|
||||
const __m128 a_k2_0 = _mm_loadu_ps(&a[122 - j2]); // 120, 121, 122, 123,
|
||||
const __m128 a_k2_4 = _mm_loadu_ps(&a[126 - j2]); // 124, 125, 126, 127,
|
||||
const __m128 a_j2_p0 = _mm_shuffle_ps(a_j2_0, a_j2_4,
|
||||
_MM_SHUFFLE(2, 0, 2 ,0)); // 2, 4, 6, 8,
|
||||
const __m128 a_j2_p1 = _mm_shuffle_ps(a_j2_0, a_j2_4,
|
||||
_MM_SHUFFLE(3, 1, 3 ,1)); // 3, 5, 7, 9,
|
||||
const __m128 a_k2_p0 = _mm_shuffle_ps(a_k2_4, a_k2_0,
|
||||
_MM_SHUFFLE(0, 2, 0 ,2)); // 126, 124, 122, 120,
|
||||
const __m128 a_k2_p1 = _mm_shuffle_ps(a_k2_4, a_k2_0,
|
||||
_MM_SHUFFLE(1, 3, 1 ,3)); // 127, 125, 123, 121,
|
||||
const __m128 a_j2_p0 = _mm_shuffle_ps(
|
||||
a_j2_0, a_j2_4, _MM_SHUFFLE(2, 0, 2, 0)); // 2, 4, 6, 8,
|
||||
const __m128 a_j2_p1 = _mm_shuffle_ps(
|
||||
a_j2_0, a_j2_4, _MM_SHUFFLE(3, 1, 3, 1)); // 3, 5, 7, 9,
|
||||
const __m128 a_k2_p0 = _mm_shuffle_ps(
|
||||
a_k2_4, a_k2_0, _MM_SHUFFLE(0, 2, 0, 2)); // 126, 124, 122, 120,
|
||||
const __m128 a_k2_p1 = _mm_shuffle_ps(
|
||||
a_k2_4, a_k2_0, _MM_SHUFFLE(1, 3, 1, 3)); // 127, 125, 123, 121,
|
||||
// Calculate 'x'.
|
||||
const __m128 xr_ = _mm_sub_ps(a_j2_p0, a_k2_p0);
|
||||
// 2-126, 4-124, 6-122, 8-120,
|
||||
// 2-126, 4-124, 6-122, 8-120,
|
||||
const __m128 xi_ = _mm_add_ps(a_j2_p1, a_k2_p1);
|
||||
// 3-127, 5-125, 7-123, 9-121,
|
||||
// 3-127, 5-125, 7-123, 9-121,
|
||||
// Calculate product into 'y'.
|
||||
// yr = wkr * xr + wki * xi;
|
||||
// yi = wkr * xi - wki * xr;
|
||||
@@ -374,12 +372,12 @@ static void rftbsub_128_SSE2(float *a) {
|
||||
const __m128 b_ = _mm_mul_ps(wki_, xi_);
|
||||
const __m128 c_ = _mm_mul_ps(wkr_, xi_);
|
||||
const __m128 d_ = _mm_mul_ps(wki_, xr_);
|
||||
const __m128 yr_ = _mm_add_ps(a_, b_); // 2-126, 4-124, 6-122, 8-120,
|
||||
const __m128 yi_ = _mm_sub_ps(c_, d_); // 3-127, 5-125, 7-123, 9-121,
|
||||
// Update 'a'.
|
||||
// a[j2 + 0] = a[j2 + 0] - yr;
|
||||
// a[j2 + 1] = yi - a[j2 + 1];
|
||||
// a[k2 + 0] = yr + a[k2 + 0];
|
||||
const __m128 yr_ = _mm_add_ps(a_, b_); // 2-126, 4-124, 6-122, 8-120,
|
||||
const __m128 yi_ = _mm_sub_ps(c_, d_); // 3-127, 5-125, 7-123, 9-121,
|
||||
// Update 'a'.
|
||||
// a[j2 + 0] = a[j2 + 0] - yr;
|
||||
// a[j2 + 1] = yi - a[j2 + 1];
|
||||
// a[k2 + 0] = yr + a[k2 + 0];
|
||||
// a[k2 + 1] = yi - a[k2 + 1];
|
||||
const __m128 a_j2_p0n = _mm_sub_ps(a_j2_p0, yr_); // 2, 4, 6, 8,
|
||||
const __m128 a_j2_p1n = _mm_sub_ps(yi_, a_j2_p1); // 3, 5, 7, 9,
|
||||
@@ -387,26 +385,26 @@ static void rftbsub_128_SSE2(float *a) {
|
||||
const __m128 a_k2_p1n = _mm_sub_ps(yi_, a_k2_p1); // 127, 125, 123, 121,
|
||||
// Shuffle in right order and store.
|
||||
const __m128 a_j2_0n = _mm_unpacklo_ps(a_j2_p0n, a_j2_p1n);
|
||||
// 2, 3, 4, 5,
|
||||
// 2, 3, 4, 5,
|
||||
const __m128 a_j2_4n = _mm_unpackhi_ps(a_j2_p0n, a_j2_p1n);
|
||||
// 6, 7, 8, 9,
|
||||
// 6, 7, 8, 9,
|
||||
const __m128 a_k2_0nt = _mm_unpackhi_ps(a_k2_p0n, a_k2_p1n);
|
||||
// 122, 123, 120, 121,
|
||||
// 122, 123, 120, 121,
|
||||
const __m128 a_k2_4nt = _mm_unpacklo_ps(a_k2_p0n, a_k2_p1n);
|
||||
// 126, 127, 124, 125,
|
||||
const __m128 a_k2_0n = _mm_shuffle_ps(a_k2_0nt, a_k2_0nt,
|
||||
_MM_SHUFFLE(1, 0, 3 ,2)); // 120, 121, 122, 123,
|
||||
const __m128 a_k2_4n = _mm_shuffle_ps(a_k2_4nt, a_k2_4nt,
|
||||
_MM_SHUFFLE(1, 0, 3 ,2)); // 124, 125, 126, 127,
|
||||
_mm_storeu_ps(&a[0 + j2], a_j2_0n);
|
||||
_mm_storeu_ps(&a[4 + j2], a_j2_4n);
|
||||
// 126, 127, 124, 125,
|
||||
const __m128 a_k2_0n = _mm_shuffle_ps(
|
||||
a_k2_0nt, a_k2_0nt, _MM_SHUFFLE(1, 0, 3, 2)); // 120, 121, 122, 123,
|
||||
const __m128 a_k2_4n = _mm_shuffle_ps(
|
||||
a_k2_4nt, a_k2_4nt, _MM_SHUFFLE(1, 0, 3, 2)); // 124, 125, 126, 127,
|
||||
_mm_storeu_ps(&a[0 + j2], a_j2_0n);
|
||||
_mm_storeu_ps(&a[4 + j2], a_j2_4n);
|
||||
_mm_storeu_ps(&a[122 - j2], a_k2_0n);
|
||||
_mm_storeu_ps(&a[126 - j2], a_k2_4n);
|
||||
}
|
||||
// Scalar code for the remaining items.
|
||||
for (; j2 < 64; j1 += 1, j2 += 2) {
|
||||
k2 = 128 - j2;
|
||||
k1 = 32 - j1;
|
||||
k1 = 32 - j1;
|
||||
wkr = 0.5f - c[k1];
|
||||
wki = c[j1];
|
||||
xr = a[j2 + 0] - a[k2 + 0];
|
||||
@@ -427,5 +425,3 @@ void aec_rdft_init_sse2(void) {
|
||||
rftfsub_128 = rftfsub_128_SSE2;
|
||||
rftbsub_128 = rftbsub_128_SSE2;
|
||||
}
|
||||
|
||||
#endif // WEBRTC_USE_SS2
|
||||
|
||||
209
webrtc/modules/audio_processing/aec/aec_resampler.c
Normal file
209
webrtc/modules/audio_processing/aec/aec_resampler.c
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Resamples a signal to an arbitrary rate. Used by the AEC to compensate for
|
||||
* clock skew by resampling the farend signal.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/audio_processing/aec/aec_resampler.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "webrtc/modules/audio_processing/aec/aec_core.h"
|
||||
|
||||
enum {
|
||||
kEstimateLengthFrames = 400
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
float buffer[kResamplerBufferSize];
|
||||
float position;
|
||||
|
||||
int deviceSampleRateHz;
|
||||
int skewData[kEstimateLengthFrames];
|
||||
int skewDataIndex;
|
||||
float skewEstimate;
|
||||
} AecResampler;
|
||||
|
||||
static int EstimateSkew(const int* rawSkew,
|
||||
int size,
|
||||
int absLimit,
|
||||
float* skewEst);
|
||||
|
||||
void* WebRtcAec_CreateResampler() {
|
||||
return malloc(sizeof(AecResampler));
|
||||
}
|
||||
|
||||
int WebRtcAec_InitResampler(void* resampInst, int deviceSampleRateHz) {
|
||||
AecResampler* obj = (AecResampler*)resampInst;
|
||||
memset(obj->buffer, 0, sizeof(obj->buffer));
|
||||
obj->position = 0.0;
|
||||
|
||||
obj->deviceSampleRateHz = deviceSampleRateHz;
|
||||
memset(obj->skewData, 0, sizeof(obj->skewData));
|
||||
obj->skewDataIndex = 0;
|
||||
obj->skewEstimate = 0.0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WebRtcAec_FreeResampler(void* resampInst) {
|
||||
AecResampler* obj = (AecResampler*)resampInst;
|
||||
free(obj);
|
||||
}
|
||||
|
||||
void WebRtcAec_ResampleLinear(void* resampInst,
|
||||
const float* inspeech,
|
||||
size_t size,
|
||||
float skew,
|
||||
float* outspeech,
|
||||
size_t* size_out) {
|
||||
AecResampler* obj = (AecResampler*)resampInst;
|
||||
|
||||
float* y;
|
||||
float be, tnew;
|
||||
size_t tn, mm;
|
||||
|
||||
assert(size <= 2 * FRAME_LEN);
|
||||
assert(resampInst != NULL);
|
||||
assert(inspeech != NULL);
|
||||
assert(outspeech != NULL);
|
||||
assert(size_out != NULL);
|
||||
|
||||
// Add new frame data in lookahead
|
||||
memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay],
|
||||
inspeech,
|
||||
size * sizeof(inspeech[0]));
|
||||
|
||||
// Sample rate ratio
|
||||
be = 1 + skew;
|
||||
|
||||
// Loop over input frame
|
||||
mm = 0;
|
||||
y = &obj->buffer[FRAME_LEN]; // Point at current frame
|
||||
|
||||
tnew = be * mm + obj->position;
|
||||
tn = (size_t)tnew;
|
||||
|
||||
while (tn < size) {
|
||||
|
||||
// Interpolation
|
||||
outspeech[mm] = y[tn] + (tnew - tn) * (y[tn + 1] - y[tn]);
|
||||
mm++;
|
||||
|
||||
tnew = be * mm + obj->position;
|
||||
tn = (int)tnew;
|
||||
}
|
||||
|
||||
*size_out = mm;
|
||||
obj->position += (*size_out) * be - size;
|
||||
|
||||
// Shift buffer
|
||||
memmove(obj->buffer,
|
||||
&obj->buffer[size],
|
||||
(kResamplerBufferSize - size) * sizeof(obj->buffer[0]));
|
||||
}
|
||||
|
||||
int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst) {
|
||||
AecResampler* obj = (AecResampler*)resampInst;
|
||||
int err = 0;
|
||||
|
||||
if (obj->skewDataIndex < kEstimateLengthFrames) {
|
||||
obj->skewData[obj->skewDataIndex] = rawSkew;
|
||||
obj->skewDataIndex++;
|
||||
} else if (obj->skewDataIndex == kEstimateLengthFrames) {
|
||||
err = EstimateSkew(
|
||||
obj->skewData, kEstimateLengthFrames, obj->deviceSampleRateHz, skewEst);
|
||||
obj->skewEstimate = *skewEst;
|
||||
obj->skewDataIndex++;
|
||||
} else {
|
||||
*skewEst = obj->skewEstimate;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int EstimateSkew(const int* rawSkew,
|
||||
int size,
|
||||
int deviceSampleRateHz,
|
||||
float* skewEst) {
|
||||
const int absLimitOuter = (int)(0.04f * deviceSampleRateHz);
|
||||
const int absLimitInner = (int)(0.0025f * deviceSampleRateHz);
|
||||
int i = 0;
|
||||
int n = 0;
|
||||
float rawAvg = 0;
|
||||
float err = 0;
|
||||
float rawAbsDev = 0;
|
||||
int upperLimit = 0;
|
||||
int lowerLimit = 0;
|
||||
float cumSum = 0;
|
||||
float x = 0;
|
||||
float x2 = 0;
|
||||
float y = 0;
|
||||
float xy = 0;
|
||||
float xAvg = 0;
|
||||
float denom = 0;
|
||||
float skew = 0;
|
||||
|
||||
*skewEst = 0; // Set in case of error below.
|
||||
for (i = 0; i < size; i++) {
|
||||
if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
|
||||
n++;
|
||||
rawAvg += rawSkew[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
return -1;
|
||||
}
|
||||
assert(n > 0);
|
||||
rawAvg /= n;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
|
||||
err = rawSkew[i] - rawAvg;
|
||||
rawAbsDev += err >= 0 ? err : -err;
|
||||
}
|
||||
}
|
||||
assert(n > 0);
|
||||
rawAbsDev /= n;
|
||||
upperLimit = (int)(rawAvg + 5 * rawAbsDev + 1); // +1 for ceiling.
|
||||
lowerLimit = (int)(rawAvg - 5 * rawAbsDev - 1); // -1 for floor.
|
||||
|
||||
n = 0;
|
||||
for (i = 0; i < size; i++) {
|
||||
if ((rawSkew[i] < absLimitInner && rawSkew[i] > -absLimitInner) ||
|
||||
(rawSkew[i] < upperLimit && rawSkew[i] > lowerLimit)) {
|
||||
n++;
|
||||
cumSum += rawSkew[i];
|
||||
x += n;
|
||||
x2 += n * n;
|
||||
y += cumSum;
|
||||
xy += n * cumSum;
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
return -1;
|
||||
}
|
||||
assert(n > 0);
|
||||
xAvg = x / n;
|
||||
denom = x2 - xAvg * x;
|
||||
|
||||
if (denom != 0) {
|
||||
skew = (xy - xAvg * y) / denom;
|
||||
}
|
||||
|
||||
*skewEst = skew;
|
||||
return 0;
|
||||
}
|
||||
39
webrtc/modules/audio_processing/aec/aec_resampler.h
Normal file
39
webrtc/modules/audio_processing/aec/aec_resampler.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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_MODULES_AUDIO_PROCESSING_AEC_AEC_RESAMPLER_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_RESAMPLER_H_
|
||||
|
||||
#include "webrtc/modules/audio_processing/aec/aec_core.h"
|
||||
|
||||
enum {
|
||||
kResamplingDelay = 1
|
||||
};
|
||||
enum {
|
||||
kResamplerBufferSize = FRAME_LEN * 4
|
||||
};
|
||||
|
||||
// Unless otherwise specified, functions return 0 on success and -1 on error.
|
||||
void* WebRtcAec_CreateResampler(); // Returns NULL on error.
|
||||
int WebRtcAec_InitResampler(void* resampInst, int deviceSampleRateHz);
|
||||
void WebRtcAec_FreeResampler(void* resampInst);
|
||||
|
||||
// Estimates skew from raw measurement.
|
||||
int WebRtcAec_GetSkew(void* resampInst, int rawSkew, float* skewEst);
|
||||
|
||||
// Resamples input using linear interpolation.
|
||||
void WebRtcAec_ResampleLinear(void* resampInst,
|
||||
const float* inspeech,
|
||||
size_t size,
|
||||
float skew,
|
||||
float* outspeech,
|
||||
size_t* size_out);
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_RESAMPLER_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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_MODULES_AUDIO_PROCESSING_AEC_ECHO_CANCELLATION_INTERNAL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_ECHO_CANCELLATION_INTERNAL_H_
|
||||
|
||||
#include "webrtc/common_audio/ring_buffer.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_core.h"
|
||||
|
||||
typedef struct {
|
||||
int delayCtr;
|
||||
int sampFreq;
|
||||
int splitSampFreq;
|
||||
int scSampFreq;
|
||||
float sampFactor; // scSampRate / sampFreq
|
||||
short skewMode;
|
||||
int bufSizeStart;
|
||||
int knownDelay;
|
||||
int rate_factor;
|
||||
|
||||
short initFlag; // indicates if AEC has been initialized
|
||||
|
||||
// Variables used for averaging far end buffer size
|
||||
short counter;
|
||||
int sum;
|
||||
short firstVal;
|
||||
short checkBufSizeCtr;
|
||||
|
||||
// Variables used for delay shifts
|
||||
short msInSndCardBuf;
|
||||
short filtDelay; // Filtered delay estimate.
|
||||
int timeForDelayChange;
|
||||
int startup_phase;
|
||||
int checkBuffSize;
|
||||
short lastDelayDiff;
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
FILE* bufFile;
|
||||
FILE* delayFile;
|
||||
FILE* skewFile;
|
||||
#endif
|
||||
|
||||
// Structures
|
||||
void* resampler;
|
||||
|
||||
int skewFrCtr;
|
||||
int resample; // if the skew is small enough we don't resample
|
||||
int highSkewCtr;
|
||||
float skew;
|
||||
|
||||
RingBuffer* far_pre_buf; // Time domain far-end pre-buffer.
|
||||
|
||||
int lastError;
|
||||
|
||||
int farend_started;
|
||||
|
||||
AecCore* aec;
|
||||
} Aec;
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_ECHO_CANCELLATION_INTERNAL_H_
|
||||
245
webrtc/modules/audio_processing/aec/include/echo_cancellation.h
Normal file
245
webrtc/modules/audio_processing/aec/include/echo_cancellation.h
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* 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_MODULES_AUDIO_PROCESSING_AEC_INCLUDE_ECHO_CANCELLATION_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_INCLUDE_ECHO_CANCELLATION_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// Errors
|
||||
#define AEC_UNSPECIFIED_ERROR 12000
|
||||
#define AEC_UNSUPPORTED_FUNCTION_ERROR 12001
|
||||
#define AEC_UNINITIALIZED_ERROR 12002
|
||||
#define AEC_NULL_POINTER_ERROR 12003
|
||||
#define AEC_BAD_PARAMETER_ERROR 12004
|
||||
|
||||
// Warnings
|
||||
#define AEC_BAD_PARAMETER_WARNING 12050
|
||||
|
||||
enum {
|
||||
kAecNlpConservative = 0,
|
||||
kAecNlpModerate,
|
||||
kAecNlpAggressive
|
||||
};
|
||||
|
||||
enum {
|
||||
kAecFalse = 0,
|
||||
kAecTrue
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int16_t nlpMode; // default kAecNlpModerate
|
||||
int16_t skewMode; // default kAecFalse
|
||||
int16_t metricsMode; // default kAecFalse
|
||||
int delay_logging; // default kAecFalse
|
||||
// float realSkew;
|
||||
} AecConfig;
|
||||
|
||||
typedef struct {
|
||||
int instant;
|
||||
int average;
|
||||
int max;
|
||||
int min;
|
||||
} AecLevel;
|
||||
|
||||
typedef struct {
|
||||
AecLevel rerl;
|
||||
AecLevel erl;
|
||||
AecLevel erle;
|
||||
AecLevel aNlp;
|
||||
} AecMetrics;
|
||||
|
||||
struct AecCore;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocates the memory needed by the AEC. The memory needs to be initialized
|
||||
* separately using the WebRtcAec_Init() function. Returns a pointer to the
|
||||
* object or NULL on error.
|
||||
*/
|
||||
void* WebRtcAec_Create();
|
||||
|
||||
/*
|
||||
* This function releases the memory allocated by WebRtcAec_Create().
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* aecInst Pointer to the AEC instance
|
||||
*/
|
||||
void WebRtcAec_Free(void* aecInst);
|
||||
|
||||
/*
|
||||
* Initializes an AEC instance.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* aecInst Pointer to the AEC instance
|
||||
* int32_t sampFreq Sampling frequency of data
|
||||
* int32_t scSampFreq Soundcard sampling frequency
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq);
|
||||
|
||||
/*
|
||||
* Inserts an 80 or 160 sample block of data into the farend buffer.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* aecInst Pointer to the AEC instance
|
||||
* const float* farend In buffer containing one frame of
|
||||
* farend signal for L band
|
||||
* int16_t nrOfSamples Number of samples in farend buffer
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
int32_t WebRtcAec_BufferFarend(void* aecInst,
|
||||
const float* farend,
|
||||
size_t nrOfSamples);
|
||||
|
||||
/*
|
||||
* Runs the echo canceller on an 80 or 160 sample blocks of data.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* aecInst Pointer to the AEC instance
|
||||
* float* const* nearend In buffer containing one frame of
|
||||
* nearend+echo signal for each band
|
||||
* int num_bands Number of bands in nearend buffer
|
||||
* int16_t nrOfSamples Number of samples in nearend buffer
|
||||
* int16_t msInSndCardBuf Delay estimate for sound card and
|
||||
* system buffers
|
||||
* int16_t skew Difference between number of samples played
|
||||
* and recorded at the soundcard (for clock skew
|
||||
* compensation)
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* float* const* out Out buffer, one frame of processed nearend
|
||||
* for each band
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
int32_t WebRtcAec_Process(void* aecInst,
|
||||
const float* const* nearend,
|
||||
size_t num_bands,
|
||||
float* const* out,
|
||||
size_t nrOfSamples,
|
||||
int16_t msInSndCardBuf,
|
||||
int32_t skew);
|
||||
|
||||
/*
|
||||
* This function enables the user to set certain parameters on-the-fly.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* handle Pointer to the AEC instance
|
||||
* AecConfig config Config instance that contains all
|
||||
* properties to be set
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
int WebRtcAec_set_config(void* handle, AecConfig config);
|
||||
|
||||
/*
|
||||
* Gets the current echo status of the nearend signal.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* handle Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int* status 0: Almost certainly nearend single-talk
|
||||
* 1: Might not be neared single-talk
|
||||
* int return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
int WebRtcAec_get_echo_status(void* handle, int* status);
|
||||
|
||||
/*
|
||||
* Gets the current echo metrics for the session.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* handle Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* AecMetrics* metrics Struct which will be filled out with the
|
||||
* current echo metrics.
|
||||
* int return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
int WebRtcAec_GetMetrics(void* handle, AecMetrics* metrics);
|
||||
|
||||
/*
|
||||
* Gets the current delay metrics for the session.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* handle Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int* median Delay median value.
|
||||
* int* std Delay standard deviation.
|
||||
* float* fraction_poor_delays Fraction of the delay estimates that may
|
||||
* cause the AEC to perform poorly.
|
||||
*
|
||||
* int return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
int WebRtcAec_GetDelayMetrics(void* handle,
|
||||
int* median,
|
||||
int* std,
|
||||
float* fraction_poor_delays);
|
||||
|
||||
/*
|
||||
* Gets the last error code.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* aecInst Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int32_t return 11000-11100: error code
|
||||
*/
|
||||
int32_t WebRtcAec_get_error_code(void* aecInst);
|
||||
|
||||
// Returns a pointer to the low level AEC handle.
|
||||
//
|
||||
// Input:
|
||||
// - handle : Pointer to the AEC instance.
|
||||
//
|
||||
// Return value:
|
||||
// - AecCore pointer : NULL for error.
|
||||
//
|
||||
struct AecCore* WebRtcAec_aec_core(void* handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_INCLUDE_ECHO_CANCELLATION_H_
|
||||
@@ -1,278 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_INTERFACE_ECHO_CANCELLATION_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_INTERFACE_ECHO_CANCELLATION_H_
|
||||
|
||||
#include "typedefs.h"
|
||||
|
||||
// Errors
|
||||
#define AEC_UNSPECIFIED_ERROR 12000
|
||||
#define AEC_UNSUPPORTED_FUNCTION_ERROR 12001
|
||||
#define AEC_UNINITIALIZED_ERROR 12002
|
||||
#define AEC_NULL_POINTER_ERROR 12003
|
||||
#define AEC_BAD_PARAMETER_ERROR 12004
|
||||
|
||||
// Warnings
|
||||
#define AEC_BAD_PARAMETER_WARNING 12050
|
||||
|
||||
enum {
|
||||
kAecNlpConservative = 0,
|
||||
kAecNlpModerate,
|
||||
kAecNlpAggressive
|
||||
};
|
||||
|
||||
enum {
|
||||
kAecFalse = 0,
|
||||
kAecTrue
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
WebRtc_Word16 nlpMode; // default kAecNlpModerate
|
||||
WebRtc_Word16 skewMode; // default kAecFalse
|
||||
WebRtc_Word16 metricsMode; // default kAecFalse
|
||||
int delay_logging; // default kAecFalse
|
||||
//float realSkew;
|
||||
} AecConfig;
|
||||
|
||||
typedef struct {
|
||||
WebRtc_Word16 instant;
|
||||
WebRtc_Word16 average;
|
||||
WebRtc_Word16 max;
|
||||
WebRtc_Word16 min;
|
||||
} AecLevel;
|
||||
|
||||
typedef struct {
|
||||
AecLevel rerl;
|
||||
AecLevel erl;
|
||||
AecLevel erle;
|
||||
AecLevel aNlp;
|
||||
} AecMetrics;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Allocates the memory needed by the AEC. The memory needs to be initialized
|
||||
* separately using the WebRtcAec_Init() function.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void **aecInst Pointer to the AEC instance to be created
|
||||
* and initialized
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_Create(void **aecInst);
|
||||
|
||||
/*
|
||||
* This function releases the memory allocated by WebRtcAec_Create().
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_Free(void *aecInst);
|
||||
|
||||
/*
|
||||
* Initializes an AEC instance.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
* WebRtc_Word32 sampFreq Sampling frequency of data
|
||||
* WebRtc_Word32 scSampFreq Soundcard sampling frequency
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_Init(void *aecInst,
|
||||
WebRtc_Word32 sampFreq,
|
||||
WebRtc_Word32 scSampFreq);
|
||||
|
||||
/*
|
||||
* Inserts an 80 or 160 sample block of data into the farend buffer.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
* WebRtc_Word16 *farend In buffer containing one frame of
|
||||
* farend signal for L band
|
||||
* WebRtc_Word16 nrOfSamples Number of samples in farend buffer
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_BufferFarend(void *aecInst,
|
||||
const WebRtc_Word16 *farend,
|
||||
WebRtc_Word16 nrOfSamples);
|
||||
|
||||
/*
|
||||
* Runs the echo canceller on an 80 or 160 sample blocks of data.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
* WebRtc_Word16 *nearend In buffer containing one frame of
|
||||
* nearend+echo signal for L band
|
||||
* WebRtc_Word16 *nearendH In buffer containing one frame of
|
||||
* nearend+echo signal for H band
|
||||
* WebRtc_Word16 nrOfSamples Number of samples in nearend buffer
|
||||
* WebRtc_Word16 msInSndCardBuf Delay estimate for sound card and
|
||||
* system buffers
|
||||
* WebRtc_Word16 skew Difference between number of samples played
|
||||
* and recorded at the soundcard (for clock skew
|
||||
* compensation)
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word16 *out Out buffer, one frame of processed nearend
|
||||
* for L band
|
||||
* WebRtc_Word16 *outH Out buffer, one frame of processed nearend
|
||||
* for H band
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_Process(void *aecInst,
|
||||
const WebRtc_Word16 *nearend,
|
||||
const WebRtc_Word16 *nearendH,
|
||||
WebRtc_Word16 *out,
|
||||
WebRtc_Word16 *outH,
|
||||
WebRtc_Word16 nrOfSamples,
|
||||
WebRtc_Word16 msInSndCardBuf,
|
||||
WebRtc_Word32 skew);
|
||||
|
||||
/*
|
||||
* This function enables the user to set certain parameters on-the-fly.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
* AecConfig config Config instance that contains all
|
||||
* properties to be set
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_set_config(void *aecInst, AecConfig config);
|
||||
|
||||
/*
|
||||
* Gets the on-the-fly paramters.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* AecConfig *config Pointer to the config instance that
|
||||
* all properties will be written to
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_get_config(void *aecInst, AecConfig *config);
|
||||
|
||||
/*
|
||||
* Gets the current echo status of the nearend signal.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word16 *status 0: Almost certainly nearend single-talk
|
||||
* 1: Might not be neared single-talk
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_get_echo_status(void *aecInst, WebRtc_Word16 *status);
|
||||
|
||||
/*
|
||||
* Gets the current echo metrics for the session.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* AecMetrics *metrics Struct which will be filled out with the
|
||||
* current echo metrics.
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_GetMetrics(void *aecInst, AecMetrics *metrics);
|
||||
|
||||
/*
|
||||
* Gets the current delay metrics for the session.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void* handle Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* int* median Delay median value.
|
||||
* int* std Delay standard deviation.
|
||||
*
|
||||
* int return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
int WebRtcAec_GetDelayMetrics(void* handle, int* median, int* std);
|
||||
|
||||
/*
|
||||
* Gets the last error code.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecInst Pointer to the AEC instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 11000-11100: error code
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_get_error_code(void *aecInst);
|
||||
|
||||
/*
|
||||
* Gets a version string.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* char *versionStr Pointer to a string array
|
||||
* WebRtc_Word16 len The maximum length of the string
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word8 *versionStr Pointer to a string array
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAec_get_version(WebRtc_Word8 *versionStr, WebRtc_Word16 len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_INTERFACE_ECHO_CANCELLATION_H_ */
|
||||
@@ -1,233 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Resamples a signal to an arbitrary rate. Used by the AEC to compensate for clock
|
||||
* skew by resampling the farend signal.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "resampler.h"
|
||||
#include "aec_core.h"
|
||||
|
||||
enum { kFrameBufferSize = FRAME_LEN * 4 };
|
||||
enum { kEstimateLengthFrames = 400 };
|
||||
|
||||
typedef struct {
|
||||
short buffer[kFrameBufferSize];
|
||||
float position;
|
||||
|
||||
int deviceSampleRateHz;
|
||||
int skewData[kEstimateLengthFrames];
|
||||
int skewDataIndex;
|
||||
float skewEstimate;
|
||||
} resampler_t;
|
||||
|
||||
static int EstimateSkew(const int* rawSkew,
|
||||
int size,
|
||||
int absLimit,
|
||||
float *skewEst);
|
||||
|
||||
int WebRtcAec_CreateResampler(void **resampInst)
|
||||
{
|
||||
resampler_t *obj = malloc(sizeof(resampler_t));
|
||||
*resampInst = obj;
|
||||
if (obj == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcAec_InitResampler(void *resampInst, int deviceSampleRateHz)
|
||||
{
|
||||
resampler_t *obj = (resampler_t*) resampInst;
|
||||
memset(obj->buffer, 0, sizeof(obj->buffer));
|
||||
obj->position = 0.0;
|
||||
|
||||
obj->deviceSampleRateHz = deviceSampleRateHz;
|
||||
memset(obj->skewData, 0, sizeof(obj->skewData));
|
||||
obj->skewDataIndex = 0;
|
||||
obj->skewEstimate = 0.0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcAec_FreeResampler(void *resampInst)
|
||||
{
|
||||
resampler_t *obj = (resampler_t*) resampInst;
|
||||
free(obj);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcAec_ResampleLinear(void *resampInst,
|
||||
const short *inspeech,
|
||||
int size,
|
||||
float skew,
|
||||
short *outspeech)
|
||||
{
|
||||
resampler_t *obj = (resampler_t*) resampInst;
|
||||
|
||||
short *y;
|
||||
float be, tnew, interp;
|
||||
int tn, outsize, mm;
|
||||
|
||||
if (size < 0 || size > 2 * FRAME_LEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Add new frame data in lookahead
|
||||
memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay],
|
||||
inspeech,
|
||||
size * sizeof(short));
|
||||
|
||||
// Sample rate ratio
|
||||
be = 1 + skew;
|
||||
|
||||
// Loop over input frame
|
||||
mm = 0;
|
||||
y = &obj->buffer[FRAME_LEN]; // Point at current frame
|
||||
|
||||
tnew = be * mm + obj->position;
|
||||
tn = (int) tnew;
|
||||
|
||||
while (tn < size) {
|
||||
|
||||
// Interpolation
|
||||
interp = y[tn] + (tnew - tn) * (y[tn+1] - y[tn]);
|
||||
|
||||
if (interp > 32767) {
|
||||
interp = 32767;
|
||||
}
|
||||
else if (interp < -32768) {
|
||||
interp = -32768;
|
||||
}
|
||||
|
||||
outspeech[mm] = (short) interp;
|
||||
mm++;
|
||||
|
||||
tnew = be * mm + obj->position;
|
||||
tn = (int) tnew;
|
||||
}
|
||||
|
||||
outsize = mm;
|
||||
obj->position += outsize * be - size;
|
||||
|
||||
// Shift buffer
|
||||
memmove(obj->buffer,
|
||||
&obj->buffer[size],
|
||||
(kFrameBufferSize - size) * sizeof(short));
|
||||
|
||||
return outsize;
|
||||
}
|
||||
|
||||
int WebRtcAec_GetSkew(void *resampInst, int rawSkew, float *skewEst)
|
||||
{
|
||||
resampler_t *obj = (resampler_t*)resampInst;
|
||||
int err = 0;
|
||||
|
||||
if (obj->skewDataIndex < kEstimateLengthFrames) {
|
||||
obj->skewData[obj->skewDataIndex] = rawSkew;
|
||||
obj->skewDataIndex++;
|
||||
}
|
||||
else if (obj->skewDataIndex == kEstimateLengthFrames) {
|
||||
err = EstimateSkew(obj->skewData,
|
||||
kEstimateLengthFrames,
|
||||
obj->deviceSampleRateHz,
|
||||
skewEst);
|
||||
obj->skewEstimate = *skewEst;
|
||||
obj->skewDataIndex++;
|
||||
}
|
||||
else {
|
||||
*skewEst = obj->skewEstimate;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int EstimateSkew(const int* rawSkew,
|
||||
int size,
|
||||
int deviceSampleRateHz,
|
||||
float *skewEst)
|
||||
{
|
||||
const int absLimitOuter = (int)(0.04f * deviceSampleRateHz);
|
||||
const int absLimitInner = (int)(0.0025f * deviceSampleRateHz);
|
||||
int i = 0;
|
||||
int n = 0;
|
||||
float rawAvg = 0;
|
||||
float err = 0;
|
||||
float rawAbsDev = 0;
|
||||
int upperLimit = 0;
|
||||
int lowerLimit = 0;
|
||||
float cumSum = 0;
|
||||
float x = 0;
|
||||
float x2 = 0;
|
||||
float y = 0;
|
||||
float xy = 0;
|
||||
float xAvg = 0;
|
||||
float denom = 0;
|
||||
float skew = 0;
|
||||
|
||||
*skewEst = 0; // Set in case of error below.
|
||||
for (i = 0; i < size; i++) {
|
||||
if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
|
||||
n++;
|
||||
rawAvg += rawSkew[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
return -1;
|
||||
}
|
||||
assert(n > 0);
|
||||
rawAvg /= n;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) {
|
||||
err = rawSkew[i] - rawAvg;
|
||||
rawAbsDev += err >= 0 ? err : -err;
|
||||
}
|
||||
}
|
||||
assert(n > 0);
|
||||
rawAbsDev /= n;
|
||||
upperLimit = (int)(rawAvg + 5 * rawAbsDev + 1); // +1 for ceiling.
|
||||
lowerLimit = (int)(rawAvg - 5 * rawAbsDev - 1); // -1 for floor.
|
||||
|
||||
n = 0;
|
||||
for (i = 0; i < size; i++) {
|
||||
if ((rawSkew[i] < absLimitInner && rawSkew[i] > -absLimitInner) ||
|
||||
(rawSkew[i] < upperLimit && rawSkew[i] > lowerLimit)) {
|
||||
n++;
|
||||
cumSum += rawSkew[i];
|
||||
x += n;
|
||||
x2 += n*n;
|
||||
y += cumSum;
|
||||
xy += n * cumSum;
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
return -1;
|
||||
}
|
||||
assert(n > 0);
|
||||
xAvg = x / n;
|
||||
denom = x2 - xAvg*x;
|
||||
|
||||
if (denom != 0) {
|
||||
skew = (xy - xAvg*y) / denom;
|
||||
}
|
||||
|
||||
*skewEst = skew;
|
||||
return 0;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_RESAMPLER_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_RESAMPLER_H_
|
||||
|
||||
enum { kResamplingDelay = 1 };
|
||||
|
||||
// Unless otherwise specified, functions return 0 on success and -1 on error
|
||||
int WebRtcAec_CreateResampler(void **resampInst);
|
||||
int WebRtcAec_InitResampler(void *resampInst, int deviceSampleRateHz);
|
||||
int WebRtcAec_FreeResampler(void *resampInst);
|
||||
|
||||
// Estimates skew from raw measurement.
|
||||
int WebRtcAec_GetSkew(void *resampInst, int rawSkew, float *skewEst);
|
||||
|
||||
// Resamples input using linear interpolation.
|
||||
// Returns size of resampled array.
|
||||
int WebRtcAec_ResampleLinear(void *resampInst,
|
||||
const short *inspeech,
|
||||
int size,
|
||||
float skew,
|
||||
short *outspeech);
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_RESAMPLER_H_
|
||||
@@ -1,9 +0,0 @@
|
||||
noinst_LTLIBRARIES = libaecm.la
|
||||
|
||||
libaecm_la_SOURCES = interface/echo_control_mobile.h \
|
||||
echo_control_mobile.c \
|
||||
aecm_core.c \
|
||||
aecm_core.h
|
||||
libaecm_la_CFLAGS = $(AM_CFLAGS) $(COMMON_CFLAGS) \
|
||||
-I$(top_srcdir)/src/common_audio/signal_processing_library/main/interface \
|
||||
-I$(top_srcdir)/src/modules/audio_processing/utility
|
||||
@@ -1,34 +0,0 @@
|
||||
# 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.
|
||||
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'aecm',
|
||||
'type': '<(library)',
|
||||
'dependencies': [
|
||||
'<(webrtc_root)/common_audio/common_audio.gyp:spl',
|
||||
'apm_util'
|
||||
],
|
||||
'include_dirs': [
|
||||
'interface',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'interface',
|
||||
],
|
||||
},
|
||||
'sources': [
|
||||
'interface/echo_control_mobile.h',
|
||||
'echo_control_mobile.c',
|
||||
'aecm_core.c',
|
||||
'aecm_core.h',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
* 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
|
||||
@@ -8,217 +8,144 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
// Performs echo control (suppression) with fft routines in fixed-point
|
||||
// Performs echo control (suppression) with fft routines in fixed-point.
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_SOURCE_AECM_CORE_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_SOURCE_AECM_CORE_H_
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AECM_AECM_CORE_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_AECM_CORE_H_
|
||||
|
||||
#define AECM_DYNAMIC_Q // turn on/off dynamic Q-domain
|
||||
//#define AECM_WITH_ABS_APPROX
|
||||
//#define AECM_SHORT // for 32 sample partition length (otherwise 64)
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
// Algorithm parameters
|
||||
|
||||
#define FRAME_LEN 80 // Total frame length, 10 ms
|
||||
#ifdef AECM_SHORT
|
||||
|
||||
#define PART_LEN 32 // Length of partition
|
||||
#define PART_LEN_SHIFT 6 // Length of (PART_LEN * 2) in base 2
|
||||
|
||||
#else
|
||||
|
||||
#define PART_LEN 64 // Length of partition
|
||||
#define PART_LEN_SHIFT 7 // Length of (PART_LEN * 2) in base 2
|
||||
#include "webrtc/common_audio/ring_buffer.h"
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/modules/audio_processing/aecm/aecm_defines.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
#ifdef _MSC_VER // visual c++
|
||||
#define ALIGN8_BEG __declspec(align(8))
|
||||
#define ALIGN8_END
|
||||
#else // gcc or icc
|
||||
#define ALIGN8_BEG
|
||||
#define ALIGN8_END __attribute__((aligned(8)))
|
||||
#endif
|
||||
|
||||
#define PART_LEN1 (PART_LEN + 1) // Unique fft coefficients
|
||||
#define PART_LEN2 (PART_LEN << 1) // Length of partition * 2
|
||||
#define PART_LEN4 (PART_LEN << 2) // Length of partition * 4
|
||||
#define FAR_BUF_LEN PART_LEN4 // Length of buffers
|
||||
#define MAX_DELAY 100
|
||||
|
||||
// Counter parameters
|
||||
#ifdef AECM_SHORT
|
||||
|
||||
#define CONV_LEN 1024 // Convergence length used at startup
|
||||
#else
|
||||
|
||||
#define CONV_LEN 512 // Convergence length used at startup
|
||||
#endif
|
||||
|
||||
#define CONV_LEN2 (CONV_LEN << 1) // Convergence length * 2 used at startup
|
||||
// Energy parameters
|
||||
#define MAX_BUF_LEN 64 // History length of energy signals
|
||||
|
||||
#define FAR_ENERGY_MIN 1025 // Lowest Far energy level: At least 2 in energy
|
||||
#define FAR_ENERGY_DIFF 929 // Allowed difference between max and min
|
||||
|
||||
#define ENERGY_DEV_OFFSET 0 // The energy error offset in Q8
|
||||
#define ENERGY_DEV_TOL 400 // The energy estimation tolerance in Q8
|
||||
#define FAR_ENERGY_VAD_REGION 230 // Far VAD tolerance region
|
||||
// Stepsize parameters
|
||||
#define MU_MIN 10 // Min stepsize 2^-MU_MIN (far end energy dependent)
|
||||
#define MU_MAX 1 // Max stepsize 2^-MU_MAX (far end energy dependent)
|
||||
#define MU_DIFF 9 // MU_MIN - MU_MAX
|
||||
// Channel parameters
|
||||
#define MIN_MSE_COUNT 20 // Min number of consecutive blocks with enough far end
|
||||
// energy to compare channel estimates
|
||||
#define MIN_MSE_DIFF 29 // The ratio between adapted and stored channel to
|
||||
// accept a new storage (0.8 in Q-MSE_RESOLUTION)
|
||||
#define MSE_RESOLUTION 5 // MSE parameter resolution
|
||||
#define RESOLUTION_CHANNEL16 12 // W16 Channel in Q-RESOLUTION_CHANNEL16
|
||||
#define RESOLUTION_CHANNEL32 28 // W32 Channel in Q-RESOLUTION_CHANNEL
|
||||
#define CHANNEL_VAD 16 // Minimum energy in frequency band to update channel
|
||||
// Suppression gain parameters: SUPGAIN_ parameters in Q-(RESOLUTION_SUPGAIN)
|
||||
#define RESOLUTION_SUPGAIN 8 // Channel in Q-(RESOLUTION_SUPGAIN)
|
||||
#define SUPGAIN_DEFAULT (1 << RESOLUTION_SUPGAIN) // Default suppression gain
|
||||
#define SUPGAIN_ERROR_PARAM_A 3072 // Estimation error parameter (Maximum gain) (8 in Q8)
|
||||
#define SUPGAIN_ERROR_PARAM_B 1536 // Estimation error parameter (Gain before going down)
|
||||
#define SUPGAIN_ERROR_PARAM_D SUPGAIN_DEFAULT // Estimation error parameter
|
||||
// (Should be the same as Default) (1 in Q8)
|
||||
#define SUPGAIN_EPC_DT 200 // = SUPGAIN_ERROR_PARAM_C * ENERGY_DEV_TOL
|
||||
// Defines for "check delay estimation"
|
||||
#define CORR_WIDTH 31 // Number of samples to correlate over.
|
||||
#define CORR_MAX 16 // Maximum correlation offset
|
||||
#define CORR_MAX_BUF 63
|
||||
#define CORR_DEV 4
|
||||
#define CORR_MAX_LEVEL 20
|
||||
#define CORR_MAX_LOW 4
|
||||
#define CORR_BUF_LEN (CORR_MAX << 1) + 1
|
||||
// Note that CORR_WIDTH + 2*CORR_MAX <= MAX_BUF_LEN
|
||||
|
||||
#define ONE_Q14 (1 << 14)
|
||||
|
||||
// NLP defines
|
||||
#define NLP_COMP_LOW 3277 // 0.2 in Q14
|
||||
#define NLP_COMP_HIGH ONE_Q14 // 1 in Q14
|
||||
|
||||
extern const WebRtc_Word16 WebRtcAecm_kSqrtHanning[];
|
||||
|
||||
typedef struct {
|
||||
WebRtc_Word16 real;
|
||||
WebRtc_Word16 imag;
|
||||
} complex16_t;
|
||||
int16_t real;
|
||||
int16_t imag;
|
||||
} ComplexInt16;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
int farBufWritePos;
|
||||
int farBufReadPos;
|
||||
int knownDelay;
|
||||
int lastKnownDelay;
|
||||
int firstVAD; // Parameter to control poorly initialized channels
|
||||
int firstVAD; // Parameter to control poorly initialized channels
|
||||
|
||||
void *farFrameBuf;
|
||||
void *nearNoisyFrameBuf;
|
||||
void *nearCleanFrameBuf;
|
||||
void *outFrameBuf;
|
||||
RingBuffer* farFrameBuf;
|
||||
RingBuffer* nearNoisyFrameBuf;
|
||||
RingBuffer* nearCleanFrameBuf;
|
||||
RingBuffer* outFrameBuf;
|
||||
|
||||
WebRtc_Word16 farBuf[FAR_BUF_LEN];
|
||||
int16_t farBuf[FAR_BUF_LEN];
|
||||
|
||||
WebRtc_Word16 mult;
|
||||
WebRtc_UWord32 seed;
|
||||
int16_t mult;
|
||||
uint32_t seed;
|
||||
|
||||
// Delay estimation variables
|
||||
void* delay_estimator_farend;
|
||||
void* delay_estimator;
|
||||
WebRtc_UWord16 currentDelay;
|
||||
uint16_t currentDelay;
|
||||
// Far end history variables
|
||||
// TODO(bjornv): Replace |far_history| with ring_buffer.
|
||||
uint16_t far_history[PART_LEN1 * MAX_DELAY];
|
||||
int far_history_pos;
|
||||
int far_q_domains[MAX_DELAY];
|
||||
|
||||
WebRtc_Word16 nlpFlag;
|
||||
WebRtc_Word16 fixedDelay;
|
||||
int16_t nlpFlag;
|
||||
int16_t fixedDelay;
|
||||
|
||||
WebRtc_UWord32 totCount;
|
||||
uint32_t totCount;
|
||||
|
||||
WebRtc_Word16 dfaCleanQDomain;
|
||||
WebRtc_Word16 dfaCleanQDomainOld;
|
||||
WebRtc_Word16 dfaNoisyQDomain;
|
||||
WebRtc_Word16 dfaNoisyQDomainOld;
|
||||
int16_t dfaCleanQDomain;
|
||||
int16_t dfaCleanQDomainOld;
|
||||
int16_t dfaNoisyQDomain;
|
||||
int16_t dfaNoisyQDomainOld;
|
||||
|
||||
WebRtc_Word16 nearLogEnergy[MAX_BUF_LEN];
|
||||
WebRtc_Word16 farLogEnergy;
|
||||
WebRtc_Word16 echoAdaptLogEnergy[MAX_BUF_LEN];
|
||||
WebRtc_Word16 echoStoredLogEnergy[MAX_BUF_LEN];
|
||||
int16_t nearLogEnergy[MAX_BUF_LEN];
|
||||
int16_t farLogEnergy;
|
||||
int16_t echoAdaptLogEnergy[MAX_BUF_LEN];
|
||||
int16_t echoStoredLogEnergy[MAX_BUF_LEN];
|
||||
|
||||
// The extra 16 or 32 bytes in the following buffers are for alignment based Neon code.
|
||||
// It's designed this way since the current GCC compiler can't align a buffer in 16 or 32
|
||||
// byte boundaries properly.
|
||||
WebRtc_Word16 channelStored_buf[PART_LEN1 + 8];
|
||||
WebRtc_Word16 channelAdapt16_buf[PART_LEN1 + 8];
|
||||
WebRtc_Word32 channelAdapt32_buf[PART_LEN1 + 8];
|
||||
WebRtc_Word16 xBuf_buf[PART_LEN2 + 16]; // farend
|
||||
WebRtc_Word16 dBufClean_buf[PART_LEN2 + 16]; // nearend
|
||||
WebRtc_Word16 dBufNoisy_buf[PART_LEN2 + 16]; // nearend
|
||||
WebRtc_Word16 outBuf_buf[PART_LEN + 8];
|
||||
// The extra 16 or 32 bytes in the following buffers are for alignment based
|
||||
// Neon code.
|
||||
// It's designed this way since the current GCC compiler can't align a
|
||||
// buffer in 16 or 32 byte boundaries properly.
|
||||
int16_t channelStored_buf[PART_LEN1 + 8];
|
||||
int16_t channelAdapt16_buf[PART_LEN1 + 8];
|
||||
int32_t channelAdapt32_buf[PART_LEN1 + 8];
|
||||
int16_t xBuf_buf[PART_LEN2 + 16]; // farend
|
||||
int16_t dBufClean_buf[PART_LEN2 + 16]; // nearend
|
||||
int16_t dBufNoisy_buf[PART_LEN2 + 16]; // nearend
|
||||
int16_t outBuf_buf[PART_LEN + 8];
|
||||
|
||||
// Pointers to the above buffers
|
||||
WebRtc_Word16 *channelStored;
|
||||
WebRtc_Word16 *channelAdapt16;
|
||||
WebRtc_Word32 *channelAdapt32;
|
||||
WebRtc_Word16 *xBuf;
|
||||
WebRtc_Word16 *dBufClean;
|
||||
WebRtc_Word16 *dBufNoisy;
|
||||
WebRtc_Word16 *outBuf;
|
||||
int16_t *channelStored;
|
||||
int16_t *channelAdapt16;
|
||||
int32_t *channelAdapt32;
|
||||
int16_t *xBuf;
|
||||
int16_t *dBufClean;
|
||||
int16_t *dBufNoisy;
|
||||
int16_t *outBuf;
|
||||
|
||||
WebRtc_Word32 echoFilt[PART_LEN1];
|
||||
WebRtc_Word16 nearFilt[PART_LEN1];
|
||||
WebRtc_Word32 noiseEst[PART_LEN1];
|
||||
int32_t echoFilt[PART_LEN1];
|
||||
int16_t nearFilt[PART_LEN1];
|
||||
int32_t noiseEst[PART_LEN1];
|
||||
int noiseEstTooLowCtr[PART_LEN1];
|
||||
int noiseEstTooHighCtr[PART_LEN1];
|
||||
WebRtc_Word16 noiseEstCtr;
|
||||
WebRtc_Word16 cngMode;
|
||||
int16_t noiseEstCtr;
|
||||
int16_t cngMode;
|
||||
|
||||
WebRtc_Word32 mseAdaptOld;
|
||||
WebRtc_Word32 mseStoredOld;
|
||||
WebRtc_Word32 mseThreshold;
|
||||
int32_t mseAdaptOld;
|
||||
int32_t mseStoredOld;
|
||||
int32_t mseThreshold;
|
||||
|
||||
WebRtc_Word16 farEnergyMin;
|
||||
WebRtc_Word16 farEnergyMax;
|
||||
WebRtc_Word16 farEnergyMaxMin;
|
||||
WebRtc_Word16 farEnergyVAD;
|
||||
WebRtc_Word16 farEnergyMSE;
|
||||
int16_t farEnergyMin;
|
||||
int16_t farEnergyMax;
|
||||
int16_t farEnergyMaxMin;
|
||||
int16_t farEnergyVAD;
|
||||
int16_t farEnergyMSE;
|
||||
int currentVADValue;
|
||||
WebRtc_Word16 vadUpdateCount;
|
||||
int16_t vadUpdateCount;
|
||||
|
||||
WebRtc_Word16 startupState;
|
||||
WebRtc_Word16 mseChannelCount;
|
||||
WebRtc_Word16 supGain;
|
||||
WebRtc_Word16 supGainOld;
|
||||
int16_t startupState;
|
||||
int16_t mseChannelCount;
|
||||
int16_t supGain;
|
||||
int16_t supGainOld;
|
||||
|
||||
WebRtc_Word16 supGainErrParamA;
|
||||
WebRtc_Word16 supGainErrParamD;
|
||||
WebRtc_Word16 supGainErrParamDiffAB;
|
||||
WebRtc_Word16 supGainErrParamDiffBD;
|
||||
int16_t supGainErrParamA;
|
||||
int16_t supGainErrParamD;
|
||||
int16_t supGainErrParamDiffAB;
|
||||
int16_t supGainErrParamDiffBD;
|
||||
|
||||
struct RealFFT* real_fft;
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
FILE *farFile;
|
||||
FILE *nearFile;
|
||||
FILE *outFile;
|
||||
#endif
|
||||
} AecmCore_t;
|
||||
} AecmCore;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_CreateCore(...)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_CreateCore()
|
||||
//
|
||||
// Allocates the memory needed by the AECM. The memory needs to be
|
||||
// initialized separately using the WebRtcAecm_InitCore() function.
|
||||
//
|
||||
// Input:
|
||||
// - aecm : Instance that should be created
|
||||
//
|
||||
// Output:
|
||||
// - aecm : Created instance
|
||||
//
|
||||
// Return value : 0 - Ok
|
||||
// -1 - Error
|
||||
//
|
||||
int WebRtcAecm_CreateCore(AecmCore_t **aecm);
|
||||
// Returns a pointer to the instance and a nullptr at failure.
|
||||
AecmCore* WebRtcAecm_CreateCore();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_InitCore(...)
|
||||
//
|
||||
// This function initializes the AECM instant created with WebRtcAecm_CreateCore(...)
|
||||
// This function initializes the AECM instant created with
|
||||
// WebRtcAecm_CreateCore()
|
||||
// Input:
|
||||
// - aecm : Pointer to the AECM instance
|
||||
// - samplingFreq : Sampling Frequency
|
||||
@@ -229,57 +156,58 @@ int WebRtcAecm_CreateCore(AecmCore_t **aecm);
|
||||
// Return value : 0 - Ok
|
||||
// -1 - Error
|
||||
//
|
||||
int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq);
|
||||
int WebRtcAecm_InitCore(AecmCore* const aecm, int samplingFreq);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_FreeCore(...)
|
||||
//
|
||||
// This function releases the memory allocated by WebRtcAecm_CreateCore()
|
||||
// Input:
|
||||
// - aecm : Pointer to the AECM instance
|
||||
//
|
||||
// Return value : 0 - Ok
|
||||
// -1 - Error
|
||||
// 11001-11016: Error
|
||||
//
|
||||
int WebRtcAecm_FreeCore(AecmCore_t *aecm);
|
||||
void WebRtcAecm_FreeCore(AecmCore* aecm);
|
||||
|
||||
int WebRtcAecm_Control(AecmCore_t *aecm, int delay, int nlpFlag);
|
||||
int WebRtcAecm_Control(AecmCore* aecm, int delay, int nlpFlag);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_InitEchoPathCore(...)
|
||||
//
|
||||
// This function resets the echo channel adaptation with the specified channel.
|
||||
// Input:
|
||||
// - aecm : Pointer to the AECM instance
|
||||
// - echo_path : Pointer to the data that should initialize the echo path
|
||||
// - echo_path : Pointer to the data that should initialize the echo
|
||||
// path
|
||||
//
|
||||
// Output:
|
||||
// - aecm : Initialized instance
|
||||
//
|
||||
void WebRtcAecm_InitEchoPathCore(AecmCore_t* aecm, const WebRtc_Word16* echo_path);
|
||||
void WebRtcAecm_InitEchoPathCore(AecmCore* aecm, const int16_t* echo_path);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_ProcessFrame(...)
|
||||
//
|
||||
// This function processes frames and sends blocks to WebRtcAecm_ProcessBlock(...)
|
||||
// This function processes frames and sends blocks to
|
||||
// WebRtcAecm_ProcessBlock(...)
|
||||
//
|
||||
// Inputs:
|
||||
// - aecm : Pointer to the AECM instance
|
||||
// - farend : In buffer containing one frame of echo signal
|
||||
// - nearendNoisy : In buffer containing one frame of nearend+echo signal without NS
|
||||
// - nearendClean : In buffer containing one frame of nearend+echo signal with NS
|
||||
// - nearendNoisy : In buffer containing one frame of nearend+echo signal
|
||||
// without NS
|
||||
// - nearendClean : In buffer containing one frame of nearend+echo signal
|
||||
// with NS
|
||||
//
|
||||
// Output:
|
||||
// - out : Out buffer, one frame of nearend signal :
|
||||
//
|
||||
//
|
||||
int WebRtcAecm_ProcessFrame(AecmCore_t * aecm, const WebRtc_Word16 * farend,
|
||||
const WebRtc_Word16 * nearendNoisy,
|
||||
const WebRtc_Word16 * nearendClean,
|
||||
WebRtc_Word16 * out);
|
||||
int WebRtcAecm_ProcessFrame(AecmCore* aecm,
|
||||
const int16_t* farend,
|
||||
const int16_t* nearendNoisy,
|
||||
const int16_t* nearendClean,
|
||||
int16_t* out);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_ProcessBlock(...)
|
||||
//
|
||||
// This function is called for every block within one frame
|
||||
@@ -288,19 +216,22 @@ int WebRtcAecm_ProcessFrame(AecmCore_t * aecm, const WebRtc_Word16 * farend,
|
||||
// Inputs:
|
||||
// - aecm : Pointer to the AECM instance
|
||||
// - farend : In buffer containing one block of echo signal
|
||||
// - nearendNoisy : In buffer containing one frame of nearend+echo signal without NS
|
||||
// - nearendClean : In buffer containing one frame of nearend+echo signal with NS
|
||||
// - nearendNoisy : In buffer containing one frame of nearend+echo signal
|
||||
// without NS
|
||||
// - nearendClean : In buffer containing one frame of nearend+echo signal
|
||||
// with NS
|
||||
//
|
||||
// Output:
|
||||
// - out : Out buffer, one block of nearend signal :
|
||||
//
|
||||
//
|
||||
int WebRtcAecm_ProcessBlock(AecmCore_t * aecm, const WebRtc_Word16 * farend,
|
||||
const WebRtc_Word16 * nearendNoisy,
|
||||
const WebRtc_Word16 * noisyClean,
|
||||
WebRtc_Word16 * out);
|
||||
int WebRtcAecm_ProcessBlock(AecmCore* aecm,
|
||||
const int16_t* farend,
|
||||
const int16_t* nearendNoisy,
|
||||
const int16_t* noisyClean,
|
||||
int16_t* out);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_BufferFarFrame()
|
||||
//
|
||||
// Inserts a frame of data into farend buffer.
|
||||
@@ -310,10 +241,11 @@ int WebRtcAecm_ProcessBlock(AecmCore_t * aecm, const WebRtc_Word16 * farend,
|
||||
// - farend : In buffer containing one frame of farend signal
|
||||
// - farLen : Length of frame
|
||||
//
|
||||
void WebRtcAecm_BufferFarFrame(AecmCore_t * const aecm, const WebRtc_Word16 * const farend,
|
||||
void WebRtcAecm_BufferFarFrame(AecmCore* const aecm,
|
||||
const int16_t* const farend,
|
||||
const int farLen);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_FetchFarFrame()
|
||||
//
|
||||
// Read the farend buffer to account for known delay
|
||||
@@ -324,35 +256,179 @@ void WebRtcAecm_BufferFarFrame(AecmCore_t * const aecm, const WebRtc_Word16 * co
|
||||
// - farLen : Length of frame
|
||||
// - knownDelay : known delay
|
||||
//
|
||||
void WebRtcAecm_FetchFarFrame(AecmCore_t * const aecm, WebRtc_Word16 * const farend,
|
||||
const int farLen, const int knownDelay);
|
||||
void WebRtcAecm_FetchFarFrame(AecmCore* const aecm,
|
||||
int16_t* const farend,
|
||||
const int farLen,
|
||||
const int knownDelay);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Some internal functions shared by ARM NEON and generic C code:
|
||||
// All the functions below are intended to be private
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_UpdateFarHistory()
|
||||
//
|
||||
// Moves the pointer to the next entry and inserts |far_spectrum| and
|
||||
// corresponding Q-domain in its buffer.
|
||||
//
|
||||
// Inputs:
|
||||
// - self : Pointer to the delay estimation instance
|
||||
// - far_spectrum : Pointer to the far end spectrum
|
||||
// - far_q : Q-domain of far end spectrum
|
||||
//
|
||||
void WebRtcAecm_UpdateFarHistory(AecmCore* self,
|
||||
uint16_t* far_spectrum,
|
||||
int far_q);
|
||||
|
||||
void WebRtcAecm_CalcLinearEnergies(AecmCore_t* aecm,
|
||||
const WebRtc_UWord16* far_spectrum,
|
||||
WebRtc_Word32* echoEst,
|
||||
WebRtc_UWord32* far_energy,
|
||||
WebRtc_UWord32* echo_energy_adapt,
|
||||
WebRtc_UWord32* echo_energy_stored);
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_AlignedFarend()
|
||||
//
|
||||
// Returns a pointer to the far end spectrum aligned to current near end
|
||||
// spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been
|
||||
// called before AlignedFarend(...). Otherwise, you get the pointer to the
|
||||
// previous frame. The memory is only valid until the next call of
|
||||
// WebRtc_DelayEstimatorProcessFix(...).
|
||||
//
|
||||
// Inputs:
|
||||
// - self : Pointer to the AECM instance.
|
||||
// - delay : Current delay estimate.
|
||||
//
|
||||
// Output:
|
||||
// - far_q : The Q-domain of the aligned far end spectrum
|
||||
//
|
||||
// Return value:
|
||||
// - far_spectrum : Pointer to the aligned far end spectrum
|
||||
// NULL - Error
|
||||
//
|
||||
const uint16_t* WebRtcAecm_AlignedFarend(AecmCore* self, int* far_q, int delay);
|
||||
|
||||
void WebRtcAecm_StoreAdaptiveChannel(AecmCore_t* aecm,
|
||||
const WebRtc_UWord16* far_spectrum,
|
||||
WebRtc_Word32* echo_est);
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_CalcSuppressionGain()
|
||||
//
|
||||
// This function calculates the suppression gain that is used in the
|
||||
// Wiener filter.
|
||||
//
|
||||
// Inputs:
|
||||
// - aecm : Pointer to the AECM instance.
|
||||
//
|
||||
// Return value:
|
||||
// - supGain : Suppression gain with which to scale the noise
|
||||
// level (Q14).
|
||||
//
|
||||
int16_t WebRtcAecm_CalcSuppressionGain(AecmCore* const aecm);
|
||||
|
||||
void WebRtcAecm_ResetAdaptiveChannel(AecmCore_t *aecm);
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_CalcEnergies()
|
||||
//
|
||||
// This function calculates the log of energies for nearend, farend and
|
||||
// estimated echoes. There is also an update of energy decision levels,
|
||||
// i.e. internal VAD.
|
||||
//
|
||||
// Inputs:
|
||||
// - aecm : Pointer to the AECM instance.
|
||||
// - far_spectrum : Pointer to farend spectrum.
|
||||
// - far_q : Q-domain of farend spectrum.
|
||||
// - nearEner : Near end energy for current block in
|
||||
// Q(aecm->dfaQDomain).
|
||||
//
|
||||
// Output:
|
||||
// - echoEst : Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16).
|
||||
//
|
||||
void WebRtcAecm_CalcEnergies(AecmCore* aecm,
|
||||
const uint16_t* far_spectrum,
|
||||
const int16_t far_q,
|
||||
const uint32_t nearEner,
|
||||
int32_t* echoEst);
|
||||
|
||||
void WebRtcAecm_WindowAndFFT(WebRtc_Word16* fft,
|
||||
const WebRtc_Word16* time_signal,
|
||||
complex16_t* freq_signal,
|
||||
int time_signal_scaling);
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_CalcStepSize()
|
||||
//
|
||||
// This function calculates the step size used in channel estimation
|
||||
//
|
||||
// Inputs:
|
||||
// - aecm : Pointer to the AECM instance.
|
||||
//
|
||||
// Return value:
|
||||
// - mu : Stepsize in log2(), i.e. number of shifts.
|
||||
//
|
||||
int16_t WebRtcAecm_CalcStepSize(AecmCore* const aecm);
|
||||
|
||||
void WebRtcAecm_InverseFFTAndWindow(AecmCore_t* aecm,
|
||||
WebRtc_Word16* fft,
|
||||
complex16_t* efw,
|
||||
WebRtc_Word16* output,
|
||||
const WebRtc_Word16* nearendClean);
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// WebRtcAecm_UpdateChannel(...)
|
||||
//
|
||||
// This function performs channel estimation.
|
||||
// NLMS and decision on channel storage.
|
||||
//
|
||||
// Inputs:
|
||||
// - aecm : Pointer to the AECM instance.
|
||||
// - far_spectrum : Absolute value of the farend signal in Q(far_q)
|
||||
// - far_q : Q-domain of the farend signal
|
||||
// - dfa : Absolute value of the nearend signal
|
||||
// (Q[aecm->dfaQDomain])
|
||||
// - mu : NLMS step size.
|
||||
// Input/Output:
|
||||
// - echoEst : Estimated echo in Q(far_q+RESOLUTION_CHANNEL16).
|
||||
//
|
||||
void WebRtcAecm_UpdateChannel(AecmCore* aecm,
|
||||
const uint16_t* far_spectrum,
|
||||
const int16_t far_q,
|
||||
const uint16_t* const dfa,
|
||||
const int16_t mu,
|
||||
int32_t* echoEst);
|
||||
|
||||
extern const int16_t WebRtcAecm_kCosTable[];
|
||||
extern const int16_t WebRtcAecm_kSinTable[];
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Some function pointers, for internal functions shared by ARM NEON and
|
||||
// generic C code.
|
||||
//
|
||||
typedef void (*CalcLinearEnergies)(AecmCore* aecm,
|
||||
const uint16_t* far_spectrum,
|
||||
int32_t* echoEst,
|
||||
uint32_t* far_energy,
|
||||
uint32_t* echo_energy_adapt,
|
||||
uint32_t* echo_energy_stored);
|
||||
extern CalcLinearEnergies WebRtcAecm_CalcLinearEnergies;
|
||||
|
||||
typedef void (*StoreAdaptiveChannel)(AecmCore* aecm,
|
||||
const uint16_t* far_spectrum,
|
||||
int32_t* echo_est);
|
||||
extern StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel;
|
||||
|
||||
typedef void (*ResetAdaptiveChannel)(AecmCore* aecm);
|
||||
extern ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel;
|
||||
|
||||
// For the above function pointers, functions for generic platforms are declared
|
||||
// and defined as static in file aecm_core.c, while those for ARM Neon platforms
|
||||
// are declared below and defined in file aecm_core_neon.c.
|
||||
#if defined(WEBRTC_DETECT_NEON) || defined(WEBRTC_HAS_NEON)
|
||||
void WebRtcAecm_CalcLinearEnergiesNeon(AecmCore* aecm,
|
||||
const uint16_t* far_spectrum,
|
||||
int32_t* echo_est,
|
||||
uint32_t* far_energy,
|
||||
uint32_t* echo_energy_adapt,
|
||||
uint32_t* echo_energy_stored);
|
||||
|
||||
void WebRtcAecm_StoreAdaptiveChannelNeon(AecmCore* aecm,
|
||||
const uint16_t* far_spectrum,
|
||||
int32_t* echo_est);
|
||||
|
||||
void WebRtcAecm_ResetAdaptiveChannelNeon(AecmCore* aecm);
|
||||
#endif
|
||||
|
||||
#if defined(MIPS32_LE)
|
||||
void WebRtcAecm_CalcLinearEnergies_mips(AecmCore* aecm,
|
||||
const uint16_t* far_spectrum,
|
||||
int32_t* echo_est,
|
||||
uint32_t* far_energy,
|
||||
uint32_t* echo_energy_adapt,
|
||||
uint32_t* echo_energy_stored);
|
||||
#if defined(MIPS_DSP_R1_LE)
|
||||
void WebRtcAecm_StoreAdaptiveChannel_mips(AecmCore* aecm,
|
||||
const uint16_t* far_spectrum,
|
||||
int32_t* echo_est);
|
||||
|
||||
void WebRtcAecm_ResetAdaptiveChannel_mips(AecmCore* aecm);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
771
webrtc/modules/audio_processing/aecm/aecm_core_c.c
Normal file
771
webrtc/modules/audio_processing/aecm/aecm_core_c.c
Normal file
@@ -0,0 +1,771 @@
|
||||
/*
|
||||
* 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/modules/audio_processing/aecm/aecm_core.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "webrtc/common_audio/ring_buffer.h"
|
||||
#include "webrtc/common_audio/signal_processing/include/real_fft.h"
|
||||
#include "webrtc/modules/audio_processing/aecm/include/echo_control_mobile.h"
|
||||
#include "webrtc/modules/audio_processing/utility/delay_estimator_wrapper.h"
|
||||
#include "webrtc/system_wrappers/interface/compile_assert_c.h"
|
||||
#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// Square root of Hanning window in Q14.
|
||||
#if defined(WEBRTC_DETECT_NEON) || defined(WEBRTC_HAS_NEON)
|
||||
// Table is defined in an ARM assembly file.
|
||||
extern const ALIGN8_BEG int16_t WebRtcAecm_kSqrtHanning[] ALIGN8_END;
|
||||
#else
|
||||
static const ALIGN8_BEG int16_t WebRtcAecm_kSqrtHanning[] ALIGN8_END = {
|
||||
0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172,
|
||||
3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224,
|
||||
6591, 6954, 7313, 7668, 8019, 8364, 8705, 9040,
|
||||
9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514,
|
||||
11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553,
|
||||
13773, 13985, 14189, 14384, 14571, 14749, 14918, 15079,
|
||||
15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034,
|
||||
16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef AECM_WITH_ABS_APPROX
|
||||
//Q15 alpha = 0.99439986968132 const Factor for magnitude approximation
|
||||
static const uint16_t kAlpha1 = 32584;
|
||||
//Q15 beta = 0.12967166976970 const Factor for magnitude approximation
|
||||
static const uint16_t kBeta1 = 4249;
|
||||
//Q15 alpha = 0.94234827210087 const Factor for magnitude approximation
|
||||
static const uint16_t kAlpha2 = 30879;
|
||||
//Q15 beta = 0.33787806009150 const Factor for magnitude approximation
|
||||
static const uint16_t kBeta2 = 11072;
|
||||
//Q15 alpha = 0.82247698684306 const Factor for magnitude approximation
|
||||
static const uint16_t kAlpha3 = 26951;
|
||||
//Q15 beta = 0.57762063060713 const Factor for magnitude approximation
|
||||
static const uint16_t kBeta3 = 18927;
|
||||
#endif
|
||||
|
||||
static const int16_t kNoiseEstQDomain = 15;
|
||||
static const int16_t kNoiseEstIncCount = 5;
|
||||
|
||||
static void ComfortNoise(AecmCore* aecm,
|
||||
const uint16_t* dfa,
|
||||
ComplexInt16* out,
|
||||
const int16_t* lambda);
|
||||
|
||||
static void WindowAndFFT(AecmCore* aecm,
|
||||
int16_t* fft,
|
||||
const int16_t* time_signal,
|
||||
ComplexInt16* freq_signal,
|
||||
int time_signal_scaling) {
|
||||
int i = 0;
|
||||
|
||||
// FFT of signal
|
||||
for (i = 0; i < PART_LEN; i++) {
|
||||
// Window time domain signal and insert into real part of
|
||||
// transformation array |fft|
|
||||
int16_t scaled_time_signal = time_signal[i] << time_signal_scaling;
|
||||
fft[i] = (int16_t)((scaled_time_signal * WebRtcAecm_kSqrtHanning[i]) >> 14);
|
||||
scaled_time_signal = time_signal[i + PART_LEN] << time_signal_scaling;
|
||||
fft[PART_LEN + i] = (int16_t)((
|
||||
scaled_time_signal * WebRtcAecm_kSqrtHanning[PART_LEN - i]) >> 14);
|
||||
}
|
||||
|
||||
// Do forward FFT, then take only the first PART_LEN complex samples,
|
||||
// and change signs of the imaginary parts.
|
||||
WebRtcSpl_RealForwardFFT(aecm->real_fft, fft, (int16_t*)freq_signal);
|
||||
for (i = 0; i < PART_LEN; i++) {
|
||||
freq_signal[i].imag = -freq_signal[i].imag;
|
||||
}
|
||||
}
|
||||
|
||||
static void InverseFFTAndWindow(AecmCore* aecm,
|
||||
int16_t* fft,
|
||||
ComplexInt16* efw,
|
||||
int16_t* output,
|
||||
const int16_t* nearendClean) {
|
||||
int i, j, outCFFT;
|
||||
int32_t tmp32no1;
|
||||
// Reuse |efw| for the inverse FFT output after transferring
|
||||
// the contents to |fft|.
|
||||
int16_t* ifft_out = (int16_t*)efw;
|
||||
|
||||
// Synthesis
|
||||
for (i = 1, j = 2; i < PART_LEN; i += 1, j += 2) {
|
||||
fft[j] = efw[i].real;
|
||||
fft[j + 1] = -efw[i].imag;
|
||||
}
|
||||
fft[0] = efw[0].real;
|
||||
fft[1] = -efw[0].imag;
|
||||
|
||||
fft[PART_LEN2] = efw[PART_LEN].real;
|
||||
fft[PART_LEN2 + 1] = -efw[PART_LEN].imag;
|
||||
|
||||
// Inverse FFT. Keep outCFFT to scale the samples in the next block.
|
||||
outCFFT = WebRtcSpl_RealInverseFFT(aecm->real_fft, fft, ifft_out);
|
||||
for (i = 0; i < PART_LEN; i++) {
|
||||
ifft_out[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
|
||||
ifft_out[i], WebRtcAecm_kSqrtHanning[i], 14);
|
||||
tmp32no1 = WEBRTC_SPL_SHIFT_W32((int32_t)ifft_out[i],
|
||||
outCFFT - aecm->dfaCleanQDomain);
|
||||
output[i] = (int16_t)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
|
||||
tmp32no1 + aecm->outBuf[i],
|
||||
WEBRTC_SPL_WORD16_MIN);
|
||||
|
||||
tmp32no1 = (ifft_out[PART_LEN + i] *
|
||||
WebRtcAecm_kSqrtHanning[PART_LEN - i]) >> 14;
|
||||
tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1,
|
||||
outCFFT - aecm->dfaCleanQDomain);
|
||||
aecm->outBuf[i] = (int16_t)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
|
||||
tmp32no1,
|
||||
WEBRTC_SPL_WORD16_MIN);
|
||||
}
|
||||
|
||||
// Copy the current block to the old position
|
||||
// (aecm->outBuf is shifted elsewhere)
|
||||
memcpy(aecm->xBuf, aecm->xBuf + PART_LEN, sizeof(int16_t) * PART_LEN);
|
||||
memcpy(aecm->dBufNoisy,
|
||||
aecm->dBufNoisy + PART_LEN,
|
||||
sizeof(int16_t) * PART_LEN);
|
||||
if (nearendClean != NULL)
|
||||
{
|
||||
memcpy(aecm->dBufClean,
|
||||
aecm->dBufClean + PART_LEN,
|
||||
sizeof(int16_t) * PART_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
// Transforms a time domain signal into the frequency domain, outputting the
|
||||
// complex valued signal, absolute value and sum of absolute values.
|
||||
//
|
||||
// time_signal [in] Pointer to time domain signal
|
||||
// freq_signal_real [out] Pointer to real part of frequency domain array
|
||||
// freq_signal_imag [out] Pointer to imaginary part of frequency domain
|
||||
// array
|
||||
// freq_signal_abs [out] Pointer to absolute value of frequency domain
|
||||
// array
|
||||
// freq_signal_sum_abs [out] Pointer to the sum of all absolute values in
|
||||
// the frequency domain array
|
||||
// return value The Q-domain of current frequency values
|
||||
//
|
||||
static int TimeToFrequencyDomain(AecmCore* aecm,
|
||||
const int16_t* time_signal,
|
||||
ComplexInt16* freq_signal,
|
||||
uint16_t* freq_signal_abs,
|
||||
uint32_t* freq_signal_sum_abs) {
|
||||
int i = 0;
|
||||
int time_signal_scaling = 0;
|
||||
|
||||
int32_t tmp32no1 = 0;
|
||||
int32_t tmp32no2 = 0;
|
||||
|
||||
// In fft_buf, +16 for 32-byte alignment.
|
||||
int16_t fft_buf[PART_LEN4 + 16];
|
||||
int16_t *fft = (int16_t *) (((uintptr_t) fft_buf + 31) & ~31);
|
||||
|
||||
int16_t tmp16no1;
|
||||
#ifndef WEBRTC_ARCH_ARM_V7
|
||||
int16_t tmp16no2;
|
||||
#endif
|
||||
#ifdef AECM_WITH_ABS_APPROX
|
||||
int16_t max_value = 0;
|
||||
int16_t min_value = 0;
|
||||
uint16_t alpha = 0;
|
||||
uint16_t beta = 0;
|
||||
#endif
|
||||
|
||||
#ifdef AECM_DYNAMIC_Q
|
||||
tmp16no1 = WebRtcSpl_MaxAbsValueW16(time_signal, PART_LEN2);
|
||||
time_signal_scaling = WebRtcSpl_NormW16(tmp16no1);
|
||||
#endif
|
||||
|
||||
WindowAndFFT(aecm, fft, time_signal, freq_signal, time_signal_scaling);
|
||||
|
||||
// Extract imaginary and real part, calculate the magnitude for
|
||||
// all frequency bins
|
||||
freq_signal[0].imag = 0;
|
||||
freq_signal[PART_LEN].imag = 0;
|
||||
freq_signal_abs[0] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[0].real);
|
||||
freq_signal_abs[PART_LEN] = (uint16_t)WEBRTC_SPL_ABS_W16(
|
||||
freq_signal[PART_LEN].real);
|
||||
(*freq_signal_sum_abs) = (uint32_t)(freq_signal_abs[0]) +
|
||||
(uint32_t)(freq_signal_abs[PART_LEN]);
|
||||
|
||||
for (i = 1; i < PART_LEN; i++)
|
||||
{
|
||||
if (freq_signal[i].real == 0)
|
||||
{
|
||||
freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
|
||||
}
|
||||
else if (freq_signal[i].imag == 0)
|
||||
{
|
||||
freq_signal_abs[i] = (uint16_t)WEBRTC_SPL_ABS_W16(freq_signal[i].real);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Approximation for magnitude of complex fft output
|
||||
// magn = sqrt(real^2 + imag^2)
|
||||
// magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|)
|
||||
//
|
||||
// The parameters alpha and beta are stored in Q15
|
||||
|
||||
#ifdef AECM_WITH_ABS_APPROX
|
||||
tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real);
|
||||
tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
|
||||
|
||||
if(tmp16no1 > tmp16no2)
|
||||
{
|
||||
max_value = tmp16no1;
|
||||
min_value = tmp16no2;
|
||||
} else
|
||||
{
|
||||
max_value = tmp16no2;
|
||||
min_value = tmp16no1;
|
||||
}
|
||||
|
||||
// Magnitude in Q(-6)
|
||||
if ((max_value >> 2) > min_value)
|
||||
{
|
||||
alpha = kAlpha1;
|
||||
beta = kBeta1;
|
||||
} else if ((max_value >> 1) > min_value)
|
||||
{
|
||||
alpha = kAlpha2;
|
||||
beta = kBeta2;
|
||||
} else
|
||||
{
|
||||
alpha = kAlpha3;
|
||||
beta = kBeta3;
|
||||
}
|
||||
tmp16no1 = (int16_t)((max_value * alpha) >> 15);
|
||||
tmp16no2 = (int16_t)((min_value * beta) >> 15);
|
||||
freq_signal_abs[i] = (uint16_t)tmp16no1 + (uint16_t)tmp16no2;
|
||||
#else
|
||||
#ifdef WEBRTC_ARCH_ARM_V7
|
||||
__asm __volatile(
|
||||
"smulbb %[tmp32no1], %[real], %[real]\n\t"
|
||||
"smlabb %[tmp32no2], %[imag], %[imag], %[tmp32no1]\n\t"
|
||||
:[tmp32no1]"+&r"(tmp32no1),
|
||||
[tmp32no2]"=r"(tmp32no2)
|
||||
:[real]"r"(freq_signal[i].real),
|
||||
[imag]"r"(freq_signal[i].imag)
|
||||
);
|
||||
#else
|
||||
tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real);
|
||||
tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag);
|
||||
tmp32no1 = tmp16no1 * tmp16no1;
|
||||
tmp32no2 = tmp16no2 * tmp16no2;
|
||||
tmp32no2 = WebRtcSpl_AddSatW32(tmp32no1, tmp32no2);
|
||||
#endif // WEBRTC_ARCH_ARM_V7
|
||||
tmp32no1 = WebRtcSpl_SqrtFloor(tmp32no2);
|
||||
|
||||
freq_signal_abs[i] = (uint16_t)tmp32no1;
|
||||
#endif // AECM_WITH_ABS_APPROX
|
||||
}
|
||||
(*freq_signal_sum_abs) += (uint32_t)freq_signal_abs[i];
|
||||
}
|
||||
|
||||
return time_signal_scaling;
|
||||
}
|
||||
|
||||
int WebRtcAecm_ProcessBlock(AecmCore* aecm,
|
||||
const int16_t* farend,
|
||||
const int16_t* nearendNoisy,
|
||||
const int16_t* nearendClean,
|
||||
int16_t* output) {
|
||||
int i;
|
||||
|
||||
uint32_t xfaSum;
|
||||
uint32_t dfaNoisySum;
|
||||
uint32_t dfaCleanSum;
|
||||
uint32_t echoEst32Gained;
|
||||
uint32_t tmpU32;
|
||||
|
||||
int32_t tmp32no1;
|
||||
|
||||
uint16_t xfa[PART_LEN1];
|
||||
uint16_t dfaNoisy[PART_LEN1];
|
||||
uint16_t dfaClean[PART_LEN1];
|
||||
uint16_t* ptrDfaClean = dfaClean;
|
||||
const uint16_t* far_spectrum_ptr = NULL;
|
||||
|
||||
// 32 byte aligned buffers (with +8 or +16).
|
||||
// TODO(kma): define fft with ComplexInt16.
|
||||
int16_t fft_buf[PART_LEN4 + 2 + 16]; // +2 to make a loop safe.
|
||||
int32_t echoEst32_buf[PART_LEN1 + 8];
|
||||
int32_t dfw_buf[PART_LEN2 + 8];
|
||||
int32_t efw_buf[PART_LEN2 + 8];
|
||||
|
||||
int16_t* fft = (int16_t*) (((uintptr_t) fft_buf + 31) & ~ 31);
|
||||
int32_t* echoEst32 = (int32_t*) (((uintptr_t) echoEst32_buf + 31) & ~ 31);
|
||||
ComplexInt16* dfw = (ComplexInt16*)(((uintptr_t)dfw_buf + 31) & ~31);
|
||||
ComplexInt16* efw = (ComplexInt16*)(((uintptr_t)efw_buf + 31) & ~31);
|
||||
|
||||
int16_t hnl[PART_LEN1];
|
||||
int16_t numPosCoef = 0;
|
||||
int16_t nlpGain = ONE_Q14;
|
||||
int delay;
|
||||
int16_t tmp16no1;
|
||||
int16_t tmp16no2;
|
||||
int16_t mu;
|
||||
int16_t supGain;
|
||||
int16_t zeros32, zeros16;
|
||||
int16_t zerosDBufNoisy, zerosDBufClean, zerosXBuf;
|
||||
int far_q;
|
||||
int16_t resolutionDiff, qDomainDiff, dfa_clean_q_domain_diff;
|
||||
|
||||
const int kMinPrefBand = 4;
|
||||
const int kMaxPrefBand = 24;
|
||||
int32_t avgHnl32 = 0;
|
||||
|
||||
// Determine startup state. There are three states:
|
||||
// (0) the first CONV_LEN blocks
|
||||
// (1) another CONV_LEN blocks
|
||||
// (2) the rest
|
||||
|
||||
if (aecm->startupState < 2)
|
||||
{
|
||||
aecm->startupState = (aecm->totCount >= CONV_LEN) +
|
||||
(aecm->totCount >= CONV_LEN2);
|
||||
}
|
||||
// END: Determine startup state
|
||||
|
||||
// Buffer near and far end signals
|
||||
memcpy(aecm->xBuf + PART_LEN, farend, sizeof(int16_t) * PART_LEN);
|
||||
memcpy(aecm->dBufNoisy + PART_LEN, nearendNoisy, sizeof(int16_t) * PART_LEN);
|
||||
if (nearendClean != NULL)
|
||||
{
|
||||
memcpy(aecm->dBufClean + PART_LEN,
|
||||
nearendClean,
|
||||
sizeof(int16_t) * PART_LEN);
|
||||
}
|
||||
|
||||
// Transform far end signal from time domain to frequency domain.
|
||||
far_q = TimeToFrequencyDomain(aecm,
|
||||
aecm->xBuf,
|
||||
dfw,
|
||||
xfa,
|
||||
&xfaSum);
|
||||
|
||||
// Transform noisy near end signal from time domain to frequency domain.
|
||||
zerosDBufNoisy = TimeToFrequencyDomain(aecm,
|
||||
aecm->dBufNoisy,
|
||||
dfw,
|
||||
dfaNoisy,
|
||||
&dfaNoisySum);
|
||||
aecm->dfaNoisyQDomainOld = aecm->dfaNoisyQDomain;
|
||||
aecm->dfaNoisyQDomain = (int16_t)zerosDBufNoisy;
|
||||
|
||||
|
||||
if (nearendClean == NULL)
|
||||
{
|
||||
ptrDfaClean = dfaNoisy;
|
||||
aecm->dfaCleanQDomainOld = aecm->dfaNoisyQDomainOld;
|
||||
aecm->dfaCleanQDomain = aecm->dfaNoisyQDomain;
|
||||
dfaCleanSum = dfaNoisySum;
|
||||
} else
|
||||
{
|
||||
// Transform clean near end signal from time domain to frequency domain.
|
||||
zerosDBufClean = TimeToFrequencyDomain(aecm,
|
||||
aecm->dBufClean,
|
||||
dfw,
|
||||
dfaClean,
|
||||
&dfaCleanSum);
|
||||
aecm->dfaCleanQDomainOld = aecm->dfaCleanQDomain;
|
||||
aecm->dfaCleanQDomain = (int16_t)zerosDBufClean;
|
||||
}
|
||||
|
||||
// Get the delay
|
||||
// Save far-end history and estimate delay
|
||||
WebRtcAecm_UpdateFarHistory(aecm, xfa, far_q);
|
||||
if (WebRtc_AddFarSpectrumFix(aecm->delay_estimator_farend,
|
||||
xfa,
|
||||
PART_LEN1,
|
||||
far_q) == -1) {
|
||||
return -1;
|
||||
}
|
||||
delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator,
|
||||
dfaNoisy,
|
||||
PART_LEN1,
|
||||
zerosDBufNoisy);
|
||||
if (delay == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (delay == -2)
|
||||
{
|
||||
// If the delay is unknown, we assume zero.
|
||||
// NOTE: this will have to be adjusted if we ever add lookahead.
|
||||
delay = 0;
|
||||
}
|
||||
|
||||
if (aecm->fixedDelay >= 0)
|
||||
{
|
||||
// Use fixed delay
|
||||
delay = aecm->fixedDelay;
|
||||
}
|
||||
|
||||
// Get aligned far end spectrum
|
||||
far_spectrum_ptr = WebRtcAecm_AlignedFarend(aecm, &far_q, delay);
|
||||
zerosXBuf = (int16_t) far_q;
|
||||
if (far_spectrum_ptr == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Calculate log(energy) and update energy threshold levels
|
||||
WebRtcAecm_CalcEnergies(aecm,
|
||||
far_spectrum_ptr,
|
||||
zerosXBuf,
|
||||
dfaNoisySum,
|
||||
echoEst32);
|
||||
|
||||
// Calculate stepsize
|
||||
mu = WebRtcAecm_CalcStepSize(aecm);
|
||||
|
||||
// Update counters
|
||||
aecm->totCount++;
|
||||
|
||||
// This is the channel estimation algorithm.
|
||||
// It is base on NLMS but has a variable step length,
|
||||
// which was calculated above.
|
||||
WebRtcAecm_UpdateChannel(aecm,
|
||||
far_spectrum_ptr,
|
||||
zerosXBuf,
|
||||
dfaNoisy,
|
||||
mu,
|
||||
echoEst32);
|
||||
supGain = WebRtcAecm_CalcSuppressionGain(aecm);
|
||||
|
||||
|
||||
// Calculate Wiener filter hnl[]
|
||||
for (i = 0; i < PART_LEN1; i++)
|
||||
{
|
||||
// Far end signal through channel estimate in Q8
|
||||
// How much can we shift right to preserve resolution
|
||||
tmp32no1 = echoEst32[i] - aecm->echoFilt[i];
|
||||
aecm->echoFilt[i] += (tmp32no1 * 50) >> 8;
|
||||
|
||||
zeros32 = WebRtcSpl_NormW32(aecm->echoFilt[i]) + 1;
|
||||
zeros16 = WebRtcSpl_NormW16(supGain) + 1;
|
||||
if (zeros32 + zeros16 > 16)
|
||||
{
|
||||
// Multiplication is safe
|
||||
// Result in
|
||||
// Q(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN+
|
||||
// aecm->xfaQDomainBuf[diff])
|
||||
echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i],
|
||||
(uint16_t)supGain);
|
||||
resolutionDiff = 14 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN;
|
||||
resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
|
||||
} else
|
||||
{
|
||||
tmp16no1 = 17 - zeros32 - zeros16;
|
||||
resolutionDiff = 14 + tmp16no1 - RESOLUTION_CHANNEL16 -
|
||||
RESOLUTION_SUPGAIN;
|
||||
resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf);
|
||||
if (zeros32 > tmp16no1)
|
||||
{
|
||||
echoEst32Gained = WEBRTC_SPL_UMUL_32_16((uint32_t)aecm->echoFilt[i],
|
||||
supGain >> tmp16no1);
|
||||
} else
|
||||
{
|
||||
// Result in Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16)
|
||||
echoEst32Gained = (aecm->echoFilt[i] >> tmp16no1) * supGain;
|
||||
}
|
||||
}
|
||||
|
||||
zeros16 = WebRtcSpl_NormW16(aecm->nearFilt[i]);
|
||||
assert(zeros16 >= 0); // |zeros16| is a norm, hence non-negative.
|
||||
dfa_clean_q_domain_diff = aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld;
|
||||
if (zeros16 < dfa_clean_q_domain_diff && aecm->nearFilt[i]) {
|
||||
tmp16no1 = aecm->nearFilt[i] << zeros16;
|
||||
qDomainDiff = zeros16 - dfa_clean_q_domain_diff;
|
||||
tmp16no2 = ptrDfaClean[i] >> -qDomainDiff;
|
||||
} else {
|
||||
tmp16no1 = dfa_clean_q_domain_diff < 0
|
||||
? aecm->nearFilt[i] >> -dfa_clean_q_domain_diff
|
||||
: aecm->nearFilt[i] << dfa_clean_q_domain_diff;
|
||||
qDomainDiff = 0;
|
||||
tmp16no2 = ptrDfaClean[i];
|
||||
}
|
||||
tmp32no1 = (int32_t)(tmp16no2 - tmp16no1);
|
||||
tmp16no2 = (int16_t)(tmp32no1 >> 4);
|
||||
tmp16no2 += tmp16no1;
|
||||
zeros16 = WebRtcSpl_NormW16(tmp16no2);
|
||||
if ((tmp16no2) & (-qDomainDiff > zeros16)) {
|
||||
aecm->nearFilt[i] = WEBRTC_SPL_WORD16_MAX;
|
||||
} else {
|
||||
aecm->nearFilt[i] = qDomainDiff < 0 ? tmp16no2 << -qDomainDiff
|
||||
: tmp16no2 >> qDomainDiff;
|
||||
}
|
||||
|
||||
// Wiener filter coefficients, resulting hnl in Q14
|
||||
if (echoEst32Gained == 0)
|
||||
{
|
||||
hnl[i] = ONE_Q14;
|
||||
} else if (aecm->nearFilt[i] == 0)
|
||||
{
|
||||
hnl[i] = 0;
|
||||
} else
|
||||
{
|
||||
// Multiply the suppression gain
|
||||
// Rounding
|
||||
echoEst32Gained += (uint32_t)(aecm->nearFilt[i] >> 1);
|
||||
tmpU32 = WebRtcSpl_DivU32U16(echoEst32Gained,
|
||||
(uint16_t)aecm->nearFilt[i]);
|
||||
|
||||
// Current resolution is
|
||||
// Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN- max(0,17-zeros16- zeros32))
|
||||
// Make sure we are in Q14
|
||||
tmp32no1 = (int32_t)WEBRTC_SPL_SHIFT_W32(tmpU32, resolutionDiff);
|
||||
if (tmp32no1 > ONE_Q14)
|
||||
{
|
||||
hnl[i] = 0;
|
||||
} else if (tmp32no1 < 0)
|
||||
{
|
||||
hnl[i] = ONE_Q14;
|
||||
} else
|
||||
{
|
||||
// 1-echoEst/dfa
|
||||
hnl[i] = ONE_Q14 - (int16_t)tmp32no1;
|
||||
if (hnl[i] < 0)
|
||||
{
|
||||
hnl[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hnl[i])
|
||||
{
|
||||
numPosCoef++;
|
||||
}
|
||||
}
|
||||
// Only in wideband. Prevent the gain in upper band from being larger than
|
||||
// in lower band.
|
||||
if (aecm->mult == 2)
|
||||
{
|
||||
// TODO(bjornv): Investigate if the scaling of hnl[i] below can cause
|
||||
// speech distortion in double-talk.
|
||||
for (i = 0; i < PART_LEN1; i++)
|
||||
{
|
||||
hnl[i] = (int16_t)((hnl[i] * hnl[i]) >> 14);
|
||||
}
|
||||
|
||||
for (i = kMinPrefBand; i <= kMaxPrefBand; i++)
|
||||
{
|
||||
avgHnl32 += (int32_t)hnl[i];
|
||||
}
|
||||
assert(kMaxPrefBand - kMinPrefBand + 1 > 0);
|
||||
avgHnl32 /= (kMaxPrefBand - kMinPrefBand + 1);
|
||||
|
||||
for (i = kMaxPrefBand; i < PART_LEN1; i++)
|
||||
{
|
||||
if (hnl[i] > (int16_t)avgHnl32)
|
||||
{
|
||||
hnl[i] = (int16_t)avgHnl32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate NLP gain, result is in Q14
|
||||
if (aecm->nlpFlag)
|
||||
{
|
||||
for (i = 0; i < PART_LEN1; i++)
|
||||
{
|
||||
// Truncate values close to zero and one.
|
||||
if (hnl[i] > NLP_COMP_HIGH)
|
||||
{
|
||||
hnl[i] = ONE_Q14;
|
||||
} else if (hnl[i] < NLP_COMP_LOW)
|
||||
{
|
||||
hnl[i] = 0;
|
||||
}
|
||||
|
||||
// Remove outliers
|
||||
if (numPosCoef < 3)
|
||||
{
|
||||
nlpGain = 0;
|
||||
} else
|
||||
{
|
||||
nlpGain = ONE_Q14;
|
||||
}
|
||||
|
||||
// NLP
|
||||
if ((hnl[i] == ONE_Q14) && (nlpGain == ONE_Q14))
|
||||
{
|
||||
hnl[i] = ONE_Q14;
|
||||
} else
|
||||
{
|
||||
hnl[i] = (int16_t)((hnl[i] * nlpGain) >> 14);
|
||||
}
|
||||
|
||||
// multiply with Wiener coefficients
|
||||
efw[i].real = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real,
|
||||
hnl[i], 14));
|
||||
efw[i].imag = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag,
|
||||
hnl[i], 14));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// multiply with Wiener coefficients
|
||||
for (i = 0; i < PART_LEN1; i++)
|
||||
{
|
||||
efw[i].real = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real,
|
||||
hnl[i], 14));
|
||||
efw[i].imag = (int16_t)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag,
|
||||
hnl[i], 14));
|
||||
}
|
||||
}
|
||||
|
||||
if (aecm->cngMode == AecmTrue)
|
||||
{
|
||||
ComfortNoise(aecm, ptrDfaClean, efw, hnl);
|
||||
}
|
||||
|
||||
InverseFFTAndWindow(aecm, fft, efw, output, nearendClean);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ComfortNoise(AecmCore* aecm,
|
||||
const uint16_t* dfa,
|
||||
ComplexInt16* out,
|
||||
const int16_t* lambda) {
|
||||
int16_t i;
|
||||
int16_t tmp16;
|
||||
int32_t tmp32;
|
||||
|
||||
int16_t randW16[PART_LEN];
|
||||
int16_t uReal[PART_LEN1];
|
||||
int16_t uImag[PART_LEN1];
|
||||
int32_t outLShift32;
|
||||
int16_t noiseRShift16[PART_LEN1];
|
||||
|
||||
int16_t shiftFromNearToNoise = kNoiseEstQDomain - aecm->dfaCleanQDomain;
|
||||
int16_t minTrackShift;
|
||||
|
||||
assert(shiftFromNearToNoise >= 0);
|
||||
assert(shiftFromNearToNoise < 16);
|
||||
|
||||
if (aecm->noiseEstCtr < 100)
|
||||
{
|
||||
// Track the minimum more quickly initially.
|
||||
aecm->noiseEstCtr++;
|
||||
minTrackShift = 6;
|
||||
} else
|
||||
{
|
||||
minTrackShift = 9;
|
||||
}
|
||||
|
||||
// Estimate noise power.
|
||||
for (i = 0; i < PART_LEN1; i++)
|
||||
{
|
||||
// Shift to the noise domain.
|
||||
tmp32 = (int32_t)dfa[i];
|
||||
outLShift32 = tmp32 << shiftFromNearToNoise;
|
||||
|
||||
if (outLShift32 < aecm->noiseEst[i])
|
||||
{
|
||||
// Reset "too low" counter
|
||||
aecm->noiseEstTooLowCtr[i] = 0;
|
||||
// Track the minimum.
|
||||
if (aecm->noiseEst[i] < (1 << minTrackShift))
|
||||
{
|
||||
// For small values, decrease noiseEst[i] every
|
||||
// |kNoiseEstIncCount| block. The regular approach below can not
|
||||
// go further down due to truncation.
|
||||
aecm->noiseEstTooHighCtr[i]++;
|
||||
if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount)
|
||||
{
|
||||
aecm->noiseEst[i]--;
|
||||
aecm->noiseEstTooHighCtr[i] = 0; // Reset the counter
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
aecm->noiseEst[i] -= ((aecm->noiseEst[i] - outLShift32)
|
||||
>> minTrackShift);
|
||||
}
|
||||
} else
|
||||
{
|
||||
// Reset "too high" counter
|
||||
aecm->noiseEstTooHighCtr[i] = 0;
|
||||
// Ramp slowly upwards until we hit the minimum again.
|
||||
if ((aecm->noiseEst[i] >> 19) > 0)
|
||||
{
|
||||
// Avoid overflow.
|
||||
// Multiplication with 2049 will cause wrap around. Scale
|
||||
// down first and then multiply
|
||||
aecm->noiseEst[i] >>= 11;
|
||||
aecm->noiseEst[i] *= 2049;
|
||||
}
|
||||
else if ((aecm->noiseEst[i] >> 11) > 0)
|
||||
{
|
||||
// Large enough for relative increase
|
||||
aecm->noiseEst[i] *= 2049;
|
||||
aecm->noiseEst[i] >>= 11;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make incremental increases based on size every
|
||||
// |kNoiseEstIncCount| block
|
||||
aecm->noiseEstTooLowCtr[i]++;
|
||||
if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount)
|
||||
{
|
||||
aecm->noiseEst[i] += (aecm->noiseEst[i] >> 9) + 1;
|
||||
aecm->noiseEstTooLowCtr[i] = 0; // Reset counter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < PART_LEN1; i++)
|
||||
{
|
||||
tmp32 = aecm->noiseEst[i] >> shiftFromNearToNoise;
|
||||
if (tmp32 > 32767)
|
||||
{
|
||||
tmp32 = 32767;
|
||||
aecm->noiseEst[i] = tmp32 << shiftFromNearToNoise;
|
||||
}
|
||||
noiseRShift16[i] = (int16_t)tmp32;
|
||||
|
||||
tmp16 = ONE_Q14 - lambda[i];
|
||||
noiseRShift16[i] = (int16_t)((tmp16 * noiseRShift16[i]) >> 14);
|
||||
}
|
||||
|
||||
// Generate a uniform random array on [0 2^15-1].
|
||||
WebRtcSpl_RandUArray(randW16, PART_LEN, &aecm->seed);
|
||||
|
||||
// Generate noise according to estimated energy.
|
||||
uReal[0] = 0; // Reject LF noise.
|
||||
uImag[0] = 0;
|
||||
for (i = 1; i < PART_LEN1; i++)
|
||||
{
|
||||
// Get a random index for the cos and sin tables over [0 359].
|
||||
tmp16 = (int16_t)((359 * randW16[i - 1]) >> 15);
|
||||
|
||||
// Tables are in Q13.
|
||||
uReal[i] = (int16_t)((noiseRShift16[i] * WebRtcAecm_kCosTable[tmp16]) >>
|
||||
13);
|
||||
uImag[i] = (int16_t)((-noiseRShift16[i] * WebRtcAecm_kSinTable[tmp16]) >>
|
||||
13);
|
||||
}
|
||||
uImag[PART_LEN] = 0;
|
||||
|
||||
for (i = 0; i < PART_LEN1; i++)
|
||||
{
|
||||
out[i].real = WebRtcSpl_AddSatW16(out[i].real, uReal[i]);
|
||||
out[i].imag = WebRtcSpl_AddSatW16(out[i].imag, uImag[i]);
|
||||
}
|
||||
}
|
||||
|
||||
1566
webrtc/modules/audio_processing/aecm/aecm_core_mips.c
Normal file
1566
webrtc/modules/audio_processing/aecm/aecm_core_mips.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
* 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
|
||||
@@ -7,308 +7,206 @@
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM_NEON)
|
||||
|
||||
#include "aecm_core.h"
|
||||
#include "webrtc/modules/audio_processing/aecm/aecm_core.h"
|
||||
|
||||
#include <arm_neon.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/real_fft.h"
|
||||
|
||||
// TODO(kma): Re-write the corresponding assembly file, the offset
|
||||
// generating script and makefile, to replace these C functions.
|
||||
|
||||
// Square root of Hanning window in Q14.
|
||||
static const WebRtc_Word16 kSqrtHanningReversed[] __attribute__ ((aligned (8))) = {
|
||||
16384, 16373, 16354, 16325,
|
||||
16286, 16237, 16179, 16111,
|
||||
16034, 15947, 15851, 15746,
|
||||
15631, 15506, 15373, 15231,
|
||||
15079, 14918, 14749, 14571,
|
||||
14384, 14189, 13985, 13773,
|
||||
13553, 13325, 13089, 12845,
|
||||
12594, 12335, 12068, 11795,
|
||||
11514, 11227, 10933, 10633,
|
||||
10326, 10013, 9695, 9370,
|
||||
9040, 8705, 8364, 8019,
|
||||
7668, 7313, 6954, 6591,
|
||||
6224, 5853, 5478, 5101,
|
||||
4720, 4337, 3951, 3562,
|
||||
3172, 2780, 2386, 1990,
|
||||
1594, 1196, 798, 399
|
||||
const ALIGN8_BEG int16_t WebRtcAecm_kSqrtHanning[] ALIGN8_END = {
|
||||
0,
|
||||
399, 798, 1196, 1594, 1990, 2386, 2780, 3172,
|
||||
3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224,
|
||||
6591, 6954, 7313, 7668, 8019, 8364, 8705, 9040,
|
||||
9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514,
|
||||
11795, 12068, 12335, 12594, 12845, 13089, 13325, 13553,
|
||||
13773, 13985, 14189, 14384, 14571, 14749, 14918, 15079,
|
||||
15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034,
|
||||
16111, 16179, 16237, 16286, 16325, 16354, 16373, 16384
|
||||
};
|
||||
|
||||
void WebRtcAecm_WindowAndFFT(WebRtc_Word16* fft,
|
||||
const WebRtc_Word16* time_signal,
|
||||
complex16_t* freq_signal,
|
||||
int time_signal_scaling)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
int16x4_t tmp16x4_scaling = vdup_n_s16(time_signal_scaling);
|
||||
__asm__("vmov.i16 d21, #0" ::: "d21");
|
||||
|
||||
for(i = 0, j = 0; i < PART_LEN; i += 4, j += 8)
|
||||
{
|
||||
int16x4_t tmp16x4_0;
|
||||
int16x4_t tmp16x4_1;
|
||||
int32x4_t tmp32x4_0;
|
||||
|
||||
/* Window near end */
|
||||
// fft[j] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT((time_signal[i]
|
||||
// << time_signal_scaling), WebRtcAecm_kSqrtHanning[i], 14);
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_0) : "r"(&time_signal[i]));
|
||||
tmp16x4_0 = vshl_s16(tmp16x4_0, tmp16x4_scaling);
|
||||
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_1) : "r"(&WebRtcAecm_kSqrtHanning[i]));
|
||||
tmp32x4_0 = vmull_s16(tmp16x4_0, tmp16x4_1);
|
||||
|
||||
__asm__("vshrn.i32 d20, %q0, #14" : : "w"(tmp32x4_0) : "d20");
|
||||
__asm__("vst2.16 {d20, d21}, [%0, :128]" : : "r"(&fft[j]) : "q10");
|
||||
|
||||
// fft[PART_LEN2 + j] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(
|
||||
// (time_signal[PART_LEN + i] << time_signal_scaling),
|
||||
// WebRtcAecm_kSqrtHanning[PART_LEN - i], 14);
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_0) : "r"(&time_signal[i + PART_LEN]));
|
||||
tmp16x4_0 = vshl_s16(tmp16x4_0, tmp16x4_scaling);
|
||||
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_1) : "r"(&kSqrtHanningReversed[i]));
|
||||
tmp32x4_0 = vmull_s16(tmp16x4_0, tmp16x4_1);
|
||||
|
||||
__asm__("vshrn.i32 d20, %q0, #14" : : "w"(tmp32x4_0) : "d20");
|
||||
__asm__("vst2.16 {d20, d21}, [%0, :128]" : : "r"(&fft[PART_LEN2 + j]) : "q10");
|
||||
}
|
||||
|
||||
WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT);
|
||||
WebRtcSpl_ComplexFFT(fft, PART_LEN_SHIFT, 1);
|
||||
|
||||
// Take only the first PART_LEN2 samples, and switch the sign of the imaginary part.
|
||||
for(i = 0, j = 0; j < PART_LEN2; i += 8, j += 16)
|
||||
{
|
||||
__asm__("vld2.16 {d20, d21, d22, d23}, [%0, :256]" : : "r"(&fft[j]) : "q10", "q11");
|
||||
__asm__("vneg.s16 d22, d22" : : : "q10");
|
||||
__asm__("vneg.s16 d23, d23" : : : "q11");
|
||||
__asm__("vst2.16 {d20, d21, d22, d23}, [%0, :256]" : :
|
||||
"r"(&freq_signal[i].real): "q10", "q11");
|
||||
}
|
||||
static inline void AddLanes(uint32_t* ptr, uint32x4_t v) {
|
||||
#if defined(WEBRTC_ARCH_ARM64)
|
||||
*(ptr) = vaddvq_u32(v);
|
||||
#else
|
||||
uint32x2_t tmp_v;
|
||||
tmp_v = vadd_u32(vget_low_u32(v), vget_high_u32(v));
|
||||
tmp_v = vpadd_u32(tmp_v, tmp_v);
|
||||
*(ptr) = vget_lane_u32(tmp_v, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void WebRtcAecm_InverseFFTAndWindow(AecmCore_t* aecm,
|
||||
WebRtc_Word16* fft,
|
||||
complex16_t* efw,
|
||||
WebRtc_Word16* output,
|
||||
const WebRtc_Word16* nearendClean)
|
||||
{
|
||||
int i, j, outCFFT;
|
||||
WebRtc_Word32 tmp32no1;
|
||||
void WebRtcAecm_CalcLinearEnergiesNeon(AecmCore* aecm,
|
||||
const uint16_t* far_spectrum,
|
||||
int32_t* echo_est,
|
||||
uint32_t* far_energy,
|
||||
uint32_t* echo_energy_adapt,
|
||||
uint32_t* echo_energy_stored) {
|
||||
int16_t* start_stored_p = aecm->channelStored;
|
||||
int16_t* start_adapt_p = aecm->channelAdapt16;
|
||||
int32_t* echo_est_p = echo_est;
|
||||
const int16_t* end_stored_p = aecm->channelStored + PART_LEN;
|
||||
const uint16_t* far_spectrum_p = far_spectrum;
|
||||
int16x8_t store_v, adapt_v;
|
||||
uint16x8_t spectrum_v;
|
||||
uint32x4_t echo_est_v_low, echo_est_v_high;
|
||||
uint32x4_t far_energy_v, echo_stored_v, echo_adapt_v;
|
||||
|
||||
// Synthesis
|
||||
for(i = 0, j = 0; i < PART_LEN; i += 4, j += 8)
|
||||
{
|
||||
// We overwrite two more elements in fft[], but it's ok.
|
||||
__asm__("vld2.16 {d20, d21}, [%0, :128]" : : "r"(&(efw[i].real)) : "q10");
|
||||
__asm__("vmov q11, q10" : : : "q10", "q11");
|
||||
far_energy_v = vdupq_n_u32(0);
|
||||
echo_adapt_v = vdupq_n_u32(0);
|
||||
echo_stored_v = vdupq_n_u32(0);
|
||||
|
||||
__asm__("vneg.s16 d23, d23" : : : "q11");
|
||||
__asm__("vst2.16 {d22, d23}, [%0, :128]" : : "r"(&fft[j]): "q11");
|
||||
// Get energy for the delayed far end signal and estimated
|
||||
// echo using both stored and adapted channels.
|
||||
// The C code:
|
||||
// for (i = 0; i < PART_LEN1; i++) {
|
||||
// echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
|
||||
// far_spectrum[i]);
|
||||
// (*far_energy) += (uint32_t)(far_spectrum[i]);
|
||||
// *echo_energy_adapt += aecm->channelAdapt16[i] * far_spectrum[i];
|
||||
// (*echo_energy_stored) += (uint32_t)echo_est[i];
|
||||
// }
|
||||
while (start_stored_p < end_stored_p) {
|
||||
spectrum_v = vld1q_u16(far_spectrum_p);
|
||||
adapt_v = vld1q_s16(start_adapt_p);
|
||||
store_v = vld1q_s16(start_stored_p);
|
||||
|
||||
__asm__("vrev64.16 q10, q10" : : : "q10");
|
||||
__asm__("vst2.16 {d20, d21}, [%0]" : : "r"(&fft[PART_LEN4 - j - 6]): "q10");
|
||||
}
|
||||
far_energy_v = vaddw_u16(far_energy_v, vget_low_u16(spectrum_v));
|
||||
far_energy_v = vaddw_u16(far_energy_v, vget_high_u16(spectrum_v));
|
||||
|
||||
fft[PART_LEN2] = efw[PART_LEN].real;
|
||||
fft[PART_LEN2 + 1] = -efw[PART_LEN].imag;
|
||||
echo_est_v_low = vmull_u16(vreinterpret_u16_s16(vget_low_s16(store_v)),
|
||||
vget_low_u16(spectrum_v));
|
||||
echo_est_v_high = vmull_u16(vreinterpret_u16_s16(vget_high_s16(store_v)),
|
||||
vget_high_u16(spectrum_v));
|
||||
vst1q_s32(echo_est_p, vreinterpretq_s32_u32(echo_est_v_low));
|
||||
vst1q_s32(echo_est_p + 4, vreinterpretq_s32_u32(echo_est_v_high));
|
||||
|
||||
// Inverse FFT, result should be scaled with outCFFT.
|
||||
WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT);
|
||||
outCFFT = WebRtcSpl_ComplexIFFT(fft, PART_LEN_SHIFT, 1);
|
||||
echo_stored_v = vaddq_u32(echo_est_v_low, echo_stored_v);
|
||||
echo_stored_v = vaddq_u32(echo_est_v_high, echo_stored_v);
|
||||
|
||||
// Take only the real values and scale with outCFFT.
|
||||
for (i = 0, j = 0; i < PART_LEN2; i += 8, j+= 16)
|
||||
{
|
||||
__asm__("vld2.16 {d20, d21, d22, d23}, [%0, :256]" : : "r"(&fft[j]) : "q10", "q11");
|
||||
__asm__("vst1.16 {d20, d21}, [%0, :128]" : : "r"(&fft[i]): "q10");
|
||||
}
|
||||
echo_adapt_v = vmlal_u16(echo_adapt_v,
|
||||
vreinterpret_u16_s16(vget_low_s16(adapt_v)),
|
||||
vget_low_u16(spectrum_v));
|
||||
echo_adapt_v = vmlal_u16(echo_adapt_v,
|
||||
vreinterpret_u16_s16(vget_high_s16(adapt_v)),
|
||||
vget_high_u16(spectrum_v));
|
||||
|
||||
int32x4_t tmp32x4_2;
|
||||
__asm__("vdup.32 %q0, %1" : "=w"(tmp32x4_2) : "r"((WebRtc_Word32)
|
||||
(outCFFT - aecm->dfaCleanQDomain)));
|
||||
for (i = 0; i < PART_LEN; i += 4)
|
||||
{
|
||||
int16x4_t tmp16x4_0;
|
||||
int16x4_t tmp16x4_1;
|
||||
int32x4_t tmp32x4_0;
|
||||
int32x4_t tmp32x4_1;
|
||||
start_stored_p += 8;
|
||||
start_adapt_p += 8;
|
||||
far_spectrum_p += 8;
|
||||
echo_est_p += 8;
|
||||
}
|
||||
|
||||
// fft[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
|
||||
// fft[i], WebRtcAecm_kSqrtHanning[i], 14);
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_0) : "r"(&fft[i]));
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_1) : "r"(&WebRtcAecm_kSqrtHanning[i]));
|
||||
__asm__("vmull.s16 %q0, %P1, %P2" : "=w"(tmp32x4_0) : "w"(tmp16x4_0), "w"(tmp16x4_1));
|
||||
__asm__("vrshr.s32 %q0, %q1, #14" : "=w"(tmp32x4_0) : "0"(tmp32x4_0));
|
||||
AddLanes(far_energy, far_energy_v);
|
||||
AddLanes(echo_energy_stored, echo_stored_v);
|
||||
AddLanes(echo_energy_adapt, echo_adapt_v);
|
||||
|
||||
// tmp32no1 = WEBRTC_SPL_SHIFT_W32((WebRtc_Word32)fft[i],
|
||||
// outCFFT - aecm->dfaCleanQDomain);
|
||||
__asm__("vshl.s32 %q0, %q1, %q2" : "=w"(tmp32x4_0) : "0"(tmp32x4_0), "w"(tmp32x4_2));
|
||||
|
||||
// fft[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
|
||||
// tmp32no1 + outBuf[i], WEBRTC_SPL_WORD16_MIN);
|
||||
// output[i] = fft[i];
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_0) : "r"(&aecm->outBuf[i]));
|
||||
__asm__("vmovl.s16 %q0, %P1" : "=w"(tmp32x4_1) : "w"(tmp16x4_0));
|
||||
__asm__("vadd.i32 %q0, %q1" : : "w"(tmp32x4_0), "w"(tmp32x4_1));
|
||||
__asm__("vqshrn.s32 %P0, %q1, #0" : "=w"(tmp16x4_0) : "w"(tmp32x4_0));
|
||||
__asm__("vst1.16 %P0, [%1, :64]" : : "w"(tmp16x4_0), "r"(&fft[i]));
|
||||
__asm__("vst1.16 %P0, [%1, :64]" : : "w"(tmp16x4_0), "r"(&output[i]));
|
||||
|
||||
// tmp32no1 = WEBRTC_SPL_MUL_16_16_RSFT(
|
||||
// fft[PART_LEN + i], WebRtcAecm_kSqrtHanning[PART_LEN - i], 14);
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_0) : "r"(&fft[PART_LEN + i]));
|
||||
__asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_1) : "r"(&kSqrtHanningReversed[i]));
|
||||
__asm__("vmull.s16 %q0, %P1, %P2" : "=w"(tmp32x4_0) : "w"(tmp16x4_0), "w"(tmp16x4_1));
|
||||
__asm__("vshr.s32 %q0, %q1, #14" : "=w"(tmp32x4_0) : "0"(tmp32x4_0));
|
||||
|
||||
// tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, outCFFT - aecm->dfaCleanQDomain);
|
||||
__asm__("vshl.s32 %q0, %q1, %q2" : "=w"(tmp32x4_0) : "0"(tmp32x4_0), "w"(tmp32x4_2));
|
||||
// outBuf[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(
|
||||
// WEBRTC_SPL_WORD16_MAX, tmp32no1, WEBRTC_SPL_WORD16_MIN);
|
||||
__asm__("vqshrn.s32 %P0, %q1, #0" : "=w"(tmp16x4_0) : "w"(tmp32x4_0));
|
||||
__asm__("vst1.16 %P0, [%1, :64]" : : "w"(tmp16x4_0), "r"(&aecm->outBuf[i]));
|
||||
}
|
||||
|
||||
// Copy the current block to the old position (outBuf is shifted elsewhere).
|
||||
for (i = 0; i < PART_LEN; i += 16)
|
||||
{
|
||||
__asm__("vld1.16 {d20, d21, d22, d23}, [%0, :256]" : :
|
||||
"r"(&aecm->xBuf[i + PART_LEN]) : "q10");
|
||||
__asm__("vst1.16 {d20, d21, d22, d23}, [%0, :256]" : : "r"(&aecm->xBuf[i]): "q10");
|
||||
}
|
||||
for (i = 0; i < PART_LEN; i += 16)
|
||||
{
|
||||
__asm__("vld1.16 {d20, d21, d22, d23}, [%0, :256]" : :
|
||||
"r"(&aecm->dBufNoisy[i + PART_LEN]) : "q10");
|
||||
__asm__("vst1.16 {d20, d21, d22, d23}, [%0, :256]" : :
|
||||
"r"(&aecm->dBufNoisy[i]): "q10");
|
||||
}
|
||||
if (nearendClean != NULL) {
|
||||
for (i = 0; i < PART_LEN; i += 16)
|
||||
{
|
||||
__asm__("vld1.16 {d20, d21, d22, d23}, [%0, :256]" : :
|
||||
"r"(&aecm->dBufClean[i + PART_LEN]) : "q10");
|
||||
__asm__("vst1.16 {d20, d21, d22, d23}, [%0, :256]" : :
|
||||
"r"(&aecm->dBufClean[i]): "q10");
|
||||
}
|
||||
}
|
||||
echo_est[PART_LEN] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[PART_LEN],
|
||||
far_spectrum[PART_LEN]);
|
||||
*echo_energy_stored += (uint32_t)echo_est[PART_LEN];
|
||||
*far_energy += (uint32_t)far_spectrum[PART_LEN];
|
||||
*echo_energy_adapt += aecm->channelAdapt16[PART_LEN] * far_spectrum[PART_LEN];
|
||||
}
|
||||
|
||||
void WebRtcAecm_CalcLinearEnergies(AecmCore_t* aecm,
|
||||
const WebRtc_UWord16* far_spectrum,
|
||||
WebRtc_Word32* echo_est,
|
||||
WebRtc_UWord32* far_energy,
|
||||
WebRtc_UWord32* echo_energy_adapt,
|
||||
WebRtc_UWord32* echo_energy_stored)
|
||||
{
|
||||
int i;
|
||||
void WebRtcAecm_StoreAdaptiveChannelNeon(AecmCore* aecm,
|
||||
const uint16_t* far_spectrum,
|
||||
int32_t* echo_est) {
|
||||
assert((uintptr_t)echo_est % 32 == 0);
|
||||
assert((uintptr_t)(aecm->channelStored) % 16 == 0);
|
||||
assert((uintptr_t)(aecm->channelAdapt16) % 16 == 0);
|
||||
|
||||
register WebRtc_UWord32 far_energy_r;
|
||||
register WebRtc_UWord32 echo_energy_stored_r;
|
||||
register WebRtc_UWord32 echo_energy_adapt_r;
|
||||
uint32x4_t tmp32x4_0;
|
||||
// This is C code of following optimized code.
|
||||
// During startup we store the channel every block.
|
||||
// memcpy(aecm->channelStored,
|
||||
// aecm->channelAdapt16,
|
||||
// sizeof(int16_t) * PART_LEN1);
|
||||
// Recalculate echo estimate
|
||||
// for (i = 0; i < PART_LEN; i += 4) {
|
||||
// echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
|
||||
// far_spectrum[i]);
|
||||
// echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1],
|
||||
// far_spectrum[i + 1]);
|
||||
// echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2],
|
||||
// far_spectrum[i + 2]);
|
||||
// echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3],
|
||||
// far_spectrum[i + 3]);
|
||||
// }
|
||||
// echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i],
|
||||
// far_spectrum[i]);
|
||||
const uint16_t* far_spectrum_p = far_spectrum;
|
||||
int16_t* start_adapt_p = aecm->channelAdapt16;
|
||||
int16_t* start_stored_p = aecm->channelStored;
|
||||
const int16_t* end_stored_p = aecm->channelStored + PART_LEN;
|
||||
int32_t* echo_est_p = echo_est;
|
||||
|
||||
__asm__("vmov.i32 q14, #0" : : : "q14"); // far_energy
|
||||
__asm__("vmov.i32 q8, #0" : : : "q8"); // echo_energy_stored
|
||||
__asm__("vmov.i32 q9, #0" : : : "q9"); // echo_energy_adapt
|
||||
uint16x8_t far_spectrum_v;
|
||||
int16x8_t adapt_v;
|
||||
uint32x4_t echo_est_v_low, echo_est_v_high;
|
||||
|
||||
for(i = 0; i < PART_LEN -7; i += 8)
|
||||
{
|
||||
// far_energy += (WebRtc_UWord32)(far_spectrum[i]);
|
||||
__asm__("vld1.16 {d26, d27}, [%0]" : : "r"(&far_spectrum[i]) : "q13");
|
||||
__asm__("vaddw.u16 q14, q14, d26" : : : "q14", "q13");
|
||||
__asm__("vaddw.u16 q14, q14, d27" : : : "q14", "q13");
|
||||
while (start_stored_p < end_stored_p) {
|
||||
far_spectrum_v = vld1q_u16(far_spectrum_p);
|
||||
adapt_v = vld1q_s16(start_adapt_p);
|
||||
|
||||
// Get estimated echo energies for adaptive channel and stored channel.
|
||||
// echoEst[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
|
||||
__asm__("vld1.16 {d24, d25}, [%0, :128]" : : "r"(&aecm->channelStored[i]) : "q12");
|
||||
__asm__("vmull.u16 q10, d26, d24" : : : "q12", "q13", "q10");
|
||||
__asm__("vmull.u16 q11, d27, d25" : : : "q12", "q13", "q11");
|
||||
__asm__("vst1.32 {d20, d21, d22, d23}, [%0, :256]" : : "r"(&echo_est[i]):
|
||||
"q10", "q11");
|
||||
vst1q_s16(start_stored_p, adapt_v);
|
||||
|
||||
// echo_energy_stored += (WebRtc_UWord32)echoEst[i];
|
||||
__asm__("vadd.u32 q8, q10" : : : "q10", "q8");
|
||||
__asm__("vadd.u32 q8, q11" : : : "q11", "q8");
|
||||
echo_est_v_low = vmull_u16(vget_low_u16(far_spectrum_v),
|
||||
vget_low_u16(vreinterpretq_u16_s16(adapt_v)));
|
||||
echo_est_v_high = vmull_u16(vget_high_u16(far_spectrum_v),
|
||||
vget_high_u16(vreinterpretq_u16_s16(adapt_v)));
|
||||
|
||||
// echo_energy_adapt += WEBRTC_SPL_UMUL_16_16(
|
||||
// aecm->channelAdapt16[i], far_spectrum[i]);
|
||||
__asm__("vld1.16 {d24, d25}, [%0, :128]" : : "r"(&aecm->channelAdapt16[i]) : "q12");
|
||||
__asm__("vmull.u16 q10, d26, d24" : : : "q12", "q13", "q10");
|
||||
__asm__("vmull.u16 q11, d27, d25" : : : "q12", "q13", "q11");
|
||||
__asm__("vadd.u32 q9, q10" : : : "q9", "q15");
|
||||
__asm__("vadd.u32 q9, q11" : : : "q9", "q11");
|
||||
}
|
||||
vst1q_s32(echo_est_p, vreinterpretq_s32_u32(echo_est_v_low));
|
||||
vst1q_s32(echo_est_p + 4, vreinterpretq_s32_u32(echo_est_v_high));
|
||||
|
||||
__asm__("vadd.u32 d28, d29" : : : "q14");
|
||||
__asm__("vpadd.u32 d28, d28" : : : "q14");
|
||||
__asm__("vmov.32 %0, d28[0]" : "=r"(far_energy_r): : "q14");
|
||||
|
||||
__asm__("vadd.u32 d18, d19" : : : "q9");
|
||||
__asm__("vpadd.u32 d18, d18" : : : "q9");
|
||||
__asm__("vmov.32 %0, d18[0]" : "=r"(echo_energy_adapt_r): : "q9");
|
||||
|
||||
__asm__("vadd.u32 d16, d17" : : : "q8");
|
||||
__asm__("vpadd.u32 d16, d16" : : : "q8");
|
||||
__asm__("vmov.32 %0, d16[0]" : "=r"(echo_energy_stored_r): : "q8");
|
||||
|
||||
// Get estimated echo energies for adaptive channel and stored channel.
|
||||
echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
|
||||
*echo_energy_stored = echo_energy_stored_r + (WebRtc_UWord32)echo_est[i];
|
||||
*far_energy = far_energy_r + (WebRtc_UWord32)(far_spectrum[i]);
|
||||
*echo_energy_adapt = echo_energy_adapt_r + WEBRTC_SPL_UMUL_16_16(
|
||||
aecm->channelAdapt16[i], far_spectrum[i]);
|
||||
far_spectrum_p += 8;
|
||||
start_adapt_p += 8;
|
||||
start_stored_p += 8;
|
||||
echo_est_p += 8;
|
||||
}
|
||||
aecm->channelStored[PART_LEN] = aecm->channelAdapt16[PART_LEN];
|
||||
echo_est[PART_LEN] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[PART_LEN],
|
||||
far_spectrum[PART_LEN]);
|
||||
}
|
||||
|
||||
void WebRtcAecm_StoreAdaptiveChannel(AecmCore_t* aecm,
|
||||
const WebRtc_UWord16* far_spectrum,
|
||||
WebRtc_Word32* echo_est)
|
||||
{
|
||||
int i;
|
||||
void WebRtcAecm_ResetAdaptiveChannelNeon(AecmCore* aecm) {
|
||||
assert((uintptr_t)(aecm->channelStored) % 16 == 0);
|
||||
assert((uintptr_t)(aecm->channelAdapt16) % 16 == 0);
|
||||
assert((uintptr_t)(aecm->channelAdapt32) % 32 == 0);
|
||||
|
||||
// During startup we store the channel every block.
|
||||
// Recalculate echo estimate.
|
||||
for(i = 0; i < PART_LEN -7; i += 8)
|
||||
{
|
||||
// aecm->channelStored[i] = acem->channelAdapt16[i];
|
||||
// echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
|
||||
__asm__("vld1.16 {d26, d27}, [%0]" : : "r"(&far_spectrum[i]) : "q13");
|
||||
__asm__("vld1.16 {d24, d25}, [%0, :128]" : : "r"(&aecm->channelAdapt16[i]) : "q12");
|
||||
__asm__("vst1.16 {d24, d25}, [%0, :128]" : : "r"(&aecm->channelStored[i]) : "q12");
|
||||
__asm__("vmull.u16 q10, d26, d24" : : : "q12", "q13", "q10");
|
||||
__asm__("vmull.u16 q11, d27, d25" : : : "q12", "q13", "q11");
|
||||
__asm__("vst1.16 {d20, d21, d22, d23}, [%0, :256]" : :
|
||||
"r"(&echo_est[i]) : "q10", "q11");
|
||||
}
|
||||
aecm->channelStored[i] = aecm->channelAdapt16[i];
|
||||
echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]);
|
||||
// The C code of following optimized code.
|
||||
// for (i = 0; i < PART_LEN1; i++) {
|
||||
// aecm->channelAdapt16[i] = aecm->channelStored[i];
|
||||
// aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32(
|
||||
// (int32_t)aecm->channelStored[i], 16);
|
||||
// }
|
||||
|
||||
int16_t* start_stored_p = aecm->channelStored;
|
||||
int16_t* start_adapt16_p = aecm->channelAdapt16;
|
||||
int32_t* start_adapt32_p = aecm->channelAdapt32;
|
||||
const int16_t* end_stored_p = start_stored_p + PART_LEN;
|
||||
|
||||
int16x8_t stored_v;
|
||||
int32x4_t adapt32_v_low, adapt32_v_high;
|
||||
|
||||
while (start_stored_p < end_stored_p) {
|
||||
stored_v = vld1q_s16(start_stored_p);
|
||||
vst1q_s16(start_adapt16_p, stored_v);
|
||||
|
||||
adapt32_v_low = vshll_n_s16(vget_low_s16(stored_v), 16);
|
||||
adapt32_v_high = vshll_n_s16(vget_high_s16(stored_v), 16);
|
||||
|
||||
vst1q_s32(start_adapt32_p, adapt32_v_low);
|
||||
vst1q_s32(start_adapt32_p + 4, adapt32_v_high);
|
||||
|
||||
start_stored_p += 8;
|
||||
start_adapt16_p += 8;
|
||||
start_adapt32_p += 8;
|
||||
}
|
||||
aecm->channelAdapt16[PART_LEN] = aecm->channelStored[PART_LEN];
|
||||
aecm->channelAdapt32[PART_LEN] = (int32_t)aecm->channelStored[PART_LEN] << 16;
|
||||
}
|
||||
|
||||
void WebRtcAecm_ResetAdaptiveChannel(AecmCore_t* aecm)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < PART_LEN -7; i += 8)
|
||||
{
|
||||
// aecm->channelAdapt16[i] = aecm->channelStored[i];
|
||||
// aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)
|
||||
// aecm->channelStored[i], 16);
|
||||
__asm__("vld1.16 {d24, d25}, [%0, :128]" : :
|
||||
"r"(&aecm->channelStored[i]) : "q12");
|
||||
__asm__("vst1.16 {d24, d25}, [%0, :128]" : :
|
||||
"r"(&aecm->channelAdapt16[i]) : "q12");
|
||||
__asm__("vshll.s16 q10, d24, #16" : : : "q12", "q13", "q10");
|
||||
__asm__("vshll.s16 q11, d25, #16" : : : "q12", "q13", "q11");
|
||||
__asm__("vst1.16 {d20, d21, d22, d23}, [%0, :256]" : :
|
||||
"r"(&aecm->channelAdapt32[i]): "q10", "q11");
|
||||
}
|
||||
aecm->channelAdapt16[i] = aecm->channelStored[i];
|
||||
aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32(
|
||||
(WebRtc_Word32)aecm->channelStored[i], 16);
|
||||
}
|
||||
|
||||
#endif // #if defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM_NEON)
|
||||
|
||||
87
webrtc/modules/audio_processing/aecm/aecm_defines.h
Normal file
87
webrtc/modules/audio_processing/aecm/aecm_defines.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AECM_AECM_DEFINES_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_AECM_DEFINES_H_
|
||||
|
||||
#define AECM_DYNAMIC_Q /* Turn on/off dynamic Q-domain. */
|
||||
|
||||
/* Algorithm parameters */
|
||||
#define FRAME_LEN 80 /* Total frame length, 10 ms. */
|
||||
|
||||
#define PART_LEN 64 /* Length of partition. */
|
||||
#define PART_LEN_SHIFT 7 /* Length of (PART_LEN * 2) in base 2. */
|
||||
|
||||
#define PART_LEN1 (PART_LEN + 1) /* Unique fft coefficients. */
|
||||
#define PART_LEN2 (PART_LEN << 1) /* Length of partition * 2. */
|
||||
#define PART_LEN4 (PART_LEN << 2) /* Length of partition * 4. */
|
||||
#define FAR_BUF_LEN PART_LEN4 /* Length of buffers. */
|
||||
#define MAX_DELAY 100
|
||||
|
||||
/* Counter parameters */
|
||||
#define CONV_LEN 512 /* Convergence length used at startup. */
|
||||
#define CONV_LEN2 (CONV_LEN << 1) /* Used at startup. */
|
||||
|
||||
/* Energy parameters */
|
||||
#define MAX_BUF_LEN 64 /* History length of energy signals. */
|
||||
#define FAR_ENERGY_MIN 1025 /* Lowest Far energy level: At least 2 */
|
||||
/* in energy. */
|
||||
#define FAR_ENERGY_DIFF 929 /* Allowed difference between max */
|
||||
/* and min. */
|
||||
#define ENERGY_DEV_OFFSET 0 /* The energy error offset in Q8. */
|
||||
#define ENERGY_DEV_TOL 400 /* The energy estimation tolerance (Q8). */
|
||||
#define FAR_ENERGY_VAD_REGION 230 /* Far VAD tolerance region. */
|
||||
|
||||
/* Stepsize parameters */
|
||||
#define MU_MIN 10 /* Min stepsize 2^-MU_MIN (far end energy */
|
||||
/* dependent). */
|
||||
#define MU_MAX 1 /* Max stepsize 2^-MU_MAX (far end energy */
|
||||
/* dependent). */
|
||||
#define MU_DIFF 9 /* MU_MIN - MU_MAX */
|
||||
|
||||
/* Channel parameters */
|
||||
#define MIN_MSE_COUNT 20 /* Min number of consecutive blocks with enough */
|
||||
/* far end energy to compare channel estimates. */
|
||||
#define MIN_MSE_DIFF 29 /* The ratio between adapted and stored channel to */
|
||||
/* accept a new storage (0.8 in Q-MSE_RESOLUTION). */
|
||||
#define MSE_RESOLUTION 5 /* MSE parameter resolution. */
|
||||
#define RESOLUTION_CHANNEL16 12 /* W16 Channel in Q-RESOLUTION_CHANNEL16. */
|
||||
#define RESOLUTION_CHANNEL32 28 /* W32 Channel in Q-RESOLUTION_CHANNEL. */
|
||||
#define CHANNEL_VAD 16 /* Minimum energy in frequency band */
|
||||
/* to update channel. */
|
||||
|
||||
/* Suppression gain parameters: SUPGAIN parameters in Q-(RESOLUTION_SUPGAIN). */
|
||||
#define RESOLUTION_SUPGAIN 8 /* Channel in Q-(RESOLUTION_SUPGAIN). */
|
||||
#define SUPGAIN_DEFAULT (1 << RESOLUTION_SUPGAIN) /* Default. */
|
||||
#define SUPGAIN_ERROR_PARAM_A 3072 /* Estimation error parameter */
|
||||
/* (Maximum gain) (8 in Q8). */
|
||||
#define SUPGAIN_ERROR_PARAM_B 1536 /* Estimation error parameter */
|
||||
/* (Gain before going down). */
|
||||
#define SUPGAIN_ERROR_PARAM_D SUPGAIN_DEFAULT /* Estimation error parameter */
|
||||
/* (Should be the same as Default) (1 in Q8). */
|
||||
#define SUPGAIN_EPC_DT 200 /* SUPGAIN_ERROR_PARAM_C * ENERGY_DEV_TOL */
|
||||
|
||||
/* Defines for "check delay estimation" */
|
||||
#define CORR_WIDTH 31 /* Number of samples to correlate over. */
|
||||
#define CORR_MAX 16 /* Maximum correlation offset. */
|
||||
#define CORR_MAX_BUF 63
|
||||
#define CORR_DEV 4
|
||||
#define CORR_MAX_LEVEL 20
|
||||
#define CORR_MAX_LOW 4
|
||||
#define CORR_BUF_LEN (CORR_MAX << 1) + 1
|
||||
/* Note that CORR_WIDTH + 2*CORR_MAX <= MAX_BUF_LEN. */
|
||||
|
||||
#define ONE_Q14 (1 << 14)
|
||||
|
||||
/* NLP defines */
|
||||
#define NLP_COMP_LOW 3277 /* 0.2 in Q14 */
|
||||
#define NLP_COMP_HIGH ONE_Q14 /* 1 in Q14 */
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
* 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
|
||||
@@ -8,22 +8,16 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
//#include <string.h>
|
||||
#include "webrtc/modules/audio_processing/aecm/include/echo_control_mobile.h"
|
||||
|
||||
#include "echo_control_mobile.h"
|
||||
#include "aecm_core.h"
|
||||
#include "ring_buffer.h"
|
||||
#ifdef AEC_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef MAC_IPHONE_PRINT
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#elif defined ARM_WINM_LOG
|
||||
#include "windows.h"
|
||||
extern HANDLE logFile;
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "webrtc/common_audio/ring_buffer.h"
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/modules/audio_processing/aecm/aecm_core.h"
|
||||
|
||||
#define BUF_SIZE_FRAMES 50 // buffer size (frames)
|
||||
// Maximum length of resampled signal. Must be an integer multiple of frames
|
||||
@@ -31,7 +25,7 @@ extern HANDLE logFile;
|
||||
// The factor of 2 handles wb, and the + 1 is as a safety margin
|
||||
#define MAX_RESAMP_LEN (5 * FRAME_LEN)
|
||||
|
||||
static const int kBufSizeSamp = BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples)
|
||||
static const size_t kBufSizeSamp = BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples)
|
||||
static const int kSampMsNb = 8; // samples per ms in nb
|
||||
// Target suppression levels for nlp modes
|
||||
// log{0.001, 0.00001, 0.00000001}
|
||||
@@ -63,7 +57,7 @@ typedef struct
|
||||
int delayChange;
|
||||
short lastDelayDiff;
|
||||
|
||||
WebRtc_Word16 echoMode;
|
||||
int16_t echoMode;
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
FILE *bufFile;
|
||||
@@ -72,47 +66,37 @@ typedef struct
|
||||
FILE *postCompFile;
|
||||
#endif // AEC_DEBUG
|
||||
// Structures
|
||||
void *farendBuf;
|
||||
RingBuffer *farendBuf;
|
||||
|
||||
int lastError;
|
||||
|
||||
AecmCore_t *aecmCore;
|
||||
} aecmob_t;
|
||||
AecmCore* aecmCore;
|
||||
} AecMobile;
|
||||
|
||||
// Estimates delay to set the position of the farend buffer read pointer
|
||||
// (controlled by knownDelay)
|
||||
static int WebRtcAecm_EstBufDelay(aecmob_t *aecmInst, short msInSndCardBuf);
|
||||
static int WebRtcAecm_EstBufDelay(AecMobile* aecmInst, short msInSndCardBuf);
|
||||
|
||||
// Stuffs the farend buffer if the estimated delay is too large
|
||||
static int WebRtcAecm_DelayComp(aecmob_t *aecmInst);
|
||||
static int WebRtcAecm_DelayComp(AecMobile* aecmInst);
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_Create(void **aecmInst)
|
||||
{
|
||||
aecmob_t *aecm;
|
||||
if (aecmInst == NULL)
|
||||
{
|
||||
return -1;
|
||||
void* WebRtcAecm_Create() {
|
||||
AecMobile* aecm = malloc(sizeof(AecMobile));
|
||||
|
||||
WebRtcSpl_Init();
|
||||
|
||||
aecm->aecmCore = WebRtcAecm_CreateCore();
|
||||
if (!aecm->aecmCore) {
|
||||
WebRtcAecm_Free(aecm);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
aecm = malloc(sizeof(aecmob_t));
|
||||
*aecmInst = aecm;
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (WebRtcAecm_CreateCore(&aecm->aecmCore) == -1)
|
||||
aecm->farendBuf = WebRtc_CreateBuffer(kBufSizeSamp,
|
||||
sizeof(int16_t));
|
||||
if (!aecm->farendBuf)
|
||||
{
|
||||
WebRtcAecm_Free(aecm);
|
||||
aecm = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (WebRtcApm_CreateBuffer(&aecm->farendBuf, kBufSizeSamp) == -1)
|
||||
{
|
||||
WebRtcAecm_Free(aecm);
|
||||
aecm = NULL;
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
aecm->initFlag = 0;
|
||||
@@ -129,16 +113,14 @@ WebRtc_Word32 WebRtcAecm_Create(void **aecmInst)
|
||||
aecm->preCompFile = fopen("preComp.pcm", "wb");
|
||||
aecm->postCompFile = fopen("postComp.pcm", "wb");
|
||||
#endif // AEC_DEBUG
|
||||
return 0;
|
||||
return aecm;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_Free(void *aecmInst)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
void WebRtcAecm_Free(void* aecmInst) {
|
||||
AecMobile* aecm = aecmInst;
|
||||
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
if (aecm == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
@@ -153,15 +135,13 @@ WebRtc_Word32 WebRtcAecm_Free(void *aecmInst)
|
||||
fclose(aecm->postCompFile);
|
||||
#endif // AEC_DEBUG
|
||||
WebRtcAecm_FreeCore(aecm->aecmCore);
|
||||
WebRtcApm_FreeBuffer(aecm->farendBuf);
|
||||
WebRtc_FreeBuffer(aecm->farendBuf);
|
||||
free(aecm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_Init(void *aecmInst, WebRtc_Word32 sampFreq)
|
||||
int32_t WebRtcAecm_Init(void *aecmInst, int32_t sampFreq)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
AecMobile* aecm = aecmInst;
|
||||
AecmConfig aecConfig;
|
||||
|
||||
if (aecm == NULL)
|
||||
@@ -184,11 +164,7 @@ WebRtc_Word32 WebRtcAecm_Init(void *aecmInst, WebRtc_Word32 sampFreq)
|
||||
}
|
||||
|
||||
// Initialize farend buffer
|
||||
if (WebRtcApm_InitBuffer(aecm->farendBuf) == -1)
|
||||
{
|
||||
aecm->lastError = AECM_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
WebRtc_InitBuffer(aecm->farendBuf);
|
||||
|
||||
aecm->initFlag = kInitCheck; // indicates that initialization has been done
|
||||
|
||||
@@ -222,11 +198,11 @@ WebRtc_Word32 WebRtcAecm_Init(void *aecmInst, WebRtc_Word32 sampFreq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_BufferFarend(void *aecmInst, const WebRtc_Word16 *farend,
|
||||
WebRtc_Word16 nrOfSamples)
|
||||
int32_t WebRtcAecm_BufferFarend(void *aecmInst, const int16_t *farend,
|
||||
size_t nrOfSamples)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
WebRtc_Word32 retVal = 0;
|
||||
AecMobile* aecm = aecmInst;
|
||||
int32_t retVal = 0;
|
||||
|
||||
if (aecm == NULL)
|
||||
{
|
||||
@@ -257,38 +233,25 @@ WebRtc_Word32 WebRtcAecm_BufferFarend(void *aecmInst, const WebRtc_Word16 *faren
|
||||
WebRtcAecm_DelayComp(aecm);
|
||||
}
|
||||
|
||||
WebRtcApm_WriteBuffer(aecm->farendBuf, farend, nrOfSamples);
|
||||
WebRtc_WriteBuffer(aecm->farendBuf, farend, nrOfSamples);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_Process(void *aecmInst, const WebRtc_Word16 *nearendNoisy,
|
||||
const WebRtc_Word16 *nearendClean, WebRtc_Word16 *out,
|
||||
WebRtc_Word16 nrOfSamples, WebRtc_Word16 msInSndCardBuf)
|
||||
int32_t WebRtcAecm_Process(void *aecmInst, const int16_t *nearendNoisy,
|
||||
const int16_t *nearendClean, int16_t *out,
|
||||
size_t nrOfSamples, int16_t msInSndCardBuf)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
WebRtc_Word32 retVal = 0;
|
||||
short i;
|
||||
short farend[FRAME_LEN];
|
||||
AecMobile* aecm = aecmInst;
|
||||
int32_t retVal = 0;
|
||||
size_t i;
|
||||
short nmbrOfFilledBuffers;
|
||||
short nBlocks10ms;
|
||||
short nFrames;
|
||||
size_t nBlocks10ms;
|
||||
size_t nFrames;
|
||||
#ifdef AEC_DEBUG
|
||||
short msInAECBuf;
|
||||
#endif
|
||||
|
||||
#ifdef ARM_WINM_LOG
|
||||
__int64 freq, start, end, diff;
|
||||
unsigned int milliseconds;
|
||||
DWORD temp;
|
||||
#elif defined MAC_IPHONE_PRINT
|
||||
// double endtime = 0, starttime = 0;
|
||||
struct timeval starttime;
|
||||
struct timeval endtime;
|
||||
static long int timeused = 0;
|
||||
static int timecount = 0;
|
||||
#endif
|
||||
|
||||
if (aecm == NULL)
|
||||
{
|
||||
return -1;
|
||||
@@ -339,13 +302,17 @@ WebRtc_Word32 WebRtcAecm_Process(void *aecmInst, const WebRtc_Word16 *nearendNoi
|
||||
{
|
||||
if (nearendClean == NULL)
|
||||
{
|
||||
memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples);
|
||||
} else
|
||||
if (out != nearendNoisy)
|
||||
{
|
||||
memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples);
|
||||
}
|
||||
} else if (out != nearendClean)
|
||||
{
|
||||
memcpy(out, nearendClean, sizeof(short) * nrOfSamples);
|
||||
}
|
||||
|
||||
nmbrOfFilledBuffers = WebRtcApm_get_buffer_size(aecm->farendBuf) / FRAME_LEN;
|
||||
nmbrOfFilledBuffers =
|
||||
(short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
|
||||
// The AECM is in the start up mode
|
||||
// AECM is disabled until the soundcard buffer and farend buffers are OK
|
||||
|
||||
@@ -407,10 +374,9 @@ WebRtc_Word32 WebRtcAecm_Process(void *aecmInst, const WebRtc_Word16 *nearendNoi
|
||||
aecm->ECstartup = 0; // Enable the AECM
|
||||
} else if (nmbrOfFilledBuffers > aecm->bufSizeStart)
|
||||
{
|
||||
WebRtcApm_FlushBuffer(
|
||||
aecm->farendBuf,
|
||||
WebRtcApm_get_buffer_size(aecm->farendBuf)
|
||||
- aecm->bufSizeStart * FRAME_LEN);
|
||||
WebRtc_MoveReadPtr(aecm->farendBuf,
|
||||
(int) WebRtc_available_read(aecm->farendBuf)
|
||||
- (int) aecm->bufSizeStart * FRAME_LEN);
|
||||
aecm->ECstartup = 0;
|
||||
}
|
||||
}
|
||||
@@ -422,20 +388,27 @@ WebRtc_Word32 WebRtcAecm_Process(void *aecmInst, const WebRtc_Word16 *nearendNoi
|
||||
// Note only 1 block supported for nb and 2 blocks for wb
|
||||
for (i = 0; i < nFrames; i++)
|
||||
{
|
||||
nmbrOfFilledBuffers = WebRtcApm_get_buffer_size(aecm->farendBuf) / FRAME_LEN;
|
||||
int16_t farend[FRAME_LEN];
|
||||
const int16_t* farend_ptr = NULL;
|
||||
|
||||
nmbrOfFilledBuffers =
|
||||
(short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN;
|
||||
|
||||
// Check that there is data in the far end buffer
|
||||
if (nmbrOfFilledBuffers > 0)
|
||||
{
|
||||
// Get the next 80 samples from the farend buffer
|
||||
WebRtcApm_ReadBuffer(aecm->farendBuf, farend, FRAME_LEN);
|
||||
WebRtc_ReadBuffer(aecm->farendBuf, (void**) &farend_ptr, farend,
|
||||
FRAME_LEN);
|
||||
|
||||
// Always store the last frame for use when we run out of data
|
||||
memcpy(&(aecm->farendOld[i][0]), farend, FRAME_LEN * sizeof(short));
|
||||
memcpy(&(aecm->farendOld[i][0]), farend_ptr,
|
||||
FRAME_LEN * sizeof(short));
|
||||
} else
|
||||
{
|
||||
// We have no data so we use the last played frame
|
||||
memcpy(farend, &(aecm->farendOld[i][0]), FRAME_LEN * sizeof(short));
|
||||
farend_ptr = farend;
|
||||
}
|
||||
|
||||
// Call buffer delay estimator when all data is extracted,
|
||||
@@ -445,77 +418,23 @@ WebRtc_Word32 WebRtcAecm_Process(void *aecmInst, const WebRtc_Word16 *nearendNoi
|
||||
WebRtcAecm_EstBufDelay(aecm, aecm->msInSndCardBuf);
|
||||
}
|
||||
|
||||
#ifdef ARM_WINM_LOG
|
||||
// measure tick start
|
||||
QueryPerformanceFrequency((LARGE_INTEGER*)&freq);
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&start);
|
||||
#elif defined MAC_IPHONE_PRINT
|
||||
// starttime = clock()/(double)CLOCKS_PER_SEC;
|
||||
gettimeofday(&starttime, NULL);
|
||||
#endif
|
||||
// Call the AECM
|
||||
/*WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearend[FRAME_LEN * i],
|
||||
&out[FRAME_LEN * i], aecm->knownDelay);*/
|
||||
if (nearendClean == NULL)
|
||||
{
|
||||
if (WebRtcAecm_ProcessFrame(aecm->aecmCore,
|
||||
farend,
|
||||
&nearendNoisy[FRAME_LEN * i],
|
||||
NULL,
|
||||
&out[FRAME_LEN * i]) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (WebRtcAecm_ProcessFrame(aecm->aecmCore,
|
||||
farend,
|
||||
&nearendNoisy[FRAME_LEN * i],
|
||||
&nearendClean[FRAME_LEN * i],
|
||||
&out[FRAME_LEN * i]) == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ARM_WINM_LOG
|
||||
|
||||
// measure tick end
|
||||
QueryPerformanceCounter((LARGE_INTEGER*)&end);
|
||||
|
||||
if(end > start)
|
||||
{
|
||||
diff = ((end - start) * 1000) / (freq/1000);
|
||||
milliseconds = (unsigned int)(diff & 0xffffffff);
|
||||
WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL);
|
||||
}
|
||||
#elif defined MAC_IPHONE_PRINT
|
||||
// endtime = clock()/(double)CLOCKS_PER_SEC;
|
||||
// printf("%f\n", endtime - starttime);
|
||||
|
||||
gettimeofday(&endtime, NULL);
|
||||
|
||||
if( endtime.tv_usec > starttime.tv_usec)
|
||||
{
|
||||
timeused += endtime.tv_usec - starttime.tv_usec;
|
||||
} else
|
||||
{
|
||||
timeused += endtime.tv_usec + 1000000 - starttime.tv_usec;
|
||||
}
|
||||
|
||||
if(++timecount == 1000)
|
||||
{
|
||||
timecount = 0;
|
||||
printf("AEC: %ld\n", timeused);
|
||||
timeused = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (WebRtcAecm_ProcessFrame(aecm->aecmCore,
|
||||
farend_ptr,
|
||||
&nearendNoisy[FRAME_LEN * i],
|
||||
(nearendClean
|
||||
? &nearendClean[FRAME_LEN * i]
|
||||
: NULL),
|
||||
&out[FRAME_LEN * i]) == -1)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef AEC_DEBUG
|
||||
msInAECBuf = WebRtcApm_get_buffer_size(aecm->farendBuf) / (kSampMsNb*aecm->aecmCore->mult);
|
||||
msInAECBuf = (short) WebRtc_available_read(aecm->farendBuf) /
|
||||
(kSampMsNb * aecm->aecmCore->mult);
|
||||
fwrite(&msInAECBuf, 2, 1, aecm->bufFile);
|
||||
fwrite(&(aecm->knownDelay), sizeof(aecm->knownDelay), 1, aecm->delayFile);
|
||||
#endif
|
||||
@@ -523,9 +442,9 @@ WebRtc_Word32 WebRtcAecm_Process(void *aecmInst, const WebRtc_Word16 *nearendNoi
|
||||
return retVal;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_set_config(void *aecmInst, AecmConfig config)
|
||||
int32_t WebRtcAecm_set_config(void *aecmInst, AecmConfig config)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
AecMobile* aecm = aecmInst;
|
||||
|
||||
if (aecm == NULL)
|
||||
{
|
||||
@@ -605,9 +524,9 @@ WebRtc_Word32 WebRtcAecm_set_config(void *aecmInst, AecmConfig config)
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_get_config(void *aecmInst, AecmConfig *config)
|
||||
int32_t WebRtcAecm_get_config(void *aecmInst, AecmConfig *config)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
AecMobile* aecm = aecmInst;
|
||||
|
||||
if (aecm == NULL)
|
||||
{
|
||||
@@ -632,17 +551,19 @@ WebRtc_Word32 WebRtcAecm_get_config(void *aecmInst, AecmConfig *config)
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_InitEchoPath(void* aecmInst,
|
||||
const void* echo_path,
|
||||
size_t size_bytes)
|
||||
int32_t WebRtcAecm_InitEchoPath(void* aecmInst,
|
||||
const void* echo_path,
|
||||
size_t size_bytes)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
const WebRtc_Word16* echo_path_ptr = echo_path;
|
||||
AecMobile* aecm = aecmInst;
|
||||
const int16_t* echo_path_ptr = echo_path;
|
||||
|
||||
if ((aecm == NULL) || (echo_path == NULL))
|
||||
{
|
||||
aecm->lastError = AECM_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
if (aecmInst == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (echo_path == NULL) {
|
||||
aecm->lastError = AECM_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (size_bytes != WebRtcAecm_echo_path_size_bytes())
|
||||
{
|
||||
@@ -661,17 +582,19 @@ WebRtc_Word32 WebRtcAecm_InitEchoPath(void* aecmInst,
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_GetEchoPath(void* aecmInst,
|
||||
void* echo_path,
|
||||
size_t size_bytes)
|
||||
int32_t WebRtcAecm_GetEchoPath(void* aecmInst,
|
||||
void* echo_path,
|
||||
size_t size_bytes)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
WebRtc_Word16* echo_path_ptr = echo_path;
|
||||
AecMobile* aecm = aecmInst;
|
||||
int16_t* echo_path_ptr = echo_path;
|
||||
|
||||
if ((aecm == NULL) || (echo_path == NULL))
|
||||
{
|
||||
aecm->lastError = AECM_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
if (aecmInst == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (echo_path == NULL) {
|
||||
aecm->lastError = AECM_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (size_bytes != WebRtcAecm_echo_path_size_bytes())
|
||||
{
|
||||
@@ -691,31 +614,12 @@ WebRtc_Word32 WebRtcAecm_GetEchoPath(void* aecmInst,
|
||||
|
||||
size_t WebRtcAecm_echo_path_size_bytes()
|
||||
{
|
||||
return (PART_LEN1 * sizeof(WebRtc_Word16));
|
||||
return (PART_LEN1 * sizeof(int16_t));
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_get_version(WebRtc_Word8 *versionStr, WebRtc_Word16 len)
|
||||
int32_t WebRtcAecm_get_error_code(void *aecmInst)
|
||||
{
|
||||
const char version[] = "AECM 1.2.0";
|
||||
const short versionLen = (short)strlen(version) + 1; // +1 for null-termination
|
||||
|
||||
if (versionStr == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (versionLen > len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(versionStr, version, versionLen);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAecm_get_error_code(void *aecmInst)
|
||||
{
|
||||
aecmob_t *aecm = aecmInst;
|
||||
AecMobile* aecm = aecmInst;
|
||||
|
||||
if (aecm == NULL)
|
||||
{
|
||||
@@ -725,19 +629,18 @@ WebRtc_Word32 WebRtcAecm_get_error_code(void *aecmInst)
|
||||
return aecm->lastError;
|
||||
}
|
||||
|
||||
static int WebRtcAecm_EstBufDelay(aecmob_t *aecm, short msInSndCardBuf)
|
||||
{
|
||||
short delayNew, nSampFar, nSampSndCard;
|
||||
static int WebRtcAecm_EstBufDelay(AecMobile* aecm, short msInSndCardBuf) {
|
||||
short delayNew, nSampSndCard;
|
||||
short nSampFar = (short) WebRtc_available_read(aecm->farendBuf);
|
||||
short diff;
|
||||
|
||||
nSampFar = WebRtcApm_get_buffer_size(aecm->farendBuf);
|
||||
nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
|
||||
|
||||
delayNew = nSampSndCard - nSampFar;
|
||||
|
||||
if (delayNew < FRAME_LEN)
|
||||
{
|
||||
WebRtcApm_FlushBuffer(aecm->farendBuf, FRAME_LEN);
|
||||
WebRtc_MoveReadPtr(aecm->farendBuf, FRAME_LEN);
|
||||
delayNew += FRAME_LEN;
|
||||
}
|
||||
|
||||
@@ -775,12 +678,11 @@ static int WebRtcAecm_EstBufDelay(aecmob_t *aecm, short msInSndCardBuf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int WebRtcAecm_DelayComp(aecmob_t *aecm)
|
||||
{
|
||||
int nSampFar, nSampSndCard, delayNew, nSampAdd;
|
||||
static int WebRtcAecm_DelayComp(AecMobile* aecm) {
|
||||
int nSampFar = (int) WebRtc_available_read(aecm->farendBuf);
|
||||
int nSampSndCard, delayNew, nSampAdd;
|
||||
const int maxStuffSamp = 10 * FRAME_LEN;
|
||||
|
||||
nSampFar = WebRtcApm_get_buffer_size(aecm->farendBuf);
|
||||
nSampSndCard = aecm->msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult;
|
||||
delayNew = nSampSndCard - nSampFar;
|
||||
|
||||
@@ -792,7 +694,7 @@ static int WebRtcAecm_DelayComp(aecmob_t *aecm)
|
||||
FRAME_LEN));
|
||||
nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp);
|
||||
|
||||
WebRtcApm_StuffBuffer(aecm->farendBuf, nSampAdd);
|
||||
WebRtc_MoveReadPtr(aecm->farendBuf, -nSampAdd);
|
||||
aecm->delayChange = 1; // the delay needs to be updated
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
* 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
|
||||
@@ -8,10 +8,12 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_INTERFACE_ECHO_CONTROL_MOBILE_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_INTERFACE_ECHO_CONTROL_MOBILE_H_
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AECM_INCLUDE_ECHO_CONTROL_MOBILE_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_INCLUDE_ECHO_CONTROL_MOBILE_H_
|
||||
|
||||
#include "typedefs.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
enum {
|
||||
AecmFalse = 0,
|
||||
@@ -29,8 +31,8 @@ enum {
|
||||
#define AECM_BAD_PARAMETER_WARNING 12100
|
||||
|
||||
typedef struct {
|
||||
WebRtc_Word16 cngMode; // AECM_FALSE, AECM_TRUE (default)
|
||||
WebRtc_Word16 echoMode; // 0, 1, 2, 3 (default), 4
|
||||
int16_t cngMode; // AECM_FALSE, AECM_TRUE (default)
|
||||
int16_t echoMode; // 0, 1, 2, 3 (default), 4
|
||||
} AecmConfig;
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -40,133 +42,116 @@ extern "C" {
|
||||
/*
|
||||
* Allocates the memory needed by the AECM. The memory needs to be
|
||||
* initialized separately using the WebRtcAecm_Init() function.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void **aecmInst Pointer to the AECM instance to be
|
||||
* created and initialized
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
* Returns a pointer to the instance and a nullptr at failure.
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_Create(void **aecmInst);
|
||||
void* WebRtcAecm_Create();
|
||||
|
||||
/*
|
||||
* This function releases the memory allocated by WebRtcAecm_Create()
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecmInst Pointer to the AECM instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
* void* aecmInst Pointer to the AECM instance
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_Free(void *aecmInst);
|
||||
void WebRtcAecm_Free(void* aecmInst);
|
||||
|
||||
/*
|
||||
* Initializes an AECM instance.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecmInst Pointer to the AECM instance
|
||||
* WebRtc_Word32 sampFreq Sampling frequency of data
|
||||
* void* aecmInst Pointer to the AECM instance
|
||||
* int32_t sampFreq Sampling frequency of data
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_Init(void* aecmInst,
|
||||
WebRtc_Word32 sampFreq);
|
||||
int32_t WebRtcAecm_Init(void* aecmInst, int32_t sampFreq);
|
||||
|
||||
/*
|
||||
* Inserts an 80 or 160 sample block of data into the farend buffer.
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecmInst Pointer to the AECM instance
|
||||
* WebRtc_Word16 *farend In buffer containing one frame of
|
||||
* void* aecmInst Pointer to the AECM instance
|
||||
* int16_t* farend In buffer containing one frame of
|
||||
* farend signal
|
||||
* WebRtc_Word16 nrOfSamples Number of samples in farend buffer
|
||||
* int16_t nrOfSamples Number of samples in farend buffer
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_BufferFarend(void* aecmInst,
|
||||
const WebRtc_Word16* farend,
|
||||
WebRtc_Word16 nrOfSamples);
|
||||
int32_t WebRtcAecm_BufferFarend(void* aecmInst,
|
||||
const int16_t* farend,
|
||||
size_t nrOfSamples);
|
||||
|
||||
/*
|
||||
* Runs the AECM on an 80 or 160 sample blocks of data.
|
||||
*
|
||||
* Inputs Description
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecmInst Pointer to the AECM instance
|
||||
* WebRtc_Word16 *nearendNoisy In buffer containing one frame of
|
||||
* void* aecmInst Pointer to the AECM instance
|
||||
* int16_t* nearendNoisy In buffer containing one frame of
|
||||
* reference nearend+echo signal. If
|
||||
* noise reduction is active, provide
|
||||
* the noisy signal here.
|
||||
* WebRtc_Word16 *nearendClean In buffer containing one frame of
|
||||
* int16_t* nearendClean In buffer containing one frame of
|
||||
* nearend+echo signal. If noise
|
||||
* reduction is active, provide the
|
||||
* clean signal here. Otherwise pass a
|
||||
* NULL pointer.
|
||||
* WebRtc_Word16 nrOfSamples Number of samples in nearend buffer
|
||||
* WebRtc_Word16 msInSndCardBuf Delay estimate for sound card and
|
||||
* int16_t nrOfSamples Number of samples in nearend buffer
|
||||
* int16_t msInSndCardBuf Delay estimate for sound card and
|
||||
* system buffers
|
||||
*
|
||||
* Outputs Description
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word16 *out Out buffer, one frame of processed nearend
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
* int16_t* out Out buffer, one frame of processed nearend
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_Process(void* aecmInst,
|
||||
const WebRtc_Word16* nearendNoisy,
|
||||
const WebRtc_Word16* nearendClean,
|
||||
WebRtc_Word16* out,
|
||||
WebRtc_Word16 nrOfSamples,
|
||||
WebRtc_Word16 msInSndCardBuf);
|
||||
int32_t WebRtcAecm_Process(void* aecmInst,
|
||||
const int16_t* nearendNoisy,
|
||||
const int16_t* nearendClean,
|
||||
int16_t* out,
|
||||
size_t nrOfSamples,
|
||||
int16_t msInSndCardBuf);
|
||||
|
||||
/*
|
||||
* This function enables the user to set certain parameters on-the-fly
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecmInst Pointer to the AECM instance
|
||||
* AecmConfig config Config instance that contains all
|
||||
* void* aecmInst Pointer to the AECM instance
|
||||
* AecmConfig config Config instance that contains all
|
||||
* properties to be set
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_set_config(void* aecmInst,
|
||||
AecmConfig config);
|
||||
int32_t WebRtcAecm_set_config(void* aecmInst, AecmConfig config);
|
||||
|
||||
/*
|
||||
* This function enables the user to set certain parameters on-the-fly
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecmInst Pointer to the AECM instance
|
||||
* void* aecmInst Pointer to the AECM instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* AecmConfig *config Pointer to the config instance that
|
||||
* AecmConfig* config Pointer to the config instance that
|
||||
* all properties will be written to
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_get_config(void *aecmInst,
|
||||
AecmConfig *config);
|
||||
int32_t WebRtcAecm_get_config(void *aecmInst, AecmConfig *config);
|
||||
|
||||
/*
|
||||
* This function enables the user to set the echo path on-the-fly.
|
||||
@@ -179,12 +164,12 @@ WebRtc_Word32 WebRtcAecm_get_config(void *aecmInst,
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_InitEchoPath(void* aecmInst,
|
||||
const void* echo_path,
|
||||
size_t size_bytes);
|
||||
int32_t WebRtcAecm_InitEchoPath(void* aecmInst,
|
||||
const void* echo_path,
|
||||
size_t size_bytes);
|
||||
|
||||
/*
|
||||
* This function enables the user to get the currently used echo path
|
||||
@@ -198,19 +183,19 @@ WebRtc_Word32 WebRtcAecm_InitEchoPath(void* aecmInst,
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* int32_t return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_GetEchoPath(void* aecmInst,
|
||||
void* echo_path,
|
||||
size_t size_bytes);
|
||||
int32_t WebRtcAecm_GetEchoPath(void* aecmInst,
|
||||
void* echo_path,
|
||||
size_t size_bytes);
|
||||
|
||||
/*
|
||||
* This function enables the user to get the echo path size in bytes
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* size_t return : size in bytes
|
||||
* size_t return Size in bytes
|
||||
*/
|
||||
size_t WebRtcAecm_echo_path_size_bytes();
|
||||
|
||||
@@ -219,32 +204,15 @@ size_t WebRtcAecm_echo_path_size_bytes();
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* void *aecmInst Pointer to the AECM instance
|
||||
* void* aecmInst Pointer to the AECM instance
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word32 return 11000-11100: error code
|
||||
* int32_t return 11000-11100: error code
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_get_error_code(void *aecmInst);
|
||||
|
||||
/*
|
||||
* Gets a version string
|
||||
*
|
||||
* Inputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* char *versionStr Pointer to a string array
|
||||
* WebRtc_Word16 len The maximum length of the string
|
||||
*
|
||||
* Outputs Description
|
||||
* -------------------------------------------------------------------
|
||||
* WebRtc_Word8 *versionStr Pointer to a string array
|
||||
* WebRtc_Word32 return 0: OK
|
||||
* -1: error
|
||||
*/
|
||||
WebRtc_Word32 WebRtcAecm_get_version(WebRtc_Word8 *versionStr,
|
||||
WebRtc_Word16 len);
|
||||
int32_t WebRtcAecm_get_error_code(void *aecmInst);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_INTERFACE_ECHO_CONTROL_MOBILE_H_ */
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AECM_INCLUDE_ECHO_CONTROL_MOBILE_H_
|
||||
@@ -1,10 +0,0 @@
|
||||
noinst_LTLIBRARIES = libagc.la
|
||||
|
||||
libagc_la_SOURCES = interface/gain_control.h \
|
||||
analog_agc.c \
|
||||
analog_agc.h \
|
||||
digital_agc.c \
|
||||
digital_agc.h
|
||||
libagc_la_CFLAGS = $(AM_CFLAGS) $(COMMON_CFLAGS) \
|
||||
-I$(top_srcdir)/src/common_audio/signal_processing_library/main/interface \
|
||||
-I$(top_srcdir)/src/modules/audio_processing/utility
|
||||
101
webrtc/modules/audio_processing/agc/agc.cc
Normal file
101
webrtc/modules/audio_processing/agc/agc.cc
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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/modules/audio_processing/agc/agc.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/modules/audio_processing/agc/histogram.h"
|
||||
#include "webrtc/modules/audio_processing/agc/utility.h"
|
||||
#include "webrtc/modules/interface/module_common_types.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
const int kDefaultLevelDbfs = -18;
|
||||
const int kNumAnalysisFrames = 100;
|
||||
const double kActivityThreshold = 0.3;
|
||||
|
||||
} // namespace
|
||||
|
||||
Agc::Agc()
|
||||
: target_level_loudness_(Dbfs2Loudness(kDefaultLevelDbfs)),
|
||||
target_level_dbfs_(kDefaultLevelDbfs),
|
||||
histogram_(Histogram::Create(kNumAnalysisFrames)),
|
||||
inactive_histogram_(Histogram::Create()) {
|
||||
}
|
||||
|
||||
Agc::~Agc() {}
|
||||
|
||||
float Agc::AnalyzePreproc(const int16_t* audio, size_t length) {
|
||||
assert(length > 0);
|
||||
size_t num_clipped = 0;
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
if (audio[i] == 32767 || audio[i] == -32768)
|
||||
++num_clipped;
|
||||
}
|
||||
return 1.0f * num_clipped / length;
|
||||
}
|
||||
|
||||
int Agc::Process(const int16_t* audio, size_t length, int sample_rate_hz) {
|
||||
vad_.ProcessChunk(audio, length, sample_rate_hz);
|
||||
const std::vector<double>& rms = vad_.chunkwise_rms();
|
||||
const std::vector<double>& probabilities =
|
||||
vad_.chunkwise_voice_probabilities();
|
||||
RTC_DCHECK_EQ(rms.size(), probabilities.size());
|
||||
for (size_t i = 0; i < rms.size(); ++i) {
|
||||
histogram_->Update(rms[i], probabilities[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Agc::GetRmsErrorDb(int* error) {
|
||||
if (!error) {
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (histogram_->num_updates() < kNumAnalysisFrames) {
|
||||
// We haven't yet received enough frames.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (histogram_->AudioContent() < kNumAnalysisFrames * kActivityThreshold) {
|
||||
// We are likely in an inactive segment.
|
||||
return false;
|
||||
}
|
||||
|
||||
double loudness = Linear2Loudness(histogram_->CurrentRms());
|
||||
*error = std::floor(Loudness2Db(target_level_loudness_ - loudness) + 0.5);
|
||||
histogram_->Reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Agc::Reset() {
|
||||
histogram_->Reset();
|
||||
}
|
||||
|
||||
int Agc::set_target_level_dbfs(int level) {
|
||||
// TODO(turajs): just some arbitrary sanity check. We can come up with better
|
||||
// limits. The upper limit should be chosen such that the risk of clipping is
|
||||
// low. The lower limit should not result in a too quiet signal.
|
||||
if (level >= 0 || level <= -100)
|
||||
return -1;
|
||||
target_level_dbfs_ = level;
|
||||
target_level_loudness_ = Dbfs2Loudness(level);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@@ -1,34 +0,0 @@
|
||||
# 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.
|
||||
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'agc',
|
||||
'type': '<(library)',
|
||||
'dependencies': [
|
||||
'<(webrtc_root)/common_audio/common_audio.gyp:spl',
|
||||
],
|
||||
'include_dirs': [
|
||||
'interface',
|
||||
],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'interface',
|
||||
],
|
||||
},
|
||||
'sources': [
|
||||
'interface/gain_control.h',
|
||||
'analog_agc.c',
|
||||
'analog_agc.h',
|
||||
'digital_agc.c',
|
||||
'digital_agc.h',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
58
webrtc/modules/audio_processing/agc/agc.h
Normal file
58
webrtc/modules/audio_processing/agc/agc.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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_MODULES_AUDIO_PROCESSING_AGC_AGC_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_AGC_H_
|
||||
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/modules/audio_processing/vad/voice_activity_detector.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class AudioFrame;
|
||||
class Histogram;
|
||||
|
||||
class Agc {
|
||||
public:
|
||||
Agc();
|
||||
virtual ~Agc();
|
||||
|
||||
// Returns the proportion of samples in the buffer which are at full-scale
|
||||
// (and presumably clipped).
|
||||
virtual float AnalyzePreproc(const int16_t* audio, size_t length);
|
||||
// |audio| must be mono; in a multi-channel stream, provide the first (usually
|
||||
// left) channel.
|
||||
virtual int Process(const int16_t* audio, size_t length, int sample_rate_hz);
|
||||
|
||||
// Retrieves the difference between the target RMS level and the current
|
||||
// signal RMS level in dB. Returns true if an update is available and false
|
||||
// otherwise, in which case |error| should be ignored and no action taken.
|
||||
virtual bool GetRmsErrorDb(int* error);
|
||||
virtual void Reset();
|
||||
|
||||
virtual int set_target_level_dbfs(int level);
|
||||
virtual int target_level_dbfs() const { return target_level_dbfs_; }
|
||||
|
||||
virtual float voice_probability() const {
|
||||
return vad_.last_voice_probability();
|
||||
}
|
||||
|
||||
private:
|
||||
double target_level_loudness_;
|
||||
int target_level_dbfs_;
|
||||
rtc::scoped_ptr<Histogram> histogram_;
|
||||
rtc::scoped_ptr<Histogram> inactive_histogram_;
|
||||
VoiceActivityDetector vad_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_AGC_H_
|
||||
442
webrtc/modules/audio_processing/agc/agc_manager_direct.cc
Normal file
442
webrtc/modules/audio_processing/agc/agc_manager_direct.cc
Normal file
@@ -0,0 +1,442 @@
|
||||
/*
|
||||
* 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/modules/audio_processing/agc/agc_manager_direct.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
#include "webrtc/modules/audio_processing/agc/gain_map_internal.h"
|
||||
#include "webrtc/modules/audio_processing/gain_control_impl.h"
|
||||
#include "webrtc/modules/interface/module_common_types.h"
|
||||
#include "webrtc/system_wrappers/interface/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
// Lowest the microphone level can be lowered due to clipping.
|
||||
const int kClippedLevelMin = 170;
|
||||
// Amount the microphone level is lowered with every clipping event.
|
||||
const int kClippedLevelStep = 15;
|
||||
// Proportion of clipped samples required to declare a clipping event.
|
||||
const float kClippedRatioThreshold = 0.1f;
|
||||
// Time in frames to wait after a clipping event before checking again.
|
||||
const int kClippedWaitFrames = 300;
|
||||
|
||||
// Amount of error we tolerate in the microphone level (presumably due to OS
|
||||
// quantization) before we assume the user has manually adjusted the microphone.
|
||||
const int kLevelQuantizationSlack = 25;
|
||||
|
||||
const int kDefaultCompressionGain = 7;
|
||||
const int kMaxCompressionGain = 12;
|
||||
const int kMinCompressionGain = 2;
|
||||
// Controls the rate of compression changes towards the target.
|
||||
const float kCompressionGainStep = 0.05f;
|
||||
|
||||
const int kMaxMicLevel = 255;
|
||||
static_assert(kGainMapSize > kMaxMicLevel, "gain map too small");
|
||||
const int kMinMicLevel = 12;
|
||||
|
||||
// Prevent very large microphone level changes.
|
||||
const int kMaxResidualGainChange = 15;
|
||||
|
||||
// Maximum additional gain allowed to compensate for microphone level
|
||||
// restrictions from clipping events.
|
||||
const int kSurplusCompressionGain = 6;
|
||||
|
||||
int ClampLevel(int mic_level) {
|
||||
return std::min(std::max(kMinMicLevel, mic_level), kMaxMicLevel);
|
||||
}
|
||||
|
||||
int LevelFromGainError(int gain_error, int level) {
|
||||
assert(level >= 0 && level <= kMaxMicLevel);
|
||||
if (gain_error == 0) {
|
||||
return level;
|
||||
}
|
||||
// TODO(ajm): Could be made more efficient with a binary search.
|
||||
int new_level = level;
|
||||
if (gain_error > 0) {
|
||||
while (kGainMap[new_level] - kGainMap[level] < gain_error &&
|
||||
new_level < kMaxMicLevel) {
|
||||
++new_level;
|
||||
}
|
||||
} else {
|
||||
while (kGainMap[new_level] - kGainMap[level] > gain_error &&
|
||||
new_level > kMinMicLevel) {
|
||||
--new_level;
|
||||
}
|
||||
}
|
||||
return new_level;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Facility for dumping debug audio files. All methods are no-ops in the
|
||||
// default case where WEBRTC_AGC_DEBUG_DUMP is undefined.
|
||||
class DebugFile {
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
public:
|
||||
explicit DebugFile(const char* filename)
|
||||
: file_(fopen(filename, "wb")) {
|
||||
assert(file_);
|
||||
}
|
||||
~DebugFile() {
|
||||
fclose(file_);
|
||||
}
|
||||
void Write(const int16_t* data, size_t length_samples) {
|
||||
fwrite(data, 1, length_samples * sizeof(int16_t), file_);
|
||||
}
|
||||
private:
|
||||
FILE* file_;
|
||||
#else
|
||||
public:
|
||||
explicit DebugFile(const char* filename) {
|
||||
}
|
||||
~DebugFile() {
|
||||
}
|
||||
void Write(const int16_t* data, size_t length_samples) {
|
||||
}
|
||||
#endif // WEBRTC_AGC_DEBUG_DUMP
|
||||
};
|
||||
|
||||
AgcManagerDirect::AgcManagerDirect(GainControl* gctrl,
|
||||
VolumeCallbacks* volume_callbacks,
|
||||
int startup_min_level)
|
||||
: agc_(new Agc()),
|
||||
gctrl_(gctrl),
|
||||
volume_callbacks_(volume_callbacks),
|
||||
frames_since_clipped_(kClippedWaitFrames),
|
||||
level_(0),
|
||||
max_level_(kMaxMicLevel),
|
||||
max_compression_gain_(kMaxCompressionGain),
|
||||
target_compression_(kDefaultCompressionGain),
|
||||
compression_(target_compression_),
|
||||
compression_accumulator_(compression_),
|
||||
capture_muted_(false),
|
||||
check_volume_on_next_process_(true), // Check at startup.
|
||||
startup_(true),
|
||||
startup_min_level_(ClampLevel(startup_min_level)),
|
||||
file_preproc_(new DebugFile("agc_preproc.pcm")),
|
||||
file_postproc_(new DebugFile("agc_postproc.pcm")) {
|
||||
}
|
||||
|
||||
AgcManagerDirect::AgcManagerDirect(Agc* agc,
|
||||
GainControl* gctrl,
|
||||
VolumeCallbacks* volume_callbacks,
|
||||
int startup_min_level)
|
||||
: agc_(agc),
|
||||
gctrl_(gctrl),
|
||||
volume_callbacks_(volume_callbacks),
|
||||
frames_since_clipped_(kClippedWaitFrames),
|
||||
level_(0),
|
||||
max_level_(kMaxMicLevel),
|
||||
max_compression_gain_(kMaxCompressionGain),
|
||||
target_compression_(kDefaultCompressionGain),
|
||||
compression_(target_compression_),
|
||||
compression_accumulator_(compression_),
|
||||
capture_muted_(false),
|
||||
check_volume_on_next_process_(true), // Check at startup.
|
||||
startup_(true),
|
||||
startup_min_level_(ClampLevel(startup_min_level)),
|
||||
file_preproc_(new DebugFile("agc_preproc.pcm")),
|
||||
file_postproc_(new DebugFile("agc_postproc.pcm")) {
|
||||
}
|
||||
|
||||
AgcManagerDirect::~AgcManagerDirect() {}
|
||||
|
||||
int AgcManagerDirect::Initialize() {
|
||||
max_level_ = kMaxMicLevel;
|
||||
max_compression_gain_ = kMaxCompressionGain;
|
||||
target_compression_ = kDefaultCompressionGain;
|
||||
compression_ = target_compression_;
|
||||
compression_accumulator_ = compression_;
|
||||
capture_muted_ = false;
|
||||
check_volume_on_next_process_ = true;
|
||||
// TODO(bjornv): Investigate if we need to reset |startup_| as well. For
|
||||
// example, what happens when we change devices.
|
||||
|
||||
if (gctrl_->set_mode(GainControl::kFixedDigital) != 0) {
|
||||
LOG_FERR1(LS_ERROR, set_mode, GainControl::kFixedDigital);
|
||||
return -1;
|
||||
}
|
||||
if (gctrl_->set_target_level_dbfs(2) != 0) {
|
||||
LOG_FERR1(LS_ERROR, set_target_level_dbfs, 2);
|
||||
return -1;
|
||||
}
|
||||
if (gctrl_->set_compression_gain_db(kDefaultCompressionGain) != 0) {
|
||||
LOG_FERR1(LS_ERROR, set_compression_gain_db, kDefaultCompressionGain);
|
||||
return -1;
|
||||
}
|
||||
if (gctrl_->enable_limiter(true) != 0) {
|
||||
LOG_FERR1(LS_ERROR, enable_limiter, true);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AgcManagerDirect::AnalyzePreProcess(int16_t* audio,
|
||||
int num_channels,
|
||||
size_t samples_per_channel) {
|
||||
size_t length = num_channels * samples_per_channel;
|
||||
if (capture_muted_) {
|
||||
return;
|
||||
}
|
||||
|
||||
file_preproc_->Write(audio, length);
|
||||
|
||||
if (frames_since_clipped_ < kClippedWaitFrames) {
|
||||
++frames_since_clipped_;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for clipped samples, as the AGC has difficulty detecting pitch
|
||||
// under clipping distortion. We do this in the preprocessing phase in order
|
||||
// to catch clipped echo as well.
|
||||
//
|
||||
// If we find a sufficiently clipped frame, drop the current microphone level
|
||||
// and enforce a new maximum level, dropped the same amount from the current
|
||||
// maximum. This harsh treatment is an effort to avoid repeated clipped echo
|
||||
// events. As compensation for this restriction, the maximum compression
|
||||
// gain is increased, through SetMaxLevel().
|
||||
float clipped_ratio = agc_->AnalyzePreproc(audio, length);
|
||||
if (clipped_ratio > kClippedRatioThreshold) {
|
||||
LOG(LS_INFO) << "[agc] Clipping detected. clipped_ratio="
|
||||
<< clipped_ratio;
|
||||
// Always decrease the maximum level, even if the current level is below
|
||||
// threshold.
|
||||
SetMaxLevel(std::max(kClippedLevelMin, max_level_ - kClippedLevelStep));
|
||||
if (level_ > kClippedLevelMin) {
|
||||
// Don't try to adjust the level if we're already below the limit. As
|
||||
// a consequence, if the user has brought the level above the limit, we
|
||||
// will still not react until the postproc updates the level.
|
||||
SetLevel(std::max(kClippedLevelMin, level_ - kClippedLevelStep));
|
||||
// Reset the AGC since the level has changed.
|
||||
agc_->Reset();
|
||||
}
|
||||
frames_since_clipped_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void AgcManagerDirect::Process(const int16_t* audio,
|
||||
size_t length,
|
||||
int sample_rate_hz) {
|
||||
if (capture_muted_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (check_volume_on_next_process_) {
|
||||
check_volume_on_next_process_ = false;
|
||||
// We have to wait until the first process call to check the volume,
|
||||
// because Chromium doesn't guarantee it to be valid any earlier.
|
||||
CheckVolumeAndReset();
|
||||
}
|
||||
|
||||
if (agc_->Process(audio, length, sample_rate_hz) != 0) {
|
||||
LOG_FERR0(LS_ERROR, Agc::Process);
|
||||
assert(false);
|
||||
}
|
||||
|
||||
UpdateGain();
|
||||
UpdateCompressor();
|
||||
|
||||
file_postproc_->Write(audio, length);
|
||||
}
|
||||
|
||||
void AgcManagerDirect::SetLevel(int new_level) {
|
||||
int voe_level = volume_callbacks_->GetMicVolume();
|
||||
if (voe_level < 0) {
|
||||
return;
|
||||
}
|
||||
if (voe_level == 0) {
|
||||
LOG(LS_INFO) << "[agc] VolumeCallbacks returned level=0, taking no action.";
|
||||
return;
|
||||
}
|
||||
if (voe_level > kMaxMicLevel) {
|
||||
LOG(LS_ERROR) << "VolumeCallbacks returned an invalid level=" << voe_level;
|
||||
return;
|
||||
}
|
||||
|
||||
if (voe_level > level_ + kLevelQuantizationSlack ||
|
||||
voe_level < level_ - kLevelQuantizationSlack) {
|
||||
LOG(LS_INFO) << "[agc] Mic volume was manually adjusted. Updating "
|
||||
<< "stored level from " << level_ << " to " << voe_level;
|
||||
level_ = voe_level;
|
||||
// Always allow the user to increase the volume.
|
||||
if (level_ > max_level_) {
|
||||
SetMaxLevel(level_);
|
||||
}
|
||||
// Take no action in this case, since we can't be sure when the volume
|
||||
// was manually adjusted. The compressor will still provide some of the
|
||||
// desired gain change.
|
||||
agc_->Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
new_level = std::min(new_level, max_level_);
|
||||
if (new_level == level_) {
|
||||
return;
|
||||
}
|
||||
|
||||
volume_callbacks_->SetMicVolume(new_level);
|
||||
LOG(LS_INFO) << "[agc] voe_level=" << voe_level << ", "
|
||||
<< "level_=" << level_ << ", "
|
||||
<< "new_level=" << new_level;
|
||||
level_ = new_level;
|
||||
}
|
||||
|
||||
void AgcManagerDirect::SetMaxLevel(int level) {
|
||||
assert(level >= kClippedLevelMin);
|
||||
max_level_ = level;
|
||||
// Scale the |kSurplusCompressionGain| linearly across the restricted
|
||||
// level range.
|
||||
max_compression_gain_ = kMaxCompressionGain + std::floor(
|
||||
(1.f * kMaxMicLevel - max_level_) / (kMaxMicLevel - kClippedLevelMin) *
|
||||
kSurplusCompressionGain + 0.5f);
|
||||
LOG(LS_INFO) << "[agc] max_level_=" << max_level_
|
||||
<< ", max_compression_gain_=" << max_compression_gain_;
|
||||
}
|
||||
|
||||
void AgcManagerDirect::SetCaptureMuted(bool muted) {
|
||||
if (capture_muted_ == muted) {
|
||||
return;
|
||||
}
|
||||
capture_muted_ = muted;
|
||||
|
||||
if (!muted) {
|
||||
// When we unmute, we should reset things to be safe.
|
||||
check_volume_on_next_process_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
float AgcManagerDirect::voice_probability() {
|
||||
return agc_->voice_probability();
|
||||
}
|
||||
|
||||
int AgcManagerDirect::CheckVolumeAndReset() {
|
||||
int level = volume_callbacks_->GetMicVolume();
|
||||
if (level < 0) {
|
||||
return -1;
|
||||
}
|
||||
// Reasons for taking action at startup:
|
||||
// 1) A person starting a call is expected to be heard.
|
||||
// 2) Independent of interpretation of |level| == 0 we should raise it so the
|
||||
// AGC can do its job properly.
|
||||
if (level == 0 && !startup_) {
|
||||
LOG(LS_INFO) << "[agc] VolumeCallbacks returned level=0, taking no action.";
|
||||
return 0;
|
||||
}
|
||||
if (level > kMaxMicLevel) {
|
||||
LOG(LS_ERROR) << "VolumeCallbacks returned an invalid level=" << level;
|
||||
return -1;
|
||||
}
|
||||
LOG(LS_INFO) << "[agc] Initial GetMicVolume()=" << level;
|
||||
|
||||
int minLevel = startup_ ? startup_min_level_ : kMinMicLevel;
|
||||
if (level < minLevel) {
|
||||
level = minLevel;
|
||||
LOG(LS_INFO) << "[agc] Initial volume too low, raising to " << level;
|
||||
volume_callbacks_->SetMicVolume(level);
|
||||
}
|
||||
agc_->Reset();
|
||||
level_ = level;
|
||||
startup_ = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Requests the RMS error from AGC and distributes the required gain change
|
||||
// between the digital compression stage and volume slider. We use the
|
||||
// compressor first, providing a slack region around the current slider
|
||||
// position to reduce movement.
|
||||
//
|
||||
// If the slider needs to be moved, we check first if the user has adjusted
|
||||
// it, in which case we take no action and cache the updated level.
|
||||
void AgcManagerDirect::UpdateGain() {
|
||||
int rms_error = 0;
|
||||
if (!agc_->GetRmsErrorDb(&rms_error)) {
|
||||
// No error update ready.
|
||||
return;
|
||||
}
|
||||
// The compressor will always add at least kMinCompressionGain. In effect,
|
||||
// this adjusts our target gain upward by the same amount and rms_error
|
||||
// needs to reflect that.
|
||||
rms_error += kMinCompressionGain;
|
||||
|
||||
// Handle as much error as possible with the compressor first.
|
||||
int raw_compression = std::max(std::min(rms_error, max_compression_gain_),
|
||||
kMinCompressionGain);
|
||||
// Deemphasize the compression gain error. Move halfway between the current
|
||||
// target and the newly received target. This serves to soften perceptible
|
||||
// intra-talkspurt adjustments, at the cost of some adaptation speed.
|
||||
if ((raw_compression == max_compression_gain_ &&
|
||||
target_compression_ == max_compression_gain_ - 1) ||
|
||||
(raw_compression == kMinCompressionGain &&
|
||||
target_compression_ == kMinCompressionGain + 1)) {
|
||||
// Special case to allow the target to reach the endpoints of the
|
||||
// compression range. The deemphasis would otherwise halt it at 1 dB shy.
|
||||
target_compression_ = raw_compression;
|
||||
} else {
|
||||
target_compression_ = (raw_compression - target_compression_) / 2
|
||||
+ target_compression_;
|
||||
}
|
||||
|
||||
// Residual error will be handled by adjusting the volume slider. Use the
|
||||
// raw rather than deemphasized compression here as we would otherwise
|
||||
// shrink the amount of slack the compressor provides.
|
||||
int residual_gain = rms_error - raw_compression;
|
||||
residual_gain = std::min(std::max(residual_gain, -kMaxResidualGainChange),
|
||||
kMaxResidualGainChange);
|
||||
LOG(LS_INFO) << "[agc] rms_error=" << rms_error << ", "
|
||||
<< "target_compression=" << target_compression_ << ", "
|
||||
<< "residual_gain=" << residual_gain;
|
||||
if (residual_gain == 0)
|
||||
return;
|
||||
|
||||
SetLevel(LevelFromGainError(residual_gain, level_));
|
||||
}
|
||||
|
||||
void AgcManagerDirect::UpdateCompressor() {
|
||||
if (compression_ == target_compression_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Adapt the compression gain slowly towards the target, in order to avoid
|
||||
// highly perceptible changes.
|
||||
if (target_compression_ > compression_) {
|
||||
compression_accumulator_ += kCompressionGainStep;
|
||||
} else {
|
||||
compression_accumulator_ -= kCompressionGainStep;
|
||||
}
|
||||
|
||||
// The compressor accepts integer gains in dB. Adjust the gain when
|
||||
// we've come within half a stepsize of the nearest integer. (We don't
|
||||
// check for equality due to potential floating point imprecision).
|
||||
int new_compression = compression_;
|
||||
int nearest_neighbor = std::floor(compression_accumulator_ + 0.5);
|
||||
if (std::fabs(compression_accumulator_ - nearest_neighbor) <
|
||||
kCompressionGainStep / 2) {
|
||||
new_compression = nearest_neighbor;
|
||||
}
|
||||
|
||||
// Set the new compression gain.
|
||||
if (new_compression != compression_) {
|
||||
compression_ = new_compression;
|
||||
compression_accumulator_ = new_compression;
|
||||
if (gctrl_->set_compression_gain_db(compression_) != 0) {
|
||||
LOG_FERR1(LS_ERROR, set_compression_gain_db, compression_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
108
webrtc/modules/audio_processing/agc/agc_manager_direct.h
Normal file
108
webrtc/modules/audio_processing/agc/agc_manager_direct.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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_MODULES_AUDIO_PROCESSING_AGC_AGC_MANAGER_DIRECT_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_AGC_MANAGER_DIRECT_H_
|
||||
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/modules/audio_processing/agc/agc.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class AudioFrame;
|
||||
class DebugFile;
|
||||
class GainControl;
|
||||
|
||||
// Callbacks that need to be injected into AgcManagerDirect to read and control
|
||||
// the volume values. This is done to remove the VoiceEngine dependency in
|
||||
// AgcManagerDirect.
|
||||
// TODO(aluebs): Remove VolumeCallbacks.
|
||||
class VolumeCallbacks {
|
||||
public:
|
||||
virtual ~VolumeCallbacks() {}
|
||||
virtual void SetMicVolume(int volume) = 0;
|
||||
virtual int GetMicVolume() = 0;
|
||||
};
|
||||
|
||||
// Direct interface to use AGC to set volume and compression values.
|
||||
// AudioProcessing uses this interface directly to integrate the callback-less
|
||||
// AGC.
|
||||
//
|
||||
// This class is not thread-safe.
|
||||
class AgcManagerDirect final {
|
||||
public:
|
||||
// AgcManagerDirect will configure GainControl internally. The user is
|
||||
// responsible for processing the audio using it after the call to Process.
|
||||
// The operating range of startup_min_level is [12, 255] and any input value
|
||||
// outside that range will be clamped.
|
||||
AgcManagerDirect(GainControl* gctrl,
|
||||
VolumeCallbacks* volume_callbacks,
|
||||
int startup_min_level);
|
||||
// Dependency injection for testing. Don't delete |agc| as the memory is owned
|
||||
// by the manager.
|
||||
AgcManagerDirect(Agc* agc,
|
||||
GainControl* gctrl,
|
||||
VolumeCallbacks* volume_callbacks,
|
||||
int startup_min_level);
|
||||
~AgcManagerDirect();
|
||||
|
||||
int Initialize();
|
||||
void AnalyzePreProcess(int16_t* audio,
|
||||
int num_channels,
|
||||
size_t samples_per_channel);
|
||||
void Process(const int16_t* audio, size_t length, int sample_rate_hz);
|
||||
|
||||
// Call when the capture stream has been muted/unmuted. This causes the
|
||||
// manager to disregard all incoming audio; chances are good it's background
|
||||
// noise to which we'd like to avoid adapting.
|
||||
void SetCaptureMuted(bool muted);
|
||||
bool capture_muted() { return capture_muted_; }
|
||||
|
||||
float voice_probability();
|
||||
|
||||
private:
|
||||
// Sets a new microphone level, after first checking that it hasn't been
|
||||
// updated by the user, in which case no action is taken.
|
||||
void SetLevel(int new_level);
|
||||
|
||||
// Set the maximum level the AGC is allowed to apply. Also updates the
|
||||
// maximum compression gain to compensate. The level must be at least
|
||||
// |kClippedLevelMin|.
|
||||
void SetMaxLevel(int level);
|
||||
|
||||
int CheckVolumeAndReset();
|
||||
void UpdateGain();
|
||||
void UpdateCompressor();
|
||||
|
||||
rtc::scoped_ptr<Agc> agc_;
|
||||
GainControl* gctrl_;
|
||||
VolumeCallbacks* volume_callbacks_;
|
||||
|
||||
int frames_since_clipped_;
|
||||
int level_;
|
||||
int max_level_;
|
||||
int max_compression_gain_;
|
||||
int target_compression_;
|
||||
int compression_;
|
||||
float compression_accumulator_;
|
||||
bool capture_muted_;
|
||||
bool check_volume_on_next_process_;
|
||||
bool startup_;
|
||||
int startup_min_level_;
|
||||
|
||||
rtc::scoped_ptr<DebugFile> file_preproc_;
|
||||
rtc::scoped_ptr<DebugFile> file_postproc_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(AgcManagerDirect);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_AGC_MANAGER_DIRECT_H_
|
||||
@@ -1,133 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_MAIN_SOURCE_ANALOG_AGC_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_MAIN_SOURCE_ANALOG_AGC_H_
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "gain_control.h"
|
||||
#include "digital_agc.h"
|
||||
|
||||
//#define AGC_DEBUG
|
||||
//#define MIC_LEVEL_FEEDBACK
|
||||
#ifdef AGC_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
/* Analog Automatic Gain Control variables:
|
||||
* Constant declarations (inner limits inside which no changes are done)
|
||||
* In the beginning the range is narrower to widen as soon as the measure
|
||||
* 'Rxx160_LP' is inside it. Currently the starting limits are -22.2+/-1dBm0
|
||||
* and the final limits -22.2+/-2.5dBm0. These levels makes the speech signal
|
||||
* go towards -25.4dBm0 (-31.4dBov). Tuned with wbfile-31.4dBov.pcm
|
||||
* The limits are created by running the AGC with a file having the desired
|
||||
* signal level and thereafter plotting Rxx160_LP in the dBm0-domain defined
|
||||
* by out=10*log10(in/260537279.7); Set the target level to the average level
|
||||
* of our measure Rxx160_LP. Remember that the levels are in blocks of 16 in
|
||||
* Q(-7). (Example matlab code: round(db2pow(-21.2)*16/2^7) )
|
||||
*/
|
||||
#define RXX_BUFFER_LEN 10
|
||||
|
||||
static const WebRtc_Word16 kMsecSpeechInner = 520;
|
||||
static const WebRtc_Word16 kMsecSpeechOuter = 340;
|
||||
|
||||
static const WebRtc_Word16 kNormalVadThreshold = 400;
|
||||
|
||||
static const WebRtc_Word16 kAlphaShortTerm = 6; // 1 >> 6 = 0.0156
|
||||
static const WebRtc_Word16 kAlphaLongTerm = 10; // 1 >> 10 = 0.000977
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Configurable parameters/variables
|
||||
WebRtc_UWord32 fs; // Sampling frequency
|
||||
WebRtc_Word16 compressionGaindB; // Fixed gain level in dB
|
||||
WebRtc_Word16 targetLevelDbfs; // Target level in -dBfs of envelope (default -3)
|
||||
WebRtc_Word16 agcMode; // Hard coded mode (adaptAna/adaptDig/fixedDig)
|
||||
WebRtc_UWord8 limiterEnable; // Enabling limiter (on/off (default off))
|
||||
WebRtcAgc_config_t defaultConfig;
|
||||
WebRtcAgc_config_t usedConfig;
|
||||
|
||||
// General variables
|
||||
WebRtc_Word16 initFlag;
|
||||
WebRtc_Word16 lastError;
|
||||
|
||||
// Target level parameters
|
||||
// Based on the above: analogTargetLevel = round((32767*10^(-22/20))^2*16/2^7)
|
||||
WebRtc_Word32 analogTargetLevel; // = RXX_BUFFER_LEN * 846805; -22 dBfs
|
||||
WebRtc_Word32 startUpperLimit; // = RXX_BUFFER_LEN * 1066064; -21 dBfs
|
||||
WebRtc_Word32 startLowerLimit; // = RXX_BUFFER_LEN * 672641; -23 dBfs
|
||||
WebRtc_Word32 upperPrimaryLimit; // = RXX_BUFFER_LEN * 1342095; -20 dBfs
|
||||
WebRtc_Word32 lowerPrimaryLimit; // = RXX_BUFFER_LEN * 534298; -24 dBfs
|
||||
WebRtc_Word32 upperSecondaryLimit;// = RXX_BUFFER_LEN * 2677832; -17 dBfs
|
||||
WebRtc_Word32 lowerSecondaryLimit;// = RXX_BUFFER_LEN * 267783; -27 dBfs
|
||||
WebRtc_UWord16 targetIdx; // Table index for corresponding target level
|
||||
#ifdef MIC_LEVEL_FEEDBACK
|
||||
WebRtc_UWord16 targetIdxOffset; // Table index offset for level compensation
|
||||
#endif
|
||||
WebRtc_Word16 analogTarget; // Digital reference level in ENV scale
|
||||
|
||||
// Analog AGC specific variables
|
||||
WebRtc_Word32 filterState[8]; // For downsampling wb to nb
|
||||
WebRtc_Word32 upperLimit; // Upper limit for mic energy
|
||||
WebRtc_Word32 lowerLimit; // Lower limit for mic energy
|
||||
WebRtc_Word32 Rxx160w32; // Average energy for one frame
|
||||
WebRtc_Word32 Rxx16_LPw32; // Low pass filtered subframe energies
|
||||
WebRtc_Word32 Rxx160_LPw32; // Low pass filtered frame energies
|
||||
WebRtc_Word32 Rxx16_LPw32Max; // Keeps track of largest energy subframe
|
||||
WebRtc_Word32 Rxx16_vectorw32[RXX_BUFFER_LEN];// Array with subframe energies
|
||||
WebRtc_Word32 Rxx16w32_array[2][5];// Energy values of microphone signal
|
||||
WebRtc_Word32 env[2][10]; // Envelope values of subframes
|
||||
|
||||
WebRtc_Word16 Rxx16pos; // Current position in the Rxx16_vectorw32
|
||||
WebRtc_Word16 envSum; // Filtered scaled envelope in subframes
|
||||
WebRtc_Word16 vadThreshold; // Threshold for VAD decision
|
||||
WebRtc_Word16 inActive; // Inactive time in milliseconds
|
||||
WebRtc_Word16 msTooLow; // Milliseconds of speech at a too low level
|
||||
WebRtc_Word16 msTooHigh; // Milliseconds of speech at a too high level
|
||||
WebRtc_Word16 changeToSlowMode; // Change to slow mode after some time at target
|
||||
WebRtc_Word16 firstCall; // First call to the process-function
|
||||
WebRtc_Word16 msZero; // Milliseconds of zero input
|
||||
WebRtc_Word16 msecSpeechOuterChange;// Min ms of speech between volume changes
|
||||
WebRtc_Word16 msecSpeechInnerChange;// Min ms of speech between volume changes
|
||||
WebRtc_Word16 activeSpeech; // Milliseconds of active speech
|
||||
WebRtc_Word16 muteGuardMs; // Counter to prevent mute action
|
||||
WebRtc_Word16 inQueue; // 10 ms batch indicator
|
||||
|
||||
// Microphone level variables
|
||||
WebRtc_Word32 micRef; // Remember ref. mic level for virtual mic
|
||||
WebRtc_UWord16 gainTableIdx; // Current position in virtual gain table
|
||||
WebRtc_Word32 micGainIdx; // Gain index of mic level to increase slowly
|
||||
WebRtc_Word32 micVol; // Remember volume between frames
|
||||
WebRtc_Word32 maxLevel; // Max possible vol level, incl dig gain
|
||||
WebRtc_Word32 maxAnalog; // Maximum possible analog volume level
|
||||
WebRtc_Word32 maxInit; // Initial value of "max"
|
||||
WebRtc_Word32 minLevel; // Minimum possible volume level
|
||||
WebRtc_Word32 minOutput; // Minimum output volume level
|
||||
WebRtc_Word32 zeroCtrlMax; // Remember max gain => don't amp low input
|
||||
|
||||
WebRtc_Word16 scale; // Scale factor for internal volume levels
|
||||
#ifdef MIC_LEVEL_FEEDBACK
|
||||
WebRtc_Word16 numBlocksMicLvlSat;
|
||||
WebRtc_UWord8 micLvlSat;
|
||||
#endif
|
||||
// Structs for VAD and digital_agc
|
||||
AgcVad_t vadMic;
|
||||
DigitalAgc_t digitalAgc;
|
||||
|
||||
#ifdef AGC_DEBUG
|
||||
FILE* fpt;
|
||||
FILE* agcLog;
|
||||
WebRtc_Word32 fcount;
|
||||
#endif
|
||||
|
||||
WebRtc_Word16 lowLevelSignal;
|
||||
} Agc_t;
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_MAIN_SOURCE_ANALOG_AGC_H_
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_MAIN_SOURCE_DIGITAL_AGC_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_MAIN_SOURCE_DIGITAL_AGC_H_
|
||||
|
||||
#ifdef AGC_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include "typedefs.h"
|
||||
#include "signal_processing_library.h"
|
||||
|
||||
// the 32 most significant bits of A(19) * B(26) >> 13
|
||||
#define AGC_MUL32(A, B) (((B)>>13)*(A) + ( ((0x00001FFF & (B))*(A)) >> 13 ))
|
||||
// C + the 32 most significant bits of A * B
|
||||
#define AGC_SCALEDIFF32(A, B, C) ((C) + ((B)>>16)*(A) + ( ((0x0000FFFF & (B))*(A)) >> 16 ))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WebRtc_Word32 downState[8];
|
||||
WebRtc_Word16 HPstate;
|
||||
WebRtc_Word16 counter;
|
||||
WebRtc_Word16 logRatio; // log( P(active) / P(inactive) ) (Q10)
|
||||
WebRtc_Word16 meanLongTerm; // Q10
|
||||
WebRtc_Word32 varianceLongTerm; // Q8
|
||||
WebRtc_Word16 stdLongTerm; // Q10
|
||||
WebRtc_Word16 meanShortTerm; // Q10
|
||||
WebRtc_Word32 varianceShortTerm; // Q8
|
||||
WebRtc_Word16 stdShortTerm; // Q10
|
||||
} AgcVad_t; // total = 54 bytes
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WebRtc_Word32 capacitorSlow;
|
||||
WebRtc_Word32 capacitorFast;
|
||||
WebRtc_Word32 gain;
|
||||
WebRtc_Word32 gainTable[32];
|
||||
WebRtc_Word16 gatePrevious;
|
||||
WebRtc_Word16 agcMode;
|
||||
AgcVad_t vadNearend;
|
||||
AgcVad_t vadFarend;
|
||||
#ifdef AGC_DEBUG
|
||||
FILE* logFile;
|
||||
int frameCounter;
|
||||
#endif
|
||||
} DigitalAgc_t;
|
||||
|
||||
WebRtc_Word32 WebRtcAgc_InitDigital(DigitalAgc_t *digitalAgcInst, WebRtc_Word16 agcMode);
|
||||
|
||||
WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *digitalAgcInst, const WebRtc_Word16 *inNear,
|
||||
const WebRtc_Word16 *inNear_H, WebRtc_Word16 *out,
|
||||
WebRtc_Word16 *out_H, WebRtc_UWord32 FS,
|
||||
WebRtc_Word16 lowLevelSignal);
|
||||
|
||||
WebRtc_Word32 WebRtcAgc_AddFarendToDigital(DigitalAgc_t *digitalAgcInst, const WebRtc_Word16 *inFar,
|
||||
WebRtc_Word16 nrSamples);
|
||||
|
||||
void WebRtcAgc_InitVad(AgcVad_t *vadInst);
|
||||
|
||||
WebRtc_Word16 WebRtcAgc_ProcessVad(AgcVad_t *vadInst, // (i) VAD state
|
||||
const WebRtc_Word16 *in, // (i) Speech signal
|
||||
WebRtc_Word16 nrSamples); // (i) number of samples
|
||||
|
||||
WebRtc_Word32 WebRtcAgc_CalculateGainTable(WebRtc_Word32 *gainTable, // Q16
|
||||
WebRtc_Word16 compressionGaindB, // Q0 (in dB)
|
||||
WebRtc_Word16 targetLevelDbfs,// Q0 (in dB)
|
||||
WebRtc_UWord8 limiterEnable, WebRtc_Word16 analogTarget);
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_MAIN_SOURCE_ANALOG_AGC_H_
|
||||
275
webrtc/modules/audio_processing/agc/gain_map_internal.h
Normal file
275
webrtc/modules/audio_processing/agc/gain_map_internal.h
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* 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_MODULES_AUDIO_PROCESSING_AGC_GAIN_MAP_INTERNAL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_GAIN_MAP_INTERNAL_H_
|
||||
|
||||
static const int kGainMapSize = 256;
|
||||
// Uses parameters: si = 2, sf = 0.25, D = 8/256
|
||||
static const int kGainMap[kGainMapSize] = {
|
||||
-56,
|
||||
-54,
|
||||
-52,
|
||||
-50,
|
||||
-48,
|
||||
-47,
|
||||
-45,
|
||||
-43,
|
||||
-42,
|
||||
-40,
|
||||
-38,
|
||||
-37,
|
||||
-35,
|
||||
-34,
|
||||
-33,
|
||||
-31,
|
||||
-30,
|
||||
-29,
|
||||
-27,
|
||||
-26,
|
||||
-25,
|
||||
-24,
|
||||
-23,
|
||||
-22,
|
||||
-20,
|
||||
-19,
|
||||
-18,
|
||||
-17,
|
||||
-16,
|
||||
-15,
|
||||
-14,
|
||||
-14,
|
||||
-13,
|
||||
-12,
|
||||
-11,
|
||||
-10,
|
||||
-9,
|
||||
-8,
|
||||
-8,
|
||||
-7,
|
||||
-6,
|
||||
-5,
|
||||
-5,
|
||||
-4,
|
||||
-3,
|
||||
-2,
|
||||
-2,
|
||||
-1,
|
||||
0,
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
3,
|
||||
4,
|
||||
4,
|
||||
5,
|
||||
5,
|
||||
6,
|
||||
6,
|
||||
7,
|
||||
7,
|
||||
8,
|
||||
8,
|
||||
9,
|
||||
9,
|
||||
10,
|
||||
10,
|
||||
11,
|
||||
11,
|
||||
12,
|
||||
12,
|
||||
13,
|
||||
13,
|
||||
13,
|
||||
14,
|
||||
14,
|
||||
15,
|
||||
15,
|
||||
15,
|
||||
16,
|
||||
16,
|
||||
17,
|
||||
17,
|
||||
17,
|
||||
18,
|
||||
18,
|
||||
18,
|
||||
19,
|
||||
19,
|
||||
19,
|
||||
20,
|
||||
20,
|
||||
21,
|
||||
21,
|
||||
21,
|
||||
22,
|
||||
22,
|
||||
22,
|
||||
23,
|
||||
23,
|
||||
23,
|
||||
24,
|
||||
24,
|
||||
24,
|
||||
24,
|
||||
25,
|
||||
25,
|
||||
25,
|
||||
26,
|
||||
26,
|
||||
26,
|
||||
27,
|
||||
27,
|
||||
27,
|
||||
28,
|
||||
28,
|
||||
28,
|
||||
28,
|
||||
29,
|
||||
29,
|
||||
29,
|
||||
30,
|
||||
30,
|
||||
30,
|
||||
30,
|
||||
31,
|
||||
31,
|
||||
31,
|
||||
32,
|
||||
32,
|
||||
32,
|
||||
32,
|
||||
33,
|
||||
33,
|
||||
33,
|
||||
33,
|
||||
34,
|
||||
34,
|
||||
34,
|
||||
35,
|
||||
35,
|
||||
35,
|
||||
35,
|
||||
36,
|
||||
36,
|
||||
36,
|
||||
36,
|
||||
37,
|
||||
37,
|
||||
37,
|
||||
38,
|
||||
38,
|
||||
38,
|
||||
38,
|
||||
39,
|
||||
39,
|
||||
39,
|
||||
39,
|
||||
40,
|
||||
40,
|
||||
40,
|
||||
40,
|
||||
41,
|
||||
41,
|
||||
41,
|
||||
41,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
42,
|
||||
43,
|
||||
43,
|
||||
43,
|
||||
44,
|
||||
44,
|
||||
44,
|
||||
44,
|
||||
45,
|
||||
45,
|
||||
45,
|
||||
45,
|
||||
46,
|
||||
46,
|
||||
46,
|
||||
46,
|
||||
47,
|
||||
47,
|
||||
47,
|
||||
47,
|
||||
48,
|
||||
48,
|
||||
48,
|
||||
48,
|
||||
49,
|
||||
49,
|
||||
49,
|
||||
49,
|
||||
50,
|
||||
50,
|
||||
50,
|
||||
50,
|
||||
51,
|
||||
51,
|
||||
51,
|
||||
51,
|
||||
52,
|
||||
52,
|
||||
52,
|
||||
52,
|
||||
53,
|
||||
53,
|
||||
53,
|
||||
53,
|
||||
54,
|
||||
54,
|
||||
54,
|
||||
54,
|
||||
55,
|
||||
55,
|
||||
55,
|
||||
55,
|
||||
56,
|
||||
56,
|
||||
56,
|
||||
56,
|
||||
57,
|
||||
57,
|
||||
57,
|
||||
57,
|
||||
58,
|
||||
58,
|
||||
58,
|
||||
58,
|
||||
59,
|
||||
59,
|
||||
59,
|
||||
59,
|
||||
60,
|
||||
60,
|
||||
60,
|
||||
60,
|
||||
61,
|
||||
61,
|
||||
61,
|
||||
61,
|
||||
62,
|
||||
62,
|
||||
62,
|
||||
62,
|
||||
63,
|
||||
63,
|
||||
63,
|
||||
63,
|
||||
64
|
||||
};
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_GAIN_MAP_INTERNAL_H_
|
||||
228
webrtc/modules/audio_processing/agc/histogram.cc
Normal file
228
webrtc/modules/audio_processing/agc/histogram.cc
Normal file
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* 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/modules/audio_processing/agc/histogram.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
#include "webrtc/modules/interface/module_common_types.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
static const double kHistBinCenters[] = {
|
||||
7.59621091765857e-02, 9.02036021061016e-02, 1.07115112009343e-01,
|
||||
1.27197217770508e-01, 1.51044347572047e-01, 1.79362373905283e-01,
|
||||
2.12989507320644e-01, 2.52921107370304e-01, 3.00339145144454e-01,
|
||||
3.56647189489147e-01, 4.23511952494003e-01, 5.02912623991786e-01,
|
||||
5.97199455365749e-01, 7.09163326739184e-01, 8.42118356728544e-01,
|
||||
1.00000000000000e+00, 1.18748153630660e+00, 1.41011239906908e+00,
|
||||
1.67448243801153e+00, 1.98841697800836e+00, 2.36120844786349e+00,
|
||||
2.80389143520905e+00, 3.32956930911896e+00, 3.95380207843188e+00,
|
||||
4.69506696634852e+00, 5.57530533426190e+00, 6.62057214370769e+00,
|
||||
7.86180718043869e+00, 9.33575086877358e+00, 1.10860317842269e+01,
|
||||
1.31644580546776e+01, 1.56325508754123e+01, 1.85633655299256e+01,
|
||||
2.20436538184971e+01, 2.61764319021997e+01, 3.10840295702492e+01,
|
||||
3.69117111886792e+01, 4.38319755100383e+01, 5.20496616180135e+01,
|
||||
6.18080121423973e+01, 7.33958732149108e+01, 8.71562442838066e+01,
|
||||
1.03496430860848e+02, 1.22900100720889e+02, 1.45941600416277e+02,
|
||||
1.73302955873365e+02, 2.05794060286978e+02, 2.44376646872353e+02,
|
||||
2.90192756065437e+02, 3.44598539797631e+02, 4.09204403447902e+02,
|
||||
4.85922673669740e+02, 5.77024203055553e+02, 6.85205587130498e+02,
|
||||
8.13668983291589e+02, 9.66216894324125e+02, 1.14736472207740e+03,
|
||||
1.36247442287647e+03, 1.61791322085579e+03, 1.92124207711260e+03,
|
||||
2.28143949334655e+03, 2.70916727454970e+03, 3.21708611729384e+03,
|
||||
3.82023036499473e+03, 4.53645302286906e+03, 5.38695420497926e+03,
|
||||
6.39690865534207e+03, 7.59621091765857e+03, 9.02036021061016e+03,
|
||||
1.07115112009343e+04, 1.27197217770508e+04, 1.51044347572047e+04,
|
||||
1.79362373905283e+04, 2.12989507320644e+04, 2.52921107370304e+04,
|
||||
3.00339145144454e+04, 3.56647189489147e+04};
|
||||
|
||||
static const double kProbQDomain = 1024.0;
|
||||
// Loudness of -15 dB (smallest expected loudness) in log domain,
|
||||
// loudness_db = 13.5 * log10(rms);
|
||||
static const double kLogDomainMinBinCenter = -2.57752062648587;
|
||||
// Loudness step of 1 dB in log domain
|
||||
static const double kLogDomainStepSizeInverse = 5.81954605750359;
|
||||
|
||||
static const int kTransientWidthThreshold = 7;
|
||||
static const double kLowProbabilityThreshold = 0.2;
|
||||
|
||||
static const int kLowProbThresholdQ10 = static_cast<int>(
|
||||
kLowProbabilityThreshold * kProbQDomain);
|
||||
|
||||
Histogram::Histogram()
|
||||
: num_updates_(0),
|
||||
audio_content_q10_(0),
|
||||
bin_count_q10_(),
|
||||
activity_probability_(),
|
||||
hist_bin_index_(),
|
||||
buffer_index_(0),
|
||||
buffer_is_full_(false),
|
||||
len_circular_buffer_(0),
|
||||
len_high_activity_(0) {
|
||||
static_assert(
|
||||
kHistSize == sizeof(kHistBinCenters) / sizeof(kHistBinCenters[0]),
|
||||
"histogram bin centers incorrect size");
|
||||
}
|
||||
|
||||
Histogram::Histogram(int window_size)
|
||||
: num_updates_(0),
|
||||
audio_content_q10_(0),
|
||||
bin_count_q10_(),
|
||||
activity_probability_(new int[window_size]),
|
||||
hist_bin_index_(new int[window_size]),
|
||||
buffer_index_(0),
|
||||
buffer_is_full_(false),
|
||||
len_circular_buffer_(window_size),
|
||||
len_high_activity_(0) {}
|
||||
|
||||
Histogram::~Histogram() {}
|
||||
|
||||
void Histogram::Update(double rms, double activity_probaility) {
|
||||
// If circular histogram is activated then remove the oldest entry.
|
||||
if (len_circular_buffer_ > 0)
|
||||
RemoveOldestEntryAndUpdate();
|
||||
|
||||
// Find the corresponding bin.
|
||||
int hist_index = GetBinIndex(rms);
|
||||
// To Q10 domain.
|
||||
int prob_q10 = static_cast<int16_t>(floor(activity_probaility *
|
||||
kProbQDomain));
|
||||
InsertNewestEntryAndUpdate(prob_q10, hist_index);
|
||||
}
|
||||
|
||||
// Doing nothing if buffer is not full, yet.
|
||||
void Histogram::RemoveOldestEntryAndUpdate() {
|
||||
assert(len_circular_buffer_ > 0);
|
||||
// Do nothing if circular buffer is not full.
|
||||
if (!buffer_is_full_)
|
||||
return;
|
||||
|
||||
int oldest_prob = activity_probability_[buffer_index_];
|
||||
int oldest_hist_index = hist_bin_index_[buffer_index_];
|
||||
UpdateHist(-oldest_prob, oldest_hist_index);
|
||||
}
|
||||
|
||||
void Histogram::RemoveTransient() {
|
||||
// Don't expect to be here if high-activity region is longer than
|
||||
// |kTransientWidthThreshold| or there has not been any transient.
|
||||
assert(len_high_activity_ <= kTransientWidthThreshold);
|
||||
int index = (buffer_index_ > 0) ? (buffer_index_ - 1) :
|
||||
len_circular_buffer_ - 1;
|
||||
while (len_high_activity_ > 0) {
|
||||
UpdateHist(-activity_probability_[index], hist_bin_index_[index]);
|
||||
activity_probability_[index] = 0;
|
||||
index = (index > 0) ? (index - 1) : (len_circular_buffer_ - 1);
|
||||
len_high_activity_--;
|
||||
}
|
||||
}
|
||||
|
||||
void Histogram::InsertNewestEntryAndUpdate(int activity_prob_q10,
|
||||
int hist_index) {
|
||||
// Update the circular buffer if it is enabled.
|
||||
if (len_circular_buffer_ > 0) {
|
||||
// Removing transient.
|
||||
if (activity_prob_q10 <= kLowProbThresholdQ10) {
|
||||
// Lower than threshold probability, set it to zero.
|
||||
activity_prob_q10 = 0;
|
||||
// Check if this has been a transient.
|
||||
if (len_high_activity_ <= kTransientWidthThreshold)
|
||||
RemoveTransient(); // Remove this transient.
|
||||
len_high_activity_ = 0;
|
||||
} else if (len_high_activity_ <= kTransientWidthThreshold) {
|
||||
len_high_activity_++;
|
||||
}
|
||||
// Updating the circular buffer.
|
||||
activity_probability_[buffer_index_] = activity_prob_q10;
|
||||
hist_bin_index_[buffer_index_] = hist_index;
|
||||
// Increment the buffer index and check for wrap-around.
|
||||
buffer_index_++;
|
||||
if (buffer_index_ >= len_circular_buffer_) {
|
||||
buffer_index_ = 0;
|
||||
buffer_is_full_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
num_updates_++;
|
||||
if (num_updates_ < 0)
|
||||
num_updates_--;
|
||||
|
||||
UpdateHist(activity_prob_q10, hist_index);
|
||||
}
|
||||
|
||||
void Histogram::UpdateHist(int activity_prob_q10, int hist_index) {
|
||||
bin_count_q10_[hist_index] += activity_prob_q10;
|
||||
audio_content_q10_ += activity_prob_q10;
|
||||
}
|
||||
|
||||
double Histogram::AudioContent() const {
|
||||
return audio_content_q10_ / kProbQDomain;
|
||||
}
|
||||
|
||||
Histogram* Histogram::Create() {
|
||||
return new Histogram;
|
||||
}
|
||||
|
||||
Histogram* Histogram::Create(int window_size) {
|
||||
if (window_size < 0)
|
||||
return NULL;
|
||||
return new Histogram(window_size);
|
||||
}
|
||||
|
||||
void Histogram::Reset() {
|
||||
// Reset the histogram, audio-content and number of updates.
|
||||
memset(bin_count_q10_, 0, sizeof(bin_count_q10_));
|
||||
audio_content_q10_ = 0;
|
||||
num_updates_ = 0;
|
||||
// Empty the circular buffer.
|
||||
buffer_index_ = 0;
|
||||
buffer_is_full_ = false;
|
||||
len_high_activity_ = 0;
|
||||
}
|
||||
|
||||
int Histogram::GetBinIndex(double rms) {
|
||||
// First exclude overload cases.
|
||||
if (rms <= kHistBinCenters[0]) {
|
||||
return 0;
|
||||
} else if (rms >= kHistBinCenters[kHistSize - 1]) {
|
||||
return kHistSize - 1;
|
||||
} else {
|
||||
// The quantizer is uniform in log domain. Alternatively we could do binary
|
||||
// search in linear domain.
|
||||
double rms_log = log(rms);
|
||||
|
||||
int index = static_cast<int>(floor((rms_log - kLogDomainMinBinCenter) *
|
||||
kLogDomainStepSizeInverse));
|
||||
// The final decision is in linear domain.
|
||||
double b = 0.5 * (kHistBinCenters[index] + kHistBinCenters[index + 1]);
|
||||
if (rms > b) {
|
||||
return index + 1;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
double Histogram::CurrentRms() const {
|
||||
double p;
|
||||
double mean_val = 0;
|
||||
if (audio_content_q10_ > 0) {
|
||||
double p_total_inverse = 1. / static_cast<double>(audio_content_q10_);
|
||||
for (int n = 0; n < kHistSize; n++) {
|
||||
p = static_cast<double>(bin_count_q10_[n]) * p_total_inverse;
|
||||
mean_val += p * kHistBinCenters[n];
|
||||
}
|
||||
} else {
|
||||
mean_val = kHistBinCenters[0];
|
||||
}
|
||||
return mean_val;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
91
webrtc/modules/audio_processing/agc/histogram.h
Normal file
91
webrtc/modules/audio_processing/agc/histogram.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_HISTOGRAM_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_HISTOGRAM_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// This class implements the histogram of loudness with circular buffers so that
|
||||
// the histogram tracks the last T seconds of the loudness.
|
||||
class Histogram {
|
||||
public:
|
||||
// Create a non-sliding Histogram.
|
||||
static Histogram* Create();
|
||||
|
||||
// Create a sliding Histogram, i.e. the histogram represents the last
|
||||
// |window_size| samples.
|
||||
static Histogram* Create(int window_size);
|
||||
~Histogram();
|
||||
|
||||
// Insert RMS and the corresponding activity probability.
|
||||
void Update(double rms, double activity_probability);
|
||||
|
||||
// Reset the histogram, forget the past.
|
||||
void Reset();
|
||||
|
||||
// Current loudness, which is actually the mean of histogram in loudness
|
||||
// domain.
|
||||
double CurrentRms() const;
|
||||
|
||||
// Sum of the histogram content.
|
||||
double AudioContent() const;
|
||||
|
||||
// Number of times the histogram has been updated.
|
||||
int num_updates() const { return num_updates_; }
|
||||
|
||||
private:
|
||||
Histogram();
|
||||
explicit Histogram(int window);
|
||||
|
||||
// Find the histogram bin associated with the given |rms|.
|
||||
int GetBinIndex(double rms);
|
||||
|
||||
void RemoveOldestEntryAndUpdate();
|
||||
void InsertNewestEntryAndUpdate(int activity_prob_q10, int hist_index);
|
||||
void UpdateHist(int activity_prob_q10, int hist_index);
|
||||
void RemoveTransient();
|
||||
|
||||
// Number of histogram bins.
|
||||
static const int kHistSize = 77;
|
||||
|
||||
// Number of times the histogram is updated
|
||||
int num_updates_;
|
||||
// Audio content, this should be equal to the sum of the components of
|
||||
// |bin_count_q10_|.
|
||||
int64_t audio_content_q10_;
|
||||
|
||||
// Histogram of input RMS in Q10 with |kHistSize_| bins. In each 'Update(),'
|
||||
// we increment the associated histogram-bin with the given probability. The
|
||||
// increment is implemented in Q10 to avoid rounding errors.
|
||||
int64_t bin_count_q10_[kHistSize];
|
||||
|
||||
// Circular buffer for probabilities
|
||||
rtc::scoped_ptr<int[]> activity_probability_;
|
||||
// Circular buffer for histogram-indices of probabilities.
|
||||
rtc::scoped_ptr<int[]> hist_bin_index_;
|
||||
// Current index of circular buffer, where the newest data will be written to,
|
||||
// therefore, pointing to the oldest data if buffer is full.
|
||||
int buffer_index_;
|
||||
// Indicating if buffer is full and we had a wrap around.
|
||||
int buffer_is_full_;
|
||||
// Size of circular buffer.
|
||||
int len_circular_buffer_;
|
||||
int len_high_activity_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_HISTOGRAM_H_
|
||||
File diff suppressed because it is too large
Load Diff
133
webrtc/modules/audio_processing/agc/legacy/analog_agc.h
Normal file
133
webrtc/modules/audio_processing/agc/legacy/analog_agc.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_ANALOG_AGC_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_ANALOG_AGC_H_
|
||||
|
||||
//#define MIC_LEVEL_FEEDBACK
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "webrtc/modules/audio_processing/agc/legacy/digital_agc.h"
|
||||
#include "webrtc/modules/audio_processing/agc/legacy/gain_control.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
/* Analog Automatic Gain Control variables:
|
||||
* Constant declarations (inner limits inside which no changes are done)
|
||||
* In the beginning the range is narrower to widen as soon as the measure
|
||||
* 'Rxx160_LP' is inside it. Currently the starting limits are -22.2+/-1dBm0
|
||||
* and the final limits -22.2+/-2.5dBm0. These levels makes the speech signal
|
||||
* go towards -25.4dBm0 (-31.4dBov). Tuned with wbfile-31.4dBov.pcm
|
||||
* The limits are created by running the AGC with a file having the desired
|
||||
* signal level and thereafter plotting Rxx160_LP in the dBm0-domain defined
|
||||
* by out=10*log10(in/260537279.7); Set the target level to the average level
|
||||
* of our measure Rxx160_LP. Remember that the levels are in blocks of 16 in
|
||||
* Q(-7). (Example matlab code: round(db2pow(-21.2)*16/2^7) )
|
||||
*/
|
||||
#define RXX_BUFFER_LEN 10
|
||||
|
||||
static const int16_t kMsecSpeechInner = 520;
|
||||
static const int16_t kMsecSpeechOuter = 340;
|
||||
|
||||
static const int16_t kNormalVadThreshold = 400;
|
||||
|
||||
static const int16_t kAlphaShortTerm = 6; // 1 >> 6 = 0.0156
|
||||
static const int16_t kAlphaLongTerm = 10; // 1 >> 10 = 0.000977
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// Configurable parameters/variables
|
||||
uint32_t fs; // Sampling frequency
|
||||
int16_t compressionGaindB; // Fixed gain level in dB
|
||||
int16_t targetLevelDbfs; // Target level in -dBfs of envelope (default -3)
|
||||
int16_t agcMode; // Hard coded mode (adaptAna/adaptDig/fixedDig)
|
||||
uint8_t limiterEnable; // Enabling limiter (on/off (default off))
|
||||
WebRtcAgcConfig defaultConfig;
|
||||
WebRtcAgcConfig usedConfig;
|
||||
|
||||
// General variables
|
||||
int16_t initFlag;
|
||||
int16_t lastError;
|
||||
|
||||
// Target level parameters
|
||||
// Based on the above: analogTargetLevel = round((32767*10^(-22/20))^2*16/2^7)
|
||||
int32_t analogTargetLevel; // = RXX_BUFFER_LEN * 846805; -22 dBfs
|
||||
int32_t startUpperLimit; // = RXX_BUFFER_LEN * 1066064; -21 dBfs
|
||||
int32_t startLowerLimit; // = RXX_BUFFER_LEN * 672641; -23 dBfs
|
||||
int32_t upperPrimaryLimit; // = RXX_BUFFER_LEN * 1342095; -20 dBfs
|
||||
int32_t lowerPrimaryLimit; // = RXX_BUFFER_LEN * 534298; -24 dBfs
|
||||
int32_t upperSecondaryLimit;// = RXX_BUFFER_LEN * 2677832; -17 dBfs
|
||||
int32_t lowerSecondaryLimit;// = RXX_BUFFER_LEN * 267783; -27 dBfs
|
||||
uint16_t targetIdx; // Table index for corresponding target level
|
||||
#ifdef MIC_LEVEL_FEEDBACK
|
||||
uint16_t targetIdxOffset; // Table index offset for level compensation
|
||||
#endif
|
||||
int16_t analogTarget; // Digital reference level in ENV scale
|
||||
|
||||
// Analog AGC specific variables
|
||||
int32_t filterState[8]; // For downsampling wb to nb
|
||||
int32_t upperLimit; // Upper limit for mic energy
|
||||
int32_t lowerLimit; // Lower limit for mic energy
|
||||
int32_t Rxx160w32; // Average energy for one frame
|
||||
int32_t Rxx16_LPw32; // Low pass filtered subframe energies
|
||||
int32_t Rxx160_LPw32; // Low pass filtered frame energies
|
||||
int32_t Rxx16_LPw32Max; // Keeps track of largest energy subframe
|
||||
int32_t Rxx16_vectorw32[RXX_BUFFER_LEN];// Array with subframe energies
|
||||
int32_t Rxx16w32_array[2][5];// Energy values of microphone signal
|
||||
int32_t env[2][10]; // Envelope values of subframes
|
||||
|
||||
int16_t Rxx16pos; // Current position in the Rxx16_vectorw32
|
||||
int16_t envSum; // Filtered scaled envelope in subframes
|
||||
int16_t vadThreshold; // Threshold for VAD decision
|
||||
int16_t inActive; // Inactive time in milliseconds
|
||||
int16_t msTooLow; // Milliseconds of speech at a too low level
|
||||
int16_t msTooHigh; // Milliseconds of speech at a too high level
|
||||
int16_t changeToSlowMode; // Change to slow mode after some time at target
|
||||
int16_t firstCall; // First call to the process-function
|
||||
int16_t msZero; // Milliseconds of zero input
|
||||
int16_t msecSpeechOuterChange;// Min ms of speech between volume changes
|
||||
int16_t msecSpeechInnerChange;// Min ms of speech between volume changes
|
||||
int16_t activeSpeech; // Milliseconds of active speech
|
||||
int16_t muteGuardMs; // Counter to prevent mute action
|
||||
int16_t inQueue; // 10 ms batch indicator
|
||||
|
||||
// Microphone level variables
|
||||
int32_t micRef; // Remember ref. mic level for virtual mic
|
||||
uint16_t gainTableIdx; // Current position in virtual gain table
|
||||
int32_t micGainIdx; // Gain index of mic level to increase slowly
|
||||
int32_t micVol; // Remember volume between frames
|
||||
int32_t maxLevel; // Max possible vol level, incl dig gain
|
||||
int32_t maxAnalog; // Maximum possible analog volume level
|
||||
int32_t maxInit; // Initial value of "max"
|
||||
int32_t minLevel; // Minimum possible volume level
|
||||
int32_t minOutput; // Minimum output volume level
|
||||
int32_t zeroCtrlMax; // Remember max gain => don't amp low input
|
||||
int32_t lastInMicLevel;
|
||||
|
||||
int16_t scale; // Scale factor for internal volume levels
|
||||
#ifdef MIC_LEVEL_FEEDBACK
|
||||
int16_t numBlocksMicLvlSat;
|
||||
uint8_t micLvlSat;
|
||||
#endif
|
||||
// Structs for VAD and digital_agc
|
||||
AgcVad vadMic;
|
||||
DigitalAgc digitalAgc;
|
||||
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
FILE* fpt;
|
||||
FILE* agcLog;
|
||||
int32_t fcount;
|
||||
#endif
|
||||
|
||||
int16_t lowLevelSignal;
|
||||
} LegacyAgc;
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_ANALOG_AGC_H_
|
||||
@@ -12,12 +12,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/audio_processing/agc/legacy/digital_agc.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#ifdef AGC_DEBUG
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include "digital_agc.h"
|
||||
#include "gain_control.h"
|
||||
|
||||
#include "webrtc/modules/audio_processing/agc/legacy/gain_control.h"
|
||||
|
||||
// To generate the gaintable, copy&paste the following lines to a Matlab window:
|
||||
// MaxGain = 6; MinGain = 0; CompRatio = 3; Knee = 1;
|
||||
@@ -33,7 +36,8 @@
|
||||
// zoom on;
|
||||
|
||||
// Generator table for y=log2(1+e^x) in Q8.
|
||||
static const WebRtc_UWord16 kGenFuncTable[128] = {
|
||||
enum { kGenFuncTableSize = 128 };
|
||||
static const uint16_t kGenFuncTable[kGenFuncTableSize] = {
|
||||
256, 485, 786, 1126, 1484, 1849, 2217, 2586,
|
||||
2955, 3324, 3693, 4063, 4432, 4801, 5171, 5540,
|
||||
5909, 6279, 6648, 7017, 7387, 7756, 8125, 8495,
|
||||
@@ -52,29 +56,29 @@ static const WebRtc_UWord16 kGenFuncTable[128] = {
|
||||
44320, 44689, 45058, 45428, 45797, 46166, 46536, 46905
|
||||
};
|
||||
|
||||
static const WebRtc_Word16 kAvgDecayTime = 250; // frames; < 3000
|
||||
static const int16_t kAvgDecayTime = 250; // frames; < 3000
|
||||
|
||||
WebRtc_Word32 WebRtcAgc_CalculateGainTable(WebRtc_Word32 *gainTable, // Q16
|
||||
WebRtc_Word16 digCompGaindB, // Q0
|
||||
WebRtc_Word16 targetLevelDbfs,// Q0
|
||||
WebRtc_UWord8 limiterEnable,
|
||||
WebRtc_Word16 analogTarget) // Q0
|
||||
int32_t WebRtcAgc_CalculateGainTable(int32_t *gainTable, // Q16
|
||||
int16_t digCompGaindB, // Q0
|
||||
int16_t targetLevelDbfs,// Q0
|
||||
uint8_t limiterEnable,
|
||||
int16_t analogTarget) // Q0
|
||||
{
|
||||
// This function generates the compressor gain table used in the fixed digital part.
|
||||
WebRtc_UWord32 tmpU32no1, tmpU32no2, absInLevel, logApprox;
|
||||
WebRtc_Word32 inLevel, limiterLvl;
|
||||
WebRtc_Word32 tmp32, tmp32no1, tmp32no2, numFIX, den, y32;
|
||||
const WebRtc_UWord16 kLog10 = 54426; // log2(10) in Q14
|
||||
const WebRtc_UWord16 kLog10_2 = 49321; // 10*log10(2) in Q14
|
||||
const WebRtc_UWord16 kLogE_1 = 23637; // log2(e) in Q14
|
||||
WebRtc_UWord16 constMaxGain;
|
||||
WebRtc_UWord16 tmpU16, intPart, fracPart;
|
||||
const WebRtc_Word16 kCompRatio = 3;
|
||||
const WebRtc_Word16 kSoftLimiterLeft = 1;
|
||||
WebRtc_Word16 limiterOffset = 0; // Limiter offset
|
||||
WebRtc_Word16 limiterIdx, limiterLvlX;
|
||||
WebRtc_Word16 constLinApprox, zeroGainLvl, maxGain, diffGain;
|
||||
WebRtc_Word16 i, tmp16, tmp16no1;
|
||||
uint32_t tmpU32no1, tmpU32no2, absInLevel, logApprox;
|
||||
int32_t inLevel, limiterLvl;
|
||||
int32_t tmp32, tmp32no1, tmp32no2, numFIX, den, y32;
|
||||
const uint16_t kLog10 = 54426; // log2(10) in Q14
|
||||
const uint16_t kLog10_2 = 49321; // 10*log10(2) in Q14
|
||||
const uint16_t kLogE_1 = 23637; // log2(e) in Q14
|
||||
uint16_t constMaxGain;
|
||||
uint16_t tmpU16, intPart, fracPart;
|
||||
const int16_t kCompRatio = 3;
|
||||
const int16_t kSoftLimiterLeft = 1;
|
||||
int16_t limiterOffset = 0; // Limiter offset
|
||||
int16_t limiterIdx, limiterLvlX;
|
||||
int16_t constLinApprox, zeroGainLvl, maxGain, diffGain;
|
||||
int16_t i, tmp16, tmp16no1;
|
||||
int zeros, zerosScale;
|
||||
|
||||
// Constants
|
||||
@@ -83,11 +87,11 @@ WebRtc_Word32 WebRtcAgc_CalculateGainTable(WebRtc_Word32 *gainTable, // Q16
|
||||
// kLog10_2 = 49321; // 10*log10(2) in Q14
|
||||
|
||||
// Calculate maximum digital gain and zero gain level
|
||||
tmp32no1 = WEBRTC_SPL_MUL_16_16(digCompGaindB - analogTarget, kCompRatio - 1);
|
||||
tmp32no1 = (digCompGaindB - analogTarget) * (kCompRatio - 1);
|
||||
tmp16no1 = analogTarget - targetLevelDbfs;
|
||||
tmp16no1 += WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio);
|
||||
maxGain = WEBRTC_SPL_MAX(tmp16no1, (analogTarget - targetLevelDbfs));
|
||||
tmp32no1 = WEBRTC_SPL_MUL_16_16(maxGain, kCompRatio);
|
||||
tmp32no1 = maxGain * kCompRatio;
|
||||
zeroGainLvl = digCompGaindB;
|
||||
zeroGainLvl -= WebRtcSpl_DivW32W16ResW16(tmp32no1 + ((kCompRatio - 1) >> 1),
|
||||
kCompRatio - 1);
|
||||
@@ -100,10 +104,11 @@ WebRtc_Word32 WebRtcAgc_CalculateGainTable(WebRtc_Word32 *gainTable, // Q16
|
||||
// Calculate the difference between maximum gain and gain at 0dB0v:
|
||||
// diffGain = maxGain + (compRatio-1)*zeroGainLvl/compRatio
|
||||
// = (compRatio-1)*digCompGaindB/compRatio
|
||||
tmp32no1 = WEBRTC_SPL_MUL_16_16(digCompGaindB, kCompRatio - 1);
|
||||
tmp32no1 = digCompGaindB * (kCompRatio - 1);
|
||||
diffGain = WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio);
|
||||
if (diffGain < 0)
|
||||
if (diffGain < 0 || diffGain >= kGenFuncTableSize)
|
||||
{
|
||||
assert(0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -111,9 +116,8 @@ WebRtc_Word32 WebRtcAgc_CalculateGainTable(WebRtc_Word32 *gainTable, // Q16
|
||||
// limiterLvlX = analogTarget - limiterOffset
|
||||
// limiterLvl = targetLevelDbfs + limiterOffset/compRatio
|
||||
limiterLvlX = analogTarget - limiterOffset;
|
||||
limiterIdx = 2
|
||||
+ WebRtcSpl_DivW32W16ResW16(WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)limiterLvlX, 13),
|
||||
WEBRTC_SPL_RSHIFT_U16(kLog10_2, 1));
|
||||
limiterIdx =
|
||||
2 + WebRtcSpl_DivW32W16ResW16((int32_t)limiterLvlX << 13, kLog10_2 / 2);
|
||||
tmp16no1 = WebRtcSpl_DivW32W16ResW16(limiterOffset + (kCompRatio >> 1), kCompRatio);
|
||||
limiterLvl = targetLevelDbfs + tmp16no1;
|
||||
|
||||
@@ -134,23 +138,23 @@ WebRtc_Word32 WebRtcAgc_CalculateGainTable(WebRtc_Word32 *gainTable, // Q16
|
||||
{
|
||||
// Calculate scaled input level (compressor):
|
||||
// inLevel = fix((-constLog10_2*(compRatio-1)*(1-i)+fix(compRatio/2))/compRatio)
|
||||
tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(kCompRatio - 1, i - 1); // Q0
|
||||
tmp16 = (int16_t)((kCompRatio - 1) * (i - 1)); // Q0
|
||||
tmp32 = WEBRTC_SPL_MUL_16_U16(tmp16, kLog10_2) + 1; // Q14
|
||||
inLevel = WebRtcSpl_DivW32W16(tmp32, kCompRatio); // Q14
|
||||
|
||||
// Calculate diffGain-inLevel, to map using the genFuncTable
|
||||
inLevel = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)diffGain, 14) - inLevel; // Q14
|
||||
inLevel = ((int32_t)diffGain << 14) - inLevel; // Q14
|
||||
|
||||
// Make calculations on abs(inLevel) and compensate for the sign afterwards.
|
||||
absInLevel = (WebRtc_UWord32)WEBRTC_SPL_ABS_W32(inLevel); // Q14
|
||||
absInLevel = (uint32_t)WEBRTC_SPL_ABS_W32(inLevel); // Q14
|
||||
|
||||
// LUT with interpolation
|
||||
intPart = (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_U32(absInLevel, 14);
|
||||
fracPart = (WebRtc_UWord16)(absInLevel & 0x00003FFF); // extract the fractional part
|
||||
intPart = (uint16_t)(absInLevel >> 14);
|
||||
fracPart = (uint16_t)(absInLevel & 0x00003FFF); // extract the fractional part
|
||||
tmpU16 = kGenFuncTable[intPart + 1] - kGenFuncTable[intPart]; // Q8
|
||||
tmpU32no1 = WEBRTC_SPL_UMUL_16_16(tmpU16, fracPart); // Q22
|
||||
tmpU32no1 += WEBRTC_SPL_LSHIFT_U32((WebRtc_UWord32)kGenFuncTable[intPart], 14); // Q22
|
||||
logApprox = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 8); // Q14
|
||||
tmpU32no1 = tmpU16 * fracPart; // Q22
|
||||
tmpU32no1 += (uint32_t)kGenFuncTable[intPart] << 14; // Q22
|
||||
logApprox = tmpU32no1 >> 8; // Q14
|
||||
// Compensate for negative exponent using the relation:
|
||||
// log2(1 + 2^-x) = log2(1 + 2^x) - x
|
||||
if (inLevel < 0)
|
||||
@@ -160,83 +164,89 @@ WebRtc_Word32 WebRtcAgc_CalculateGainTable(WebRtc_Word32 *gainTable, // Q16
|
||||
if (zeros < 15)
|
||||
{
|
||||
// Not enough space for multiplication
|
||||
tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(absInLevel, 15 - zeros); // Q(zeros-1)
|
||||
tmpU32no2 = absInLevel >> (15 - zeros); // Q(zeros-1)
|
||||
tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no2, kLogE_1); // Q(zeros+13)
|
||||
if (zeros < 9)
|
||||
{
|
||||
tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 9 - zeros); // Q(zeros+13)
|
||||
zerosScale = 9 - zeros;
|
||||
tmpU32no1 >>= zerosScale; // Q(zeros+13)
|
||||
} else
|
||||
{
|
||||
tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(tmpU32no2, zeros - 9); // Q22
|
||||
tmpU32no2 >>= zeros - 9; // Q22
|
||||
}
|
||||
} else
|
||||
{
|
||||
tmpU32no2 = WEBRTC_SPL_UMUL_32_16(absInLevel, kLogE_1); // Q28
|
||||
tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(tmpU32no2, 6); // Q22
|
||||
tmpU32no2 >>= 6; // Q22
|
||||
}
|
||||
logApprox = 0;
|
||||
if (tmpU32no2 < tmpU32no1)
|
||||
{
|
||||
logApprox = WEBRTC_SPL_RSHIFT_U32(tmpU32no1 - tmpU32no2, 8 - zerosScale); //Q14
|
||||
logApprox = (tmpU32no1 - tmpU32no2) >> (8 - zerosScale); //Q14
|
||||
}
|
||||
}
|
||||
numFIX = WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_U16(maxGain, constMaxGain), 6); // Q14
|
||||
numFIX -= WEBRTC_SPL_MUL_32_16((WebRtc_Word32)logApprox, diffGain); // Q14
|
||||
numFIX = (maxGain * constMaxGain) << 6; // Q14
|
||||
numFIX -= (int32_t)logApprox * diffGain; // Q14
|
||||
|
||||
// Calculate ratio
|
||||
// Shift numFIX as much as possible
|
||||
zeros = WebRtcSpl_NormW32(numFIX);
|
||||
numFIX = WEBRTC_SPL_LSHIFT_W32(numFIX, zeros); // Q(14+zeros)
|
||||
// Shift |numFIX| as much as possible.
|
||||
// Ensure we avoid wrap-around in |den| as well.
|
||||
if (numFIX > (den >> 8)) // |den| is Q8.
|
||||
{
|
||||
zeros = WebRtcSpl_NormW32(numFIX);
|
||||
} else
|
||||
{
|
||||
zeros = WebRtcSpl_NormW32(den) + 8;
|
||||
}
|
||||
numFIX <<= zeros; // Q(14+zeros)
|
||||
|
||||
// Shift den so we end up in Qy1
|
||||
tmp32no1 = WEBRTC_SPL_SHIFT_W32(den, zeros - 8); // Q(zeros)
|
||||
if (numFIX < 0)
|
||||
{
|
||||
numFIX -= WEBRTC_SPL_RSHIFT_W32(tmp32no1, 1);
|
||||
numFIX -= tmp32no1 / 2;
|
||||
} else
|
||||
{
|
||||
numFIX += WEBRTC_SPL_RSHIFT_W32(tmp32no1, 1);
|
||||
numFIX += tmp32no1 / 2;
|
||||
}
|
||||
y32 = WEBRTC_SPL_DIV(numFIX, tmp32no1); // in Q14
|
||||
y32 = numFIX / tmp32no1; // in Q14
|
||||
if (limiterEnable && (i < limiterIdx))
|
||||
{
|
||||
tmp32 = WEBRTC_SPL_MUL_16_U16(i - 1, kLog10_2); // Q14
|
||||
tmp32 -= WEBRTC_SPL_LSHIFT_W32(limiterLvl, 14); // Q14
|
||||
tmp32 -= limiterLvl << 14; // Q14
|
||||
y32 = WebRtcSpl_DivW32W16(tmp32 + 10, 20);
|
||||
}
|
||||
if (y32 > 39000)
|
||||
{
|
||||
tmp32 = WEBRTC_SPL_MUL(y32 >> 1, kLog10) + 4096; // in Q27
|
||||
tmp32 = WEBRTC_SPL_RSHIFT_W32(tmp32, 13); // in Q14
|
||||
tmp32 = (y32 >> 1) * kLog10 + 4096; // in Q27
|
||||
tmp32 >>= 13; // In Q14.
|
||||
} else
|
||||
{
|
||||
tmp32 = WEBRTC_SPL_MUL(y32, kLog10) + 8192; // in Q28
|
||||
tmp32 = WEBRTC_SPL_RSHIFT_W32(tmp32, 14); // in Q14
|
||||
tmp32 = y32 * kLog10 + 8192; // in Q28
|
||||
tmp32 >>= 14; // In Q14.
|
||||
}
|
||||
tmp32 += WEBRTC_SPL_LSHIFT_W32(16, 14); // in Q14 (Make sure final output is in Q16)
|
||||
tmp32 += 16 << 14; // in Q14 (Make sure final output is in Q16)
|
||||
|
||||
// Calculate power
|
||||
if (tmp32 > 0)
|
||||
{
|
||||
intPart = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 14);
|
||||
fracPart = (WebRtc_UWord16)(tmp32 & 0x00003FFF); // in Q14
|
||||
if (WEBRTC_SPL_RSHIFT_W32(fracPart, 13))
|
||||
intPart = (int16_t)(tmp32 >> 14);
|
||||
fracPart = (uint16_t)(tmp32 & 0x00003FFF); // in Q14
|
||||
if ((fracPart >> 13) != 0)
|
||||
{
|
||||
tmp16 = WEBRTC_SPL_LSHIFT_W16(2, 14) - constLinApprox;
|
||||
tmp32no2 = WEBRTC_SPL_LSHIFT_W32(1, 14) - fracPart;
|
||||
tmp32no2 = WEBRTC_SPL_MUL_32_16(tmp32no2, tmp16);
|
||||
tmp32no2 = WEBRTC_SPL_RSHIFT_W32(tmp32no2, 13);
|
||||
tmp32no2 = WEBRTC_SPL_LSHIFT_W32(1, 14) - tmp32no2;
|
||||
tmp16 = (2 << 14) - constLinApprox;
|
||||
tmp32no2 = (1 << 14) - fracPart;
|
||||
tmp32no2 *= tmp16;
|
||||
tmp32no2 >>= 13;
|
||||
tmp32no2 = (1 << 14) - tmp32no2;
|
||||
} else
|
||||
{
|
||||
tmp16 = constLinApprox - WEBRTC_SPL_LSHIFT_W16(1, 14);
|
||||
tmp32no2 = WEBRTC_SPL_MUL_32_16(fracPart, tmp16);
|
||||
tmp32no2 = WEBRTC_SPL_RSHIFT_W32(tmp32no2, 13);
|
||||
tmp16 = constLinApprox - (1 << 14);
|
||||
tmp32no2 = (fracPart * tmp16) >> 13;
|
||||
}
|
||||
fracPart = (WebRtc_UWord16)tmp32no2;
|
||||
gainTable[i] = WEBRTC_SPL_LSHIFT_W32(1, intPart)
|
||||
+ WEBRTC_SPL_SHIFT_W32(fracPart, intPart - 14);
|
||||
fracPart = (uint16_t)tmp32no2;
|
||||
gainTable[i] =
|
||||
(1 << intPart) + WEBRTC_SPL_SHIFT_W32(fracPart, intPart - 14);
|
||||
} else
|
||||
{
|
||||
gainTable[i] = 0;
|
||||
@@ -246,9 +256,7 @@ WebRtc_Word32 WebRtcAgc_CalculateGainTable(WebRtc_Word32 *gainTable, // Q16
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAgc_InitDigital(DigitalAgc_t *stt, WebRtc_Word16 agcMode)
|
||||
{
|
||||
|
||||
int32_t WebRtcAgc_InitDigital(DigitalAgc* stt, int16_t agcMode) {
|
||||
if (agcMode == kAgcModeFixedDigital)
|
||||
{
|
||||
// start at minimum to find correct gain faster
|
||||
@@ -256,13 +264,13 @@ WebRtc_Word32 WebRtcAgc_InitDigital(DigitalAgc_t *stt, WebRtc_Word16 agcMode)
|
||||
} else
|
||||
{
|
||||
// start out with 0 dB gain
|
||||
stt->capacitorSlow = 134217728; // (WebRtc_Word32)(0.125f * 32768.0f * 32768.0f);
|
||||
stt->capacitorSlow = 134217728; // (int32_t)(0.125f * 32768.0f * 32768.0f);
|
||||
}
|
||||
stt->capacitorFast = 0;
|
||||
stt->gain = 65536;
|
||||
stt->gatePrevious = 0;
|
||||
stt->agcMode = agcMode;
|
||||
#ifdef AGC_DEBUG
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
stt->frameCounter = 0;
|
||||
#endif
|
||||
|
||||
@@ -273,52 +281,45 @@ WebRtc_Word32 WebRtcAgc_InitDigital(DigitalAgc_t *stt, WebRtc_Word16 agcMode)
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAgc_AddFarendToDigital(DigitalAgc_t *stt, const WebRtc_Word16 *in_far,
|
||||
WebRtc_Word16 nrSamples)
|
||||
{
|
||||
// Check for valid pointer
|
||||
if (&stt->vadFarend == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t WebRtcAgc_AddFarendToDigital(DigitalAgc* stt,
|
||||
const int16_t* in_far,
|
||||
size_t nrSamples) {
|
||||
assert(stt != NULL);
|
||||
// VAD for far end
|
||||
WebRtcAgc_ProcessVad(&stt->vadFarend, in_far, nrSamples);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *stt, const WebRtc_Word16 *in_near,
|
||||
const WebRtc_Word16 *in_near_H, WebRtc_Word16 *out,
|
||||
WebRtc_Word16 *out_H, WebRtc_UWord32 FS,
|
||||
WebRtc_Word16 lowlevelSignal)
|
||||
{
|
||||
int32_t WebRtcAgc_ProcessDigital(DigitalAgc* stt,
|
||||
const int16_t* const* in_near,
|
||||
size_t num_bands,
|
||||
int16_t* const* out,
|
||||
uint32_t FS,
|
||||
int16_t lowlevelSignal) {
|
||||
// array for gains (one value per ms, incl start & end)
|
||||
WebRtc_Word32 gains[11];
|
||||
int32_t gains[11];
|
||||
|
||||
WebRtc_Word32 out_tmp, tmp32;
|
||||
WebRtc_Word32 env[10];
|
||||
WebRtc_Word32 nrg, max_nrg;
|
||||
WebRtc_Word32 cur_level;
|
||||
WebRtc_Word32 gain32, delta;
|
||||
WebRtc_Word16 logratio;
|
||||
WebRtc_Word16 lower_thr, upper_thr;
|
||||
WebRtc_Word16 zeros, zeros_fast, frac;
|
||||
WebRtc_Word16 decay;
|
||||
WebRtc_Word16 gate, gain_adj;
|
||||
WebRtc_Word16 k, n;
|
||||
WebRtc_Word16 L, L2; // samples/subframe
|
||||
int32_t out_tmp, tmp32;
|
||||
int32_t env[10];
|
||||
int32_t max_nrg;
|
||||
int32_t cur_level;
|
||||
int32_t gain32, delta;
|
||||
int16_t logratio;
|
||||
int16_t lower_thr, upper_thr;
|
||||
int16_t zeros = 0, zeros_fast, frac = 0;
|
||||
int16_t decay;
|
||||
int16_t gate, gain_adj;
|
||||
int16_t k;
|
||||
size_t n, i, L;
|
||||
int16_t L2; // samples/subframe
|
||||
|
||||
// determine number of samples per ms
|
||||
if (FS == 8000)
|
||||
{
|
||||
L = 8;
|
||||
L2 = 3;
|
||||
} else if (FS == 16000)
|
||||
{
|
||||
L = 16;
|
||||
L2 = 4;
|
||||
} else if (FS == 32000)
|
||||
} else if (FS == 16000 || FS == 32000 || FS == 48000)
|
||||
{
|
||||
L = 16;
|
||||
L2 = 4;
|
||||
@@ -327,27 +328,22 @@ WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *stt, const WebRtc_Word16 *i
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO(andrew): again, we don't need input and output pointers...
|
||||
if (in_near != out)
|
||||
for (i = 0; i < num_bands; ++i)
|
||||
{
|
||||
// Only needed if they don't already point to the same place.
|
||||
memcpy(out, in_near, 10 * L * sizeof(WebRtc_Word16));
|
||||
}
|
||||
if (FS == 32000)
|
||||
{
|
||||
if (in_near_H != out_H)
|
||||
if (in_near[i] != out[i])
|
||||
{
|
||||
memcpy(out_H, in_near_H, 10 * L * sizeof(WebRtc_Word16));
|
||||
// Only needed if they don't already point to the same place.
|
||||
memcpy(out[i], in_near[i], 10 * L * sizeof(in_near[i][0]));
|
||||
}
|
||||
}
|
||||
// VAD for near end
|
||||
logratio = WebRtcAgc_ProcessVad(&stt->vadNearend, out, L * 10);
|
||||
logratio = WebRtcAgc_ProcessVad(&stt->vadNearend, out[0], L * 10);
|
||||
|
||||
// Account for far end VAD
|
||||
if (stt->vadFarend.counter > 10)
|
||||
{
|
||||
tmp32 = WEBRTC_SPL_MUL_16_16(3, logratio);
|
||||
logratio = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32 - stt->vadFarend.logRatio, 2);
|
||||
tmp32 = 3 * logratio;
|
||||
logratio = (int16_t)((tmp32 - stt->vadFarend.logRatio) >> 2);
|
||||
}
|
||||
|
||||
// Determine decay factor depending on VAD
|
||||
@@ -364,11 +360,11 @@ WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *stt, const WebRtc_Word16 *i
|
||||
decay = 0;
|
||||
} else
|
||||
{
|
||||
// decay = (WebRtc_Word16)(((lower_thr - logratio)
|
||||
// decay = (int16_t)(((lower_thr - logratio)
|
||||
// * (2^27/(DecayTime*(upper_thr-lower_thr)))) >> 10);
|
||||
// SUBSTITUTED: 2^27/(DecayTime*(upper_thr-lower_thr)) -> 65
|
||||
tmp32 = WEBRTC_SPL_MUL_16_16((lower_thr - logratio), 65);
|
||||
decay = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 10);
|
||||
tmp32 = (lower_thr - logratio) * 65;
|
||||
decay = (int16_t)(tmp32 >> 10);
|
||||
}
|
||||
|
||||
// adjust decay factor for long silence (detected as low standard deviation)
|
||||
@@ -380,9 +376,9 @@ WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *stt, const WebRtc_Word16 *i
|
||||
decay = 0;
|
||||
} else if (stt->vadNearend.stdLongTerm < 8096)
|
||||
{
|
||||
// decay = (WebRtc_Word16)(((stt->vadNearend.stdLongTerm - 4000) * decay) >> 12);
|
||||
tmp32 = WEBRTC_SPL_MUL_16_16((stt->vadNearend.stdLongTerm - 4000), decay);
|
||||
decay = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 12);
|
||||
// decay = (int16_t)(((stt->vadNearend.stdLongTerm - 4000) * decay) >> 12);
|
||||
tmp32 = (stt->vadNearend.stdLongTerm - 4000) * decay;
|
||||
decay = (int16_t)(tmp32 >> 12);
|
||||
}
|
||||
|
||||
if (lowlevelSignal != 0)
|
||||
@@ -390,9 +386,14 @@ WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *stt, const WebRtc_Word16 *i
|
||||
decay = 0;
|
||||
}
|
||||
}
|
||||
#ifdef AGC_DEBUG
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
stt->frameCounter++;
|
||||
fprintf(stt->logFile, "%5.2f\t%d\t%d\t%d\t", (float)(stt->frameCounter) / 100, logratio, decay, stt->vadNearend.stdLongTerm);
|
||||
fprintf(stt->logFile,
|
||||
"%5.2f\t%d\t%d\t%d\t",
|
||||
(float)(stt->frameCounter) / 100,
|
||||
logratio,
|
||||
decay,
|
||||
stt->vadNearend.stdLongTerm);
|
||||
#endif
|
||||
// Find max amplitude per sub frame
|
||||
// iterate over sub frames
|
||||
@@ -402,7 +403,7 @@ WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *stt, const WebRtc_Word16 *i
|
||||
max_nrg = 0;
|
||||
for (n = 0; n < L; n++)
|
||||
{
|
||||
nrg = WEBRTC_SPL_MUL_16_16(out[k * L + n], out[k * L + n]);
|
||||
int32_t nrg = out[0][k * L + n] * out[0][k * L + n];
|
||||
if (nrg > max_nrg)
|
||||
{
|
||||
max_nrg = nrg;
|
||||
@@ -445,34 +446,39 @@ WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *stt, const WebRtc_Word16 *i
|
||||
}
|
||||
// Translate signal level into gain, using a piecewise linear approximation
|
||||
// find number of leading zeros
|
||||
zeros = WebRtcSpl_NormU32((WebRtc_UWord32)cur_level);
|
||||
zeros = WebRtcSpl_NormU32((uint32_t)cur_level);
|
||||
if (cur_level == 0)
|
||||
{
|
||||
zeros = 31;
|
||||
}
|
||||
tmp32 = (WEBRTC_SPL_LSHIFT_W32(cur_level, zeros) & 0x7FFFFFFF);
|
||||
frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 19); // Q12
|
||||
tmp32 = WEBRTC_SPL_MUL((stt->gainTable[zeros-1] - stt->gainTable[zeros]), frac);
|
||||
gains[k + 1] = stt->gainTable[zeros] + WEBRTC_SPL_RSHIFT_W32(tmp32, 12);
|
||||
#ifdef AGC_DEBUG
|
||||
if (k == 0)
|
||||
{
|
||||
fprintf(stt->logFile, "%d\t%d\t%d\t%d\t%d\n", env[0], cur_level, stt->capacitorFast, stt->capacitorSlow, zeros);
|
||||
tmp32 = (cur_level << zeros) & 0x7FFFFFFF;
|
||||
frac = (int16_t)(tmp32 >> 19); // Q12.
|
||||
tmp32 = (stt->gainTable[zeros-1] - stt->gainTable[zeros]) * frac;
|
||||
gains[k + 1] = stt->gainTable[zeros] + (tmp32 >> 12);
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
if (k == 0) {
|
||||
fprintf(stt->logFile,
|
||||
"%d\t%d\t%d\t%d\t%d\n",
|
||||
env[0],
|
||||
cur_level,
|
||||
stt->capacitorFast,
|
||||
stt->capacitorSlow,
|
||||
zeros);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Gate processing (lower gain during absence of speech)
|
||||
zeros = WEBRTC_SPL_LSHIFT_W16(zeros, 9) - WEBRTC_SPL_RSHIFT_W16(frac, 3);
|
||||
zeros = (zeros << 9) - (frac >> 3);
|
||||
// find number of leading zeros
|
||||
zeros_fast = WebRtcSpl_NormU32((WebRtc_UWord32)stt->capacitorFast);
|
||||
zeros_fast = WebRtcSpl_NormU32((uint32_t)stt->capacitorFast);
|
||||
if (stt->capacitorFast == 0)
|
||||
{
|
||||
zeros_fast = 31;
|
||||
}
|
||||
tmp32 = (WEBRTC_SPL_LSHIFT_W32(stt->capacitorFast, zeros_fast) & 0x7FFFFFFF);
|
||||
zeros_fast = WEBRTC_SPL_LSHIFT_W16(zeros_fast, 9);
|
||||
zeros_fast -= (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 22);
|
||||
tmp32 = (stt->capacitorFast << zeros_fast) & 0x7FFFFFFF;
|
||||
zeros_fast <<= 9;
|
||||
zeros_fast -= (int16_t)(tmp32 >> 22);
|
||||
|
||||
gate = 1000 + zeros_fast - zeros - stt->vadNearend.stdShortTerm;
|
||||
|
||||
@@ -481,8 +487,8 @@ WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *stt, const WebRtc_Word16 *i
|
||||
stt->gatePrevious = 0;
|
||||
} else
|
||||
{
|
||||
tmp32 = WEBRTC_SPL_MUL_16_16(stt->gatePrevious, 7);
|
||||
gate = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)gate + tmp32, 3);
|
||||
tmp32 = stt->gatePrevious * 7;
|
||||
gate = (int16_t)((gate + tmp32) >> 3);
|
||||
stt->gatePrevious = gate;
|
||||
}
|
||||
// gate < 0 -> no gate
|
||||
@@ -491,7 +497,7 @@ WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *stt, const WebRtc_Word16 *i
|
||||
{
|
||||
if (gate < 2500)
|
||||
{
|
||||
gain_adj = WEBRTC_SPL_RSHIFT_W16(2500 - gate, 5);
|
||||
gain_adj = (2500 - gate) >> 5;
|
||||
} else
|
||||
{
|
||||
gain_adj = 0;
|
||||
@@ -501,12 +507,12 @@ WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *stt, const WebRtc_Word16 *i
|
||||
if ((gains[k + 1] - stt->gainTable[0]) > 8388608)
|
||||
{
|
||||
// To prevent wraparound
|
||||
tmp32 = WEBRTC_SPL_RSHIFT_W32((gains[k+1] - stt->gainTable[0]), 8);
|
||||
tmp32 = WEBRTC_SPL_MUL(tmp32, (178 + gain_adj));
|
||||
tmp32 = (gains[k + 1] - stt->gainTable[0]) >> 8;
|
||||
tmp32 *= 178 + gain_adj;
|
||||
} else
|
||||
{
|
||||
tmp32 = WEBRTC_SPL_MUL((gains[k+1] - stt->gainTable[0]), (178 + gain_adj));
|
||||
tmp32 = WEBRTC_SPL_RSHIFT_W32(tmp32, 8);
|
||||
tmp32 = (gains[k+1] - stt->gainTable[0]) * (178 + gain_adj);
|
||||
tmp32 >>= 8;
|
||||
}
|
||||
gains[k + 1] = stt->gainTable[0] + tmp32;
|
||||
}
|
||||
@@ -521,23 +527,23 @@ WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *stt, const WebRtc_Word16 *i
|
||||
{
|
||||
zeros = 16 - WebRtcSpl_NormW32(gains[k + 1]);
|
||||
}
|
||||
gain32 = WEBRTC_SPL_RSHIFT_W32(gains[k+1], zeros) + 1;
|
||||
gain32 = WEBRTC_SPL_MUL(gain32, gain32);
|
||||
gain32 = (gains[k + 1] >> zeros) + 1;
|
||||
gain32 *= gain32;
|
||||
// check for overflow
|
||||
while (AGC_MUL32(WEBRTC_SPL_RSHIFT_W32(env[k], 12) + 1, gain32)
|
||||
> WEBRTC_SPL_SHIFT_W32((WebRtc_Word32)32767, 2 * (1 - zeros + 10)))
|
||||
while (AGC_MUL32((env[k] >> 12) + 1, gain32)
|
||||
> WEBRTC_SPL_SHIFT_W32((int32_t)32767, 2 * (1 - zeros + 10)))
|
||||
{
|
||||
// multiply by 253/256 ==> -0.1 dB
|
||||
if (gains[k + 1] > 8388607)
|
||||
{
|
||||
// Prevent wrap around
|
||||
gains[k + 1] = WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(gains[k+1], 8), 253);
|
||||
gains[k + 1] = (gains[k+1] / 256) * 253;
|
||||
} else
|
||||
{
|
||||
gains[k + 1] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(gains[k+1], 253), 8);
|
||||
gains[k + 1] = (gains[k+1] * 253) / 256;
|
||||
}
|
||||
gain32 = WEBRTC_SPL_RSHIFT_W32(gains[k+1], zeros) + 1;
|
||||
gain32 = WEBRTC_SPL_MUL(gain32, gain32);
|
||||
gain32 = (gains[k + 1] >> zeros) + 1;
|
||||
gain32 *= gain32;
|
||||
}
|
||||
}
|
||||
// gain reductions should be done 1 ms earlier than gain increases
|
||||
@@ -553,42 +559,25 @@ WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *stt, const WebRtc_Word16 *i
|
||||
|
||||
// Apply gain
|
||||
// handle first sub frame separately
|
||||
delta = WEBRTC_SPL_LSHIFT_W32(gains[1] - gains[0], (4 - L2));
|
||||
gain32 = WEBRTC_SPL_LSHIFT_W32(gains[0], 4);
|
||||
delta = (gains[1] - gains[0]) << (4 - L2);
|
||||
gain32 = gains[0] << 4;
|
||||
// iterate over samples
|
||||
for (n = 0; n < L; n++)
|
||||
{
|
||||
// For lower band
|
||||
tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out[n], WEBRTC_SPL_RSHIFT_W32(gain32 + 127, 7));
|
||||
out_tmp = WEBRTC_SPL_RSHIFT_W32(tmp32 , 16);
|
||||
if (out_tmp > 4095)
|
||||
for (i = 0; i < num_bands; ++i)
|
||||
{
|
||||
out[n] = (WebRtc_Word16)32767;
|
||||
} else if (out_tmp < -4096)
|
||||
{
|
||||
out[n] = (WebRtc_Word16)-32768;
|
||||
} else
|
||||
{
|
||||
tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out[n], WEBRTC_SPL_RSHIFT_W32(gain32, 4));
|
||||
out[n] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32 , 16);
|
||||
}
|
||||
// For higher band
|
||||
if (FS == 32000)
|
||||
{
|
||||
tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out_H[n],
|
||||
WEBRTC_SPL_RSHIFT_W32(gain32 + 127, 7));
|
||||
out_tmp = WEBRTC_SPL_RSHIFT_W32(tmp32 , 16);
|
||||
tmp32 = out[i][n] * ((gain32 + 127) >> 7);
|
||||
out_tmp = tmp32 >> 16;
|
||||
if (out_tmp > 4095)
|
||||
{
|
||||
out_H[n] = (WebRtc_Word16)32767;
|
||||
out[i][n] = (int16_t)32767;
|
||||
} else if (out_tmp < -4096)
|
||||
{
|
||||
out_H[n] = (WebRtc_Word16)-32768;
|
||||
out[i][n] = (int16_t)-32768;
|
||||
} else
|
||||
{
|
||||
tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out_H[n],
|
||||
WEBRTC_SPL_RSHIFT_W32(gain32, 4));
|
||||
out_H[n] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32 , 16);
|
||||
tmp32 = out[i][n] * (gain32 >> 4);
|
||||
out[i][n] = (int16_t)(tmp32 >> 16);
|
||||
}
|
||||
}
|
||||
//
|
||||
@@ -598,21 +587,15 @@ WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *stt, const WebRtc_Word16 *i
|
||||
// iterate over subframes
|
||||
for (k = 1; k < 10; k++)
|
||||
{
|
||||
delta = WEBRTC_SPL_LSHIFT_W32(gains[k+1] - gains[k], (4 - L2));
|
||||
gain32 = WEBRTC_SPL_LSHIFT_W32(gains[k], 4);
|
||||
delta = (gains[k+1] - gains[k]) << (4 - L2);
|
||||
gain32 = gains[k] << 4;
|
||||
// iterate over samples
|
||||
for (n = 0; n < L; n++)
|
||||
{
|
||||
// For lower band
|
||||
tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out[k * L + n],
|
||||
WEBRTC_SPL_RSHIFT_W32(gain32, 4));
|
||||
out[k * L + n] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32 , 16);
|
||||
// For higher band
|
||||
if (FS == 32000)
|
||||
for (i = 0; i < num_bands; ++i)
|
||||
{
|
||||
tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out_H[k * L + n],
|
||||
WEBRTC_SPL_RSHIFT_W32(gain32, 4));
|
||||
out_H[k * L + n] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32 , 16);
|
||||
tmp32 = out[i][k * L + n] * (gain32 >> 4);
|
||||
out[i][k * L + n] = (int16_t)(tmp32 >> 16);
|
||||
}
|
||||
gain32 += delta;
|
||||
}
|
||||
@@ -621,24 +604,23 @@ WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *stt, const WebRtc_Word16 *i
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WebRtcAgc_InitVad(AgcVad_t *state)
|
||||
{
|
||||
WebRtc_Word16 k;
|
||||
void WebRtcAgc_InitVad(AgcVad* state) {
|
||||
int16_t k;
|
||||
|
||||
state->HPstate = 0; // state of high pass filter
|
||||
state->logRatio = 0; // log( P(active) / P(inactive) )
|
||||
// average input level (Q10)
|
||||
state->meanLongTerm = WEBRTC_SPL_LSHIFT_W16(15, 10);
|
||||
state->meanLongTerm = 15 << 10;
|
||||
|
||||
// variance of input level (Q8)
|
||||
state->varianceLongTerm = WEBRTC_SPL_LSHIFT_W32(500, 8);
|
||||
state->varianceLongTerm = 500 << 8;
|
||||
|
||||
state->stdLongTerm = 0; // standard deviation of input level in dB
|
||||
// short-term average input level (Q10)
|
||||
state->meanShortTerm = WEBRTC_SPL_LSHIFT_W16(15, 10);
|
||||
state->meanShortTerm = 15 << 10;
|
||||
|
||||
// short-term variance of input level (Q8)
|
||||
state->varianceShortTerm = WEBRTC_SPL_LSHIFT_W32(500, 8);
|
||||
state->varianceShortTerm = 500 << 8;
|
||||
|
||||
state->stdShortTerm = 0; // short-term standard deviation of input level in dB
|
||||
state->counter = 3; // counts updates
|
||||
@@ -649,17 +631,17 @@ void WebRtcAgc_InitVad(AgcVad_t *state)
|
||||
}
|
||||
}
|
||||
|
||||
WebRtc_Word16 WebRtcAgc_ProcessVad(AgcVad_t *state, // (i) VAD state
|
||||
const WebRtc_Word16 *in, // (i) Speech signal
|
||||
WebRtc_Word16 nrSamples) // (i) number of samples
|
||||
int16_t WebRtcAgc_ProcessVad(AgcVad* state, // (i) VAD state
|
||||
const int16_t* in, // (i) Speech signal
|
||||
size_t nrSamples) // (i) number of samples
|
||||
{
|
||||
WebRtc_Word32 out, nrg, tmp32, tmp32b;
|
||||
WebRtc_UWord16 tmpU16;
|
||||
WebRtc_Word16 k, subfr, tmp16;
|
||||
WebRtc_Word16 buf1[8];
|
||||
WebRtc_Word16 buf2[4];
|
||||
WebRtc_Word16 HPstate;
|
||||
WebRtc_Word16 zeros, dB;
|
||||
int32_t out, nrg, tmp32, tmp32b;
|
||||
uint16_t tmpU16;
|
||||
int16_t k, subfr, tmp16;
|
||||
int16_t buf1[8];
|
||||
int16_t buf2[4];
|
||||
int16_t HPstate;
|
||||
int16_t zeros, dB;
|
||||
|
||||
// process in 10 sub frames of 1 ms (to save on memory)
|
||||
nrg = 0;
|
||||
@@ -671,9 +653,9 @@ WebRtc_Word16 WebRtcAgc_ProcessVad(AgcVad_t *state, // (i) VAD state
|
||||
{
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
tmp32 = (WebRtc_Word32)in[2 * k] + (WebRtc_Word32)in[2 * k + 1];
|
||||
tmp32 = WEBRTC_SPL_RSHIFT_W32(tmp32, 1);
|
||||
buf1[k] = (WebRtc_Word16)tmp32;
|
||||
tmp32 = (int32_t)in[2 * k] + (int32_t)in[2 * k + 1];
|
||||
tmp32 >>= 1;
|
||||
buf1[k] = (int16_t)tmp32;
|
||||
}
|
||||
in += 16;
|
||||
|
||||
@@ -688,10 +670,9 @@ WebRtc_Word16 WebRtcAgc_ProcessVad(AgcVad_t *state, // (i) VAD state
|
||||
for (k = 0; k < 4; k++)
|
||||
{
|
||||
out = buf2[k] + HPstate;
|
||||
tmp32 = WEBRTC_SPL_MUL(600, out);
|
||||
HPstate = (WebRtc_Word16)(WEBRTC_SPL_RSHIFT_W32(tmp32, 10) - buf2[k]);
|
||||
tmp32 = WEBRTC_SPL_MUL(out, out);
|
||||
nrg += WEBRTC_SPL_RSHIFT_W32(tmp32, 6);
|
||||
tmp32 = 600 * out;
|
||||
HPstate = (int16_t)((tmp32 >> 10) - buf2[k]);
|
||||
nrg += (out * out) >> 6;
|
||||
}
|
||||
}
|
||||
state->HPstate = HPstate;
|
||||
@@ -722,7 +703,7 @@ WebRtc_Word16 WebRtcAgc_ProcessVad(AgcVad_t *state, // (i) VAD state
|
||||
}
|
||||
|
||||
// energy level (range {-32..30}) (Q10)
|
||||
dB = WEBRTC_SPL_LSHIFT_W16(15 - zeros, 11);
|
||||
dB = (15 - zeros) << 11;
|
||||
|
||||
// Update statistics
|
||||
|
||||
@@ -733,44 +714,49 @@ WebRtc_Word16 WebRtcAgc_ProcessVad(AgcVad_t *state, // (i) VAD state
|
||||
}
|
||||
|
||||
// update short-term estimate of mean energy level (Q10)
|
||||
tmp32 = (WEBRTC_SPL_MUL_16_16(state->meanShortTerm, 15) + (WebRtc_Word32)dB);
|
||||
state->meanShortTerm = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 4);
|
||||
tmp32 = state->meanShortTerm * 15 + dB;
|
||||
state->meanShortTerm = (int16_t)(tmp32 >> 4);
|
||||
|
||||
// update short-term estimate of variance in energy level (Q8)
|
||||
tmp32 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(dB, dB), 12);
|
||||
tmp32 += WEBRTC_SPL_MUL(state->varianceShortTerm, 15);
|
||||
state->varianceShortTerm = WEBRTC_SPL_RSHIFT_W32(tmp32, 4);
|
||||
tmp32 = (dB * dB) >> 12;
|
||||
tmp32 += state->varianceShortTerm * 15;
|
||||
state->varianceShortTerm = tmp32 / 16;
|
||||
|
||||
// update short-term estimate of standard deviation in energy level (Q10)
|
||||
tmp32 = WEBRTC_SPL_MUL_16_16(state->meanShortTerm, state->meanShortTerm);
|
||||
tmp32 = WEBRTC_SPL_LSHIFT_W32(state->varianceShortTerm, 12) - tmp32;
|
||||
state->stdShortTerm = (WebRtc_Word16)WebRtcSpl_Sqrt(tmp32);
|
||||
tmp32 = state->meanShortTerm * state->meanShortTerm;
|
||||
tmp32 = (state->varianceShortTerm << 12) - tmp32;
|
||||
state->stdShortTerm = (int16_t)WebRtcSpl_Sqrt(tmp32);
|
||||
|
||||
// update long-term estimate of mean energy level (Q10)
|
||||
tmp32 = WEBRTC_SPL_MUL_16_16(state->meanLongTerm, state->counter) + (WebRtc_Word32)dB;
|
||||
state->meanLongTerm = WebRtcSpl_DivW32W16ResW16(tmp32,
|
||||
WEBRTC_SPL_ADD_SAT_W16(state->counter, 1));
|
||||
tmp32 = state->meanLongTerm * state->counter + dB;
|
||||
state->meanLongTerm = WebRtcSpl_DivW32W16ResW16(
|
||||
tmp32, WebRtcSpl_AddSatW16(state->counter, 1));
|
||||
|
||||
// update long-term estimate of variance in energy level (Q8)
|
||||
tmp32 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(dB, dB), 12);
|
||||
tmp32 += WEBRTC_SPL_MUL(state->varianceLongTerm, state->counter);
|
||||
state->varianceLongTerm = WebRtcSpl_DivW32W16(tmp32,
|
||||
WEBRTC_SPL_ADD_SAT_W16(state->counter, 1));
|
||||
tmp32 = (dB * dB) >> 12;
|
||||
tmp32 += state->varianceLongTerm * state->counter;
|
||||
state->varianceLongTerm = WebRtcSpl_DivW32W16(
|
||||
tmp32, WebRtcSpl_AddSatW16(state->counter, 1));
|
||||
|
||||
// update long-term estimate of standard deviation in energy level (Q10)
|
||||
tmp32 = WEBRTC_SPL_MUL_16_16(state->meanLongTerm, state->meanLongTerm);
|
||||
tmp32 = WEBRTC_SPL_LSHIFT_W32(state->varianceLongTerm, 12) - tmp32;
|
||||
state->stdLongTerm = (WebRtc_Word16)WebRtcSpl_Sqrt(tmp32);
|
||||
tmp32 = state->meanLongTerm * state->meanLongTerm;
|
||||
tmp32 = (state->varianceLongTerm << 12) - tmp32;
|
||||
state->stdLongTerm = (int16_t)WebRtcSpl_Sqrt(tmp32);
|
||||
|
||||
// update voice activity measure (Q10)
|
||||
tmp16 = WEBRTC_SPL_LSHIFT_W16(3, 12);
|
||||
tmp32 = WEBRTC_SPL_MUL_16_16(tmp16, (dB - state->meanLongTerm));
|
||||
tmp16 = 3 << 12;
|
||||
// TODO(bjornv): (dB - state->meanLongTerm) can overflow, e.g., in
|
||||
// ApmTest.Process unit test. Previously the macro WEBRTC_SPL_MUL_16_16()
|
||||
// was used, which did an intermediate cast to (int16_t), hence losing
|
||||
// significant bits. This cause logRatio to max out positive, rather than
|
||||
// negative. This is a bug, but has very little significance.
|
||||
tmp32 = tmp16 * (int16_t)(dB - state->meanLongTerm);
|
||||
tmp32 = WebRtcSpl_DivW32W16(tmp32, state->stdLongTerm);
|
||||
tmpU16 = WEBRTC_SPL_LSHIFT_U16((WebRtc_UWord16)13, 12);
|
||||
tmpU16 = (13 << 12);
|
||||
tmp32b = WEBRTC_SPL_MUL_16_U16(state->logRatio, tmpU16);
|
||||
tmp32 += WEBRTC_SPL_RSHIFT_W32(tmp32b, 10);
|
||||
tmp32 += tmp32b >> 10;
|
||||
|
||||
state->logRatio = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 6);
|
||||
state->logRatio = (int16_t)(tmp32 >> 6);
|
||||
|
||||
// limit
|
||||
if (state->logRatio > 2048)
|
||||
80
webrtc/modules/audio_processing/agc/legacy/digital_agc.h
Normal file
80
webrtc/modules/audio_processing/agc/legacy/digital_agc.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIGITAL_AGC_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIGITAL_AGC_H_
|
||||
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// the 32 most significant bits of A(19) * B(26) >> 13
|
||||
#define AGC_MUL32(A, B) (((B)>>13)*(A) + ( ((0x00001FFF & (B))*(A)) >> 13 ))
|
||||
// C + the 32 most significant bits of A * B
|
||||
#define AGC_SCALEDIFF32(A, B, C) ((C) + ((B)>>16)*(A) + ( ((0x0000FFFF & (B))*(A)) >> 16 ))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t downState[8];
|
||||
int16_t HPstate;
|
||||
int16_t counter;
|
||||
int16_t logRatio; // log( P(active) / P(inactive) ) (Q10)
|
||||
int16_t meanLongTerm; // Q10
|
||||
int32_t varianceLongTerm; // Q8
|
||||
int16_t stdLongTerm; // Q10
|
||||
int16_t meanShortTerm; // Q10
|
||||
int32_t varianceShortTerm; // Q8
|
||||
int16_t stdShortTerm; // Q10
|
||||
} AgcVad; // total = 54 bytes
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t capacitorSlow;
|
||||
int32_t capacitorFast;
|
||||
int32_t gain;
|
||||
int32_t gainTable[32];
|
||||
int16_t gatePrevious;
|
||||
int16_t agcMode;
|
||||
AgcVad vadNearend;
|
||||
AgcVad vadFarend;
|
||||
#ifdef WEBRTC_AGC_DEBUG_DUMP
|
||||
FILE* logFile;
|
||||
int frameCounter;
|
||||
#endif
|
||||
} DigitalAgc;
|
||||
|
||||
int32_t WebRtcAgc_InitDigital(DigitalAgc* digitalAgcInst, int16_t agcMode);
|
||||
|
||||
int32_t WebRtcAgc_ProcessDigital(DigitalAgc* digitalAgcInst,
|
||||
const int16_t* const* inNear,
|
||||
size_t num_bands,
|
||||
int16_t* const* out,
|
||||
uint32_t FS,
|
||||
int16_t lowLevelSignal);
|
||||
|
||||
int32_t WebRtcAgc_AddFarendToDigital(DigitalAgc* digitalAgcInst,
|
||||
const int16_t* inFar,
|
||||
size_t nrSamples);
|
||||
|
||||
void WebRtcAgc_InitVad(AgcVad* vadInst);
|
||||
|
||||
int16_t WebRtcAgc_ProcessVad(AgcVad* vadInst, // (i) VAD state
|
||||
const int16_t* in, // (i) Speech signal
|
||||
size_t nrSamples); // (i) number of samples
|
||||
|
||||
int32_t WebRtcAgc_CalculateGainTable(int32_t *gainTable, // Q16
|
||||
int16_t compressionGaindB, // Q0 (in dB)
|
||||
int16_t targetLevelDbfs,// Q0 (in dB)
|
||||
uint8_t limiterEnable,
|
||||
int16_t analogTarget);
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_DIGITAL_AGC_H_
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
* 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
|
||||
@@ -8,10 +8,10 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_MAIN_INTERFACE_GAIN_CONTROL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_MAIN_INTERFACE_GAIN_CONTROL_H_
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_GAIN_CONTROL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_GAIN_CONTROL_H_
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// Errors
|
||||
#define AGC_UNSPECIFIED_ERROR 18000
|
||||
@@ -39,10 +39,10 @@ enum
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WebRtc_Word16 targetLevelDbfs; // default 3 (-3 dBOv)
|
||||
WebRtc_Word16 compressionGaindB; // default 9 dB
|
||||
WebRtc_UWord8 limiterEnable; // default kAgcTrue (on)
|
||||
} WebRtcAgc_config_t;
|
||||
int16_t targetLevelDbfs; // default 3 (-3 dBOv)
|
||||
int16_t compressionGaindB; // default 9 dB
|
||||
uint8_t limiterEnable; // default kAgcTrue (on)
|
||||
} WebRtcAgcConfig;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
@@ -50,14 +50,14 @@ extern "C"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This function processes a 10/20ms frame of far-end speech to determine
|
||||
* if there is active speech. Far-end speech length can be either 10ms or
|
||||
* 20ms. The length of the input speech vector must be given in samples
|
||||
* (80/160 when FS=8000, and 160/320 when FS=16000 or FS=32000).
|
||||
* This function processes a 10 ms frame of far-end speech to determine
|
||||
* if there is active speech. The length of the input speech vector must be
|
||||
* given in samples (80 when FS=8000, and 160 when FS=16000, FS=32000 or
|
||||
* FS=48000).
|
||||
*
|
||||
* Input:
|
||||
* - agcInst : AGC instance.
|
||||
* - inFar : Far-end input speech vector (10 or 20ms)
|
||||
* - inFar : Far-end input speech vector
|
||||
* - samples : Number of samples in input vector
|
||||
*
|
||||
* Return value:
|
||||
@@ -65,26 +65,23 @@ extern "C"
|
||||
* : -1 - Error
|
||||
*/
|
||||
int WebRtcAgc_AddFarend(void* agcInst,
|
||||
const WebRtc_Word16* inFar,
|
||||
WebRtc_Word16 samples);
|
||||
const int16_t* inFar,
|
||||
size_t samples);
|
||||
|
||||
/*
|
||||
* This function processes a 10/20ms frame of microphone speech to determine
|
||||
* if there is active speech. Microphone speech length can be either 10ms or
|
||||
* 20ms. The length of the input speech vector must be given in samples
|
||||
* (80/160 when FS=8000, and 160/320 when FS=16000 or FS=32000). For very low
|
||||
* input levels, the input signal is increased in level by multiplying and
|
||||
* overwriting the samples in inMic[].
|
||||
* This function processes a 10 ms frame of microphone speech to determine
|
||||
* if there is active speech. The length of the input speech vector must be
|
||||
* given in samples (80 when FS=8000, and 160 when FS=16000, FS=32000 or
|
||||
* FS=48000). For very low input levels, the input signal is increased in level
|
||||
* by multiplying and overwriting the samples in inMic[].
|
||||
*
|
||||
* This function should be called before any further processing of the
|
||||
* near-end microphone signal.
|
||||
*
|
||||
* Input:
|
||||
* - agcInst : AGC instance.
|
||||
* - inMic : Microphone input speech vector (10 or 20 ms) for
|
||||
* L band
|
||||
* - inMic_H : Microphone input speech vector (10 or 20 ms) for
|
||||
* H band
|
||||
* - inMic : Microphone input speech vector for each band
|
||||
* - num_bands : Number of bands in input vector
|
||||
* - samples : Number of samples in input vector
|
||||
*
|
||||
* Return value:
|
||||
@@ -92,24 +89,21 @@ int WebRtcAgc_AddFarend(void* agcInst,
|
||||
* : -1 - Error
|
||||
*/
|
||||
int WebRtcAgc_AddMic(void* agcInst,
|
||||
WebRtc_Word16* inMic,
|
||||
WebRtc_Word16* inMic_H,
|
||||
WebRtc_Word16 samples);
|
||||
int16_t* const* inMic,
|
||||
size_t num_bands,
|
||||
size_t samples);
|
||||
|
||||
/*
|
||||
* This function replaces the analog microphone with a virtual one.
|
||||
* It is a digital gain applied to the input signal and is used in the
|
||||
* agcAdaptiveDigital mode where no microphone level is adjustable.
|
||||
* Microphone speech length can be either 10ms or 20ms. The length of the
|
||||
* input speech vector must be given in samples (80/160 when FS=8000, and
|
||||
* 160/320 when FS=16000 or FS=32000).
|
||||
* agcAdaptiveDigital mode where no microphone level is adjustable. The length
|
||||
* of the input speech vector must be given in samples (80 when FS=8000, and 160
|
||||
* when FS=16000, FS=32000 or FS=48000).
|
||||
*
|
||||
* Input:
|
||||
* - agcInst : AGC instance.
|
||||
* - inMic : Microphone input speech vector for (10 or 20 ms)
|
||||
* L band
|
||||
* - inMic_H : Microphone input speech vector for (10 or 20 ms)
|
||||
* H band
|
||||
* - inMic : Microphone input speech vector for each band
|
||||
* - num_bands : Number of bands in input vector
|
||||
* - samples : Number of samples in input vector
|
||||
* - micLevelIn : Input level of microphone (static)
|
||||
*
|
||||
@@ -123,30 +117,27 @@ int WebRtcAgc_AddMic(void* agcInst,
|
||||
* : -1 - Error
|
||||
*/
|
||||
int WebRtcAgc_VirtualMic(void* agcInst,
|
||||
WebRtc_Word16* inMic,
|
||||
WebRtc_Word16* inMic_H,
|
||||
WebRtc_Word16 samples,
|
||||
WebRtc_Word32 micLevelIn,
|
||||
WebRtc_Word32* micLevelOut);
|
||||
int16_t* const* inMic,
|
||||
size_t num_bands,
|
||||
size_t samples,
|
||||
int32_t micLevelIn,
|
||||
int32_t* micLevelOut);
|
||||
|
||||
/*
|
||||
* This function processes a 10/20ms frame and adjusts (normalizes) the gain
|
||||
* both analog and digitally. The gain adjustments are done only during
|
||||
* active periods of speech. The input speech length can be either 10ms or
|
||||
* 20ms and the output is of the same length. The length of the speech
|
||||
* vectors must be given in samples (80/160 when FS=8000, and 160/320 when
|
||||
* FS=16000 or FS=32000). The echo parameter can be used to ensure the AGC will
|
||||
* not adjust upward in the presence of echo.
|
||||
* This function processes a 10 ms frame and adjusts (normalizes) the gain both
|
||||
* analog and digitally. The gain adjustments are done only during active
|
||||
* periods of speech. The length of the speech vectors must be given in samples
|
||||
* (80 when FS=8000, and 160 when FS=16000, FS=32000 or FS=48000). The echo
|
||||
* parameter can be used to ensure the AGC will not adjust upward in the
|
||||
* presence of echo.
|
||||
*
|
||||
* This function should be called after processing the near-end microphone
|
||||
* signal, in any case after any echo cancellation.
|
||||
*
|
||||
* Input:
|
||||
* - agcInst : AGC instance
|
||||
* - inNear : Near-end input speech vector (10 or 20 ms) for
|
||||
* L band
|
||||
* - inNear_H : Near-end input speech vector (10 or 20 ms) for
|
||||
* H band
|
||||
* - inNear : Near-end input speech vector for each band
|
||||
* - num_bands : Number of bands in input/output vector
|
||||
* - samples : Number of samples in input/output vector
|
||||
* - inMicLevel : Current microphone volume level
|
||||
* - echo : Set to 0 if the signal passed to add_mic is
|
||||
@@ -156,9 +147,8 @@ int WebRtcAgc_VirtualMic(void* agcInst,
|
||||
*
|
||||
* Output:
|
||||
* - outMicLevel : Adjusted microphone volume level
|
||||
* - out : Gain-adjusted near-end speech vector (L band)
|
||||
* - out : Gain-adjusted near-end speech vector
|
||||
* : May be the same vector as the input.
|
||||
* - out_H : Gain-adjusted near-end speech vector (H band)
|
||||
* - saturationWarning : A returned value of 1 indicates a saturation event
|
||||
* has occurred and the volume cannot be further
|
||||
* reduced. Otherwise will be set to 0.
|
||||
@@ -168,15 +158,14 @@ int WebRtcAgc_VirtualMic(void* agcInst,
|
||||
* : -1 - Error
|
||||
*/
|
||||
int WebRtcAgc_Process(void* agcInst,
|
||||
const WebRtc_Word16* inNear,
|
||||
const WebRtc_Word16* inNear_H,
|
||||
WebRtc_Word16 samples,
|
||||
WebRtc_Word16* out,
|
||||
WebRtc_Word16* out_H,
|
||||
WebRtc_Word32 inMicLevel,
|
||||
WebRtc_Word32* outMicLevel,
|
||||
WebRtc_Word16 echo,
|
||||
WebRtc_UWord8* saturationWarning);
|
||||
const int16_t* const* inNear,
|
||||
size_t num_bands,
|
||||
size_t samples,
|
||||
int16_t* const* out,
|
||||
int32_t inMicLevel,
|
||||
int32_t* outMicLevel,
|
||||
int16_t echo,
|
||||
uint8_t* saturationWarning);
|
||||
|
||||
/*
|
||||
* This function sets the config parameters (targetLevelDbfs,
|
||||
@@ -192,7 +181,7 @@ int WebRtcAgc_Process(void* agcInst,
|
||||
* : 0 - Normal operation.
|
||||
* : -1 - Error
|
||||
*/
|
||||
int WebRtcAgc_set_config(void* agcInst, WebRtcAgc_config_t config);
|
||||
int WebRtcAgc_set_config(void* agcInst, WebRtcAgcConfig config);
|
||||
|
||||
/*
|
||||
* This function returns the config parameters (targetLevelDbfs,
|
||||
@@ -208,27 +197,21 @@ int WebRtcAgc_set_config(void* agcInst, WebRtcAgc_config_t config);
|
||||
* : 0 - Normal operation.
|
||||
* : -1 - Error
|
||||
*/
|
||||
int WebRtcAgc_get_config(void* agcInst, WebRtcAgc_config_t* config);
|
||||
int WebRtcAgc_get_config(void* agcInst, WebRtcAgcConfig* config);
|
||||
|
||||
/*
|
||||
* This function creates an AGC instance, which will contain the state
|
||||
* information for one (duplex) channel.
|
||||
*
|
||||
* Return value : AGC instance if successful
|
||||
* : 0 (i.e., a NULL pointer) if unsuccessful
|
||||
* This function creates and returns an AGC instance, which will contain the
|
||||
* state information for one (duplex) channel.
|
||||
*/
|
||||
int WebRtcAgc_Create(void **agcInst);
|
||||
void* WebRtcAgc_Create();
|
||||
|
||||
/*
|
||||
* This function frees the AGC instance created at the beginning.
|
||||
*
|
||||
* Input:
|
||||
* - agcInst : AGC instance.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
int WebRtcAgc_Free(void *agcInst);
|
||||
void WebRtcAgc_Free(void* agcInst);
|
||||
|
||||
/*
|
||||
* This function initializes an AGC instance.
|
||||
@@ -247,27 +230,13 @@ int WebRtcAgc_Free(void *agcInst);
|
||||
* -1 - Error
|
||||
*/
|
||||
int WebRtcAgc_Init(void *agcInst,
|
||||
WebRtc_Word32 minLevel,
|
||||
WebRtc_Word32 maxLevel,
|
||||
WebRtc_Word16 agcMode,
|
||||
WebRtc_UWord32 fs);
|
||||
|
||||
/*
|
||||
* This function returns a text string containing the version.
|
||||
*
|
||||
* Input:
|
||||
* - length : Length of the char array pointed to by version
|
||||
* Output:
|
||||
* - version : Pointer to a char array of to which the version
|
||||
* : string will be copied.
|
||||
*
|
||||
* Return value : 0 - OK
|
||||
* -1 - Error
|
||||
*/
|
||||
int WebRtcAgc_Version(WebRtc_Word8 *versionStr, WebRtc_Word16 length);
|
||||
int32_t minLevel,
|
||||
int32_t maxLevel,
|
||||
int16_t agcMode,
|
||||
uint32_t fs);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_MAIN_INTERFACE_GAIN_CONTROL_H_
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_LEGACY_GAIN_CONTROL_H_
|
||||
35
webrtc/modules/audio_processing/agc/utility.cc
Normal file
35
webrtc/modules/audio_processing/agc/utility.cc
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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/modules/audio_processing/agc/utility.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
static const double kLog10 = 2.30258509299;
|
||||
static const double kLinear2DbScale = 20.0 / kLog10;
|
||||
static const double kLinear2LoudnessScale = 13.4 / kLog10;
|
||||
|
||||
double Loudness2Db(double loudness) {
|
||||
return loudness * kLinear2DbScale / kLinear2LoudnessScale;
|
||||
}
|
||||
|
||||
double Linear2Loudness(double rms) {
|
||||
if (rms == 0)
|
||||
return -15;
|
||||
return kLinear2LoudnessScale * log(rms);
|
||||
}
|
||||
|
||||
double Db2Loudness(double db) {
|
||||
return db * kLinear2LoudnessScale / kLinear2DbScale;
|
||||
}
|
||||
|
||||
double Dbfs2Loudness(double dbfs) {
|
||||
return Db2Loudness(90 + dbfs);
|
||||
}
|
||||
23
webrtc/modules/audio_processing/agc/utility.h
Normal file
23
webrtc/modules/audio_processing/agc/utility.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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_MODULES_AUDIO_PROCESSING_AGC_UTILITY_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_UTILITY_H_
|
||||
|
||||
// TODO(turajs): Add description of function.
|
||||
double Loudness2Db(double loudness);
|
||||
|
||||
double Linear2Loudness(double rms);
|
||||
|
||||
double Db2Loudness(double db);
|
||||
|
||||
double Dbfs2Loudness(double dbfs);
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_UTILITY_H_
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
* 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
|
||||
@@ -8,173 +8,331 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "audio_buffer.h"
|
||||
#include "webrtc/modules/audio_processing/audio_buffer.h"
|
||||
|
||||
#include "webrtc/common_audio/include/audio_util.h"
|
||||
#include "webrtc/common_audio/resampler/push_sinc_resampler.h"
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/common_audio/channel_buffer.h"
|
||||
#include "webrtc/modules/audio_processing/common.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
enum {
|
||||
kSamplesPer8kHzChannel = 80,
|
||||
kSamplesPer16kHzChannel = 160,
|
||||
kSamplesPer32kHzChannel = 320
|
||||
};
|
||||
const size_t kSamplesPer16kHzChannel = 160;
|
||||
const size_t kSamplesPer32kHzChannel = 320;
|
||||
const size_t kSamplesPer48kHzChannel = 480;
|
||||
|
||||
void StereoToMono(const WebRtc_Word16* left, const WebRtc_Word16* right,
|
||||
WebRtc_Word16* out, int samples_per_channel) {
|
||||
WebRtc_Word32 data_int32 = 0;
|
||||
for (int i = 0; i < samples_per_channel; i++) {
|
||||
data_int32 = (left[i] + right[i]) >> 1;
|
||||
if (data_int32 > 32767) {
|
||||
data_int32 = 32767;
|
||||
} else if (data_int32 < -32768) {
|
||||
data_int32 = -32768;
|
||||
}
|
||||
|
||||
out[i] = static_cast<WebRtc_Word16>(data_int32);
|
||||
int KeyboardChannelIndex(const StreamConfig& stream_config) {
|
||||
if (!stream_config.has_keyboard()) {
|
||||
assert(false);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return stream_config.num_channels();
|
||||
}
|
||||
|
||||
size_t NumBandsFromSamplesPerChannel(size_t num_frames) {
|
||||
size_t num_bands = 1;
|
||||
if (num_frames == kSamplesPer32kHzChannel ||
|
||||
num_frames == kSamplesPer48kHzChannel) {
|
||||
num_bands = rtc::CheckedDivExact(num_frames, kSamplesPer16kHzChannel);
|
||||
}
|
||||
return num_bands;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
struct AudioChannel {
|
||||
AudioChannel() {
|
||||
memset(data, 0, sizeof(data));
|
||||
}
|
||||
|
||||
WebRtc_Word16 data[kSamplesPer32kHzChannel];
|
||||
};
|
||||
|
||||
struct SplitAudioChannel {
|
||||
SplitAudioChannel() {
|
||||
memset(low_pass_data, 0, sizeof(low_pass_data));
|
||||
memset(high_pass_data, 0, sizeof(high_pass_data));
|
||||
memset(analysis_filter_state1, 0, sizeof(analysis_filter_state1));
|
||||
memset(analysis_filter_state2, 0, sizeof(analysis_filter_state2));
|
||||
memset(synthesis_filter_state1, 0, sizeof(synthesis_filter_state1));
|
||||
memset(synthesis_filter_state2, 0, sizeof(synthesis_filter_state2));
|
||||
}
|
||||
|
||||
WebRtc_Word16 low_pass_data[kSamplesPer16kHzChannel];
|
||||
WebRtc_Word16 high_pass_data[kSamplesPer16kHzChannel];
|
||||
|
||||
WebRtc_Word32 analysis_filter_state1[6];
|
||||
WebRtc_Word32 analysis_filter_state2[6];
|
||||
WebRtc_Word32 synthesis_filter_state1[6];
|
||||
WebRtc_Word32 synthesis_filter_state2[6];
|
||||
};
|
||||
|
||||
// TODO(andrew): check range of input parameters?
|
||||
AudioBuffer::AudioBuffer(int max_num_channels,
|
||||
int samples_per_channel)
|
||||
: max_num_channels_(max_num_channels),
|
||||
num_channels_(0),
|
||||
num_mixed_channels_(0),
|
||||
num_mixed_low_pass_channels_(0),
|
||||
samples_per_channel_(samples_per_channel),
|
||||
samples_per_split_channel_(samples_per_channel),
|
||||
AudioBuffer::AudioBuffer(size_t input_num_frames,
|
||||
int num_input_channels,
|
||||
size_t process_num_frames,
|
||||
int num_process_channels,
|
||||
size_t output_num_frames)
|
||||
: input_num_frames_(input_num_frames),
|
||||
num_input_channels_(num_input_channels),
|
||||
proc_num_frames_(process_num_frames),
|
||||
num_proc_channels_(num_process_channels),
|
||||
output_num_frames_(output_num_frames),
|
||||
num_channels_(num_process_channels),
|
||||
num_bands_(NumBandsFromSamplesPerChannel(proc_num_frames_)),
|
||||
num_split_frames_(rtc::CheckedDivExact(proc_num_frames_, num_bands_)),
|
||||
mixed_low_pass_valid_(false),
|
||||
reference_copied_(false),
|
||||
activity_(AudioFrame::kVadUnknown),
|
||||
data_(NULL),
|
||||
channels_(NULL),
|
||||
split_channels_(NULL),
|
||||
mixed_low_pass_channels_(NULL),
|
||||
low_pass_reference_channels_(NULL) {
|
||||
if (max_num_channels_ > 1) {
|
||||
channels_ = new AudioChannel[max_num_channels_];
|
||||
mixed_low_pass_channels_ = new AudioChannel[max_num_channels_];
|
||||
}
|
||||
low_pass_reference_channels_ = new AudioChannel[max_num_channels_];
|
||||
keyboard_data_(NULL),
|
||||
data_(new IFChannelBuffer(proc_num_frames_, num_proc_channels_)) {
|
||||
assert(input_num_frames_ > 0);
|
||||
assert(proc_num_frames_ > 0);
|
||||
assert(output_num_frames_ > 0);
|
||||
assert(num_input_channels_ > 0);
|
||||
assert(num_proc_channels_ > 0 && num_proc_channels_ <= num_input_channels_);
|
||||
|
||||
if (samples_per_channel_ == kSamplesPer32kHzChannel) {
|
||||
split_channels_ = new SplitAudioChannel[max_num_channels_];
|
||||
samples_per_split_channel_ = kSamplesPer16kHzChannel;
|
||||
if (input_num_frames_ != proc_num_frames_ ||
|
||||
output_num_frames_ != proc_num_frames_) {
|
||||
// Create an intermediate buffer for resampling.
|
||||
process_buffer_.reset(new ChannelBuffer<float>(proc_num_frames_,
|
||||
num_proc_channels_));
|
||||
|
||||
if (input_num_frames_ != proc_num_frames_) {
|
||||
for (int i = 0; i < num_proc_channels_; ++i) {
|
||||
input_resamplers_.push_back(
|
||||
new PushSincResampler(input_num_frames_,
|
||||
proc_num_frames_));
|
||||
}
|
||||
}
|
||||
|
||||
if (output_num_frames_ != proc_num_frames_) {
|
||||
for (int i = 0; i < num_proc_channels_; ++i) {
|
||||
output_resamplers_.push_back(
|
||||
new PushSincResampler(proc_num_frames_,
|
||||
output_num_frames_));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (num_bands_ > 1) {
|
||||
split_data_.reset(new IFChannelBuffer(proc_num_frames_,
|
||||
num_proc_channels_,
|
||||
num_bands_));
|
||||
splitting_filter_.reset(new SplittingFilter(num_proc_channels_,
|
||||
num_bands_,
|
||||
proc_num_frames_));
|
||||
}
|
||||
}
|
||||
|
||||
AudioBuffer::~AudioBuffer() {
|
||||
if (channels_ != NULL) {
|
||||
delete [] channels_;
|
||||
AudioBuffer::~AudioBuffer() {}
|
||||
|
||||
void AudioBuffer::CopyFrom(const float* const* data,
|
||||
const StreamConfig& stream_config) {
|
||||
assert(stream_config.num_frames() == input_num_frames_);
|
||||
assert(stream_config.num_channels() == num_input_channels_);
|
||||
InitForNewData();
|
||||
// Initialized lazily because there's a different condition in
|
||||
// DeinterleaveFrom.
|
||||
const bool need_to_downmix =
|
||||
num_input_channels_ > 1 && num_proc_channels_ == 1;
|
||||
if (need_to_downmix && !input_buffer_) {
|
||||
input_buffer_.reset(
|
||||
new IFChannelBuffer(input_num_frames_, num_proc_channels_));
|
||||
}
|
||||
|
||||
if (mixed_low_pass_channels_ != NULL) {
|
||||
delete [] mixed_low_pass_channels_;
|
||||
if (stream_config.has_keyboard()) {
|
||||
keyboard_data_ = data[KeyboardChannelIndex(stream_config)];
|
||||
}
|
||||
|
||||
if (low_pass_reference_channels_ != NULL) {
|
||||
delete [] low_pass_reference_channels_;
|
||||
// Downmix.
|
||||
const float* const* data_ptr = data;
|
||||
if (need_to_downmix) {
|
||||
DownmixToMono<float, float>(data, input_num_frames_, num_input_channels_,
|
||||
input_buffer_->fbuf()->channels()[0]);
|
||||
data_ptr = input_buffer_->fbuf_const()->channels();
|
||||
}
|
||||
|
||||
if (split_channels_ != NULL) {
|
||||
delete [] split_channels_;
|
||||
// Resample.
|
||||
if (input_num_frames_ != proc_num_frames_) {
|
||||
for (int i = 0; i < num_proc_channels_; ++i) {
|
||||
input_resamplers_[i]->Resample(data_ptr[i],
|
||||
input_num_frames_,
|
||||
process_buffer_->channels()[i],
|
||||
proc_num_frames_);
|
||||
}
|
||||
data_ptr = process_buffer_->channels();
|
||||
}
|
||||
|
||||
// Convert to the S16 range.
|
||||
for (int i = 0; i < num_proc_channels_; ++i) {
|
||||
FloatToFloatS16(data_ptr[i],
|
||||
proc_num_frames_,
|
||||
data_->fbuf()->channels()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
WebRtc_Word16* AudioBuffer::data(int channel) const {
|
||||
assert(channel >= 0 && channel < num_channels_);
|
||||
if (data_ != NULL) {
|
||||
return data_;
|
||||
void AudioBuffer::CopyTo(const StreamConfig& stream_config,
|
||||
float* const* data) {
|
||||
assert(stream_config.num_frames() == output_num_frames_);
|
||||
assert(stream_config.num_channels() == num_channels_);
|
||||
|
||||
// Convert to the float range.
|
||||
float* const* data_ptr = data;
|
||||
if (output_num_frames_ != proc_num_frames_) {
|
||||
// Convert to an intermediate buffer for subsequent resampling.
|
||||
data_ptr = process_buffer_->channels();
|
||||
}
|
||||
for (int i = 0; i < num_channels_; ++i) {
|
||||
FloatS16ToFloat(data_->fbuf()->channels()[i],
|
||||
proc_num_frames_,
|
||||
data_ptr[i]);
|
||||
}
|
||||
|
||||
return channels_[channel].data;
|
||||
// Resample.
|
||||
if (output_num_frames_ != proc_num_frames_) {
|
||||
for (int i = 0; i < num_channels_; ++i) {
|
||||
output_resamplers_[i]->Resample(data_ptr[i],
|
||||
proc_num_frames_,
|
||||
data[i],
|
||||
output_num_frames_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WebRtc_Word16* AudioBuffer::low_pass_split_data(int channel) const {
|
||||
assert(channel >= 0 && channel < num_channels_);
|
||||
if (split_channels_ == NULL) {
|
||||
return data(channel);
|
||||
void AudioBuffer::InitForNewData() {
|
||||
keyboard_data_ = NULL;
|
||||
mixed_low_pass_valid_ = false;
|
||||
reference_copied_ = false;
|
||||
activity_ = AudioFrame::kVadUnknown;
|
||||
num_channels_ = num_proc_channels_;
|
||||
}
|
||||
|
||||
const int16_t* const* AudioBuffer::channels_const() const {
|
||||
return data_->ibuf_const()->channels();
|
||||
}
|
||||
|
||||
int16_t* const* AudioBuffer::channels() {
|
||||
mixed_low_pass_valid_ = false;
|
||||
return data_->ibuf()->channels();
|
||||
}
|
||||
|
||||
const int16_t* const* AudioBuffer::split_bands_const(int channel) const {
|
||||
return split_data_.get() ?
|
||||
split_data_->ibuf_const()->bands(channel) :
|
||||
data_->ibuf_const()->bands(channel);
|
||||
}
|
||||
|
||||
int16_t* const* AudioBuffer::split_bands(int channel) {
|
||||
mixed_low_pass_valid_ = false;
|
||||
return split_data_.get() ?
|
||||
split_data_->ibuf()->bands(channel) :
|
||||
data_->ibuf()->bands(channel);
|
||||
}
|
||||
|
||||
const int16_t* const* AudioBuffer::split_channels_const(Band band) const {
|
||||
if (split_data_.get()) {
|
||||
return split_data_->ibuf_const()->channels(band);
|
||||
} else {
|
||||
return band == kBand0To8kHz ? data_->ibuf_const()->channels() : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t* const* AudioBuffer::split_channels(Band band) {
|
||||
mixed_low_pass_valid_ = false;
|
||||
if (split_data_.get()) {
|
||||
return split_data_->ibuf()->channels(band);
|
||||
} else {
|
||||
return band == kBand0To8kHz ? data_->ibuf()->channels() : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ChannelBuffer<int16_t>* AudioBuffer::data() {
|
||||
mixed_low_pass_valid_ = false;
|
||||
return data_->ibuf();
|
||||
}
|
||||
|
||||
const ChannelBuffer<int16_t>* AudioBuffer::data() const {
|
||||
return data_->ibuf_const();
|
||||
}
|
||||
|
||||
ChannelBuffer<int16_t>* AudioBuffer::split_data() {
|
||||
mixed_low_pass_valid_ = false;
|
||||
return split_data_.get() ? split_data_->ibuf() : data_->ibuf();
|
||||
}
|
||||
|
||||
const ChannelBuffer<int16_t>* AudioBuffer::split_data() const {
|
||||
return split_data_.get() ? split_data_->ibuf_const() : data_->ibuf_const();
|
||||
}
|
||||
|
||||
const float* const* AudioBuffer::channels_const_f() const {
|
||||
return data_->fbuf_const()->channels();
|
||||
}
|
||||
|
||||
float* const* AudioBuffer::channels_f() {
|
||||
mixed_low_pass_valid_ = false;
|
||||
return data_->fbuf()->channels();
|
||||
}
|
||||
|
||||
const float* const* AudioBuffer::split_bands_const_f(int channel) const {
|
||||
return split_data_.get() ?
|
||||
split_data_->fbuf_const()->bands(channel) :
|
||||
data_->fbuf_const()->bands(channel);
|
||||
}
|
||||
|
||||
float* const* AudioBuffer::split_bands_f(int channel) {
|
||||
mixed_low_pass_valid_ = false;
|
||||
return split_data_.get() ?
|
||||
split_data_->fbuf()->bands(channel) :
|
||||
data_->fbuf()->bands(channel);
|
||||
}
|
||||
|
||||
const float* const* AudioBuffer::split_channels_const_f(Band band) const {
|
||||
if (split_data_.get()) {
|
||||
return split_data_->fbuf_const()->channels(band);
|
||||
} else {
|
||||
return band == kBand0To8kHz ? data_->fbuf_const()->channels() : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
float* const* AudioBuffer::split_channels_f(Band band) {
|
||||
mixed_low_pass_valid_ = false;
|
||||
if (split_data_.get()) {
|
||||
return split_data_->fbuf()->channels(band);
|
||||
} else {
|
||||
return band == kBand0To8kHz ? data_->fbuf()->channels() : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ChannelBuffer<float>* AudioBuffer::data_f() {
|
||||
mixed_low_pass_valid_ = false;
|
||||
return data_->fbuf();
|
||||
}
|
||||
|
||||
const ChannelBuffer<float>* AudioBuffer::data_f() const {
|
||||
return data_->fbuf_const();
|
||||
}
|
||||
|
||||
ChannelBuffer<float>* AudioBuffer::split_data_f() {
|
||||
mixed_low_pass_valid_ = false;
|
||||
return split_data_.get() ? split_data_->fbuf() : data_->fbuf();
|
||||
}
|
||||
|
||||
const ChannelBuffer<float>* AudioBuffer::split_data_f() const {
|
||||
return split_data_.get() ? split_data_->fbuf_const() : data_->fbuf_const();
|
||||
}
|
||||
|
||||
const int16_t* AudioBuffer::mixed_low_pass_data() {
|
||||
if (num_proc_channels_ == 1) {
|
||||
return split_bands_const(0)[kBand0To8kHz];
|
||||
}
|
||||
|
||||
return split_channels_[channel].low_pass_data;
|
||||
}
|
||||
if (!mixed_low_pass_valid_) {
|
||||
if (!mixed_low_pass_channels_.get()) {
|
||||
mixed_low_pass_channels_.reset(
|
||||
new ChannelBuffer<int16_t>(num_split_frames_, 1));
|
||||
}
|
||||
|
||||
WebRtc_Word16* AudioBuffer::high_pass_split_data(int channel) const {
|
||||
assert(channel >= 0 && channel < num_channels_);
|
||||
if (split_channels_ == NULL) {
|
||||
return NULL;
|
||||
DownmixToMono<int16_t, int32_t>(split_channels_const(kBand0To8kHz),
|
||||
num_split_frames_, num_channels_,
|
||||
mixed_low_pass_channels_->channels()[0]);
|
||||
mixed_low_pass_valid_ = true;
|
||||
}
|
||||
|
||||
return split_channels_[channel].high_pass_data;
|
||||
return mixed_low_pass_channels_->channels()[0];
|
||||
}
|
||||
|
||||
WebRtc_Word16* AudioBuffer::mixed_low_pass_data(int channel) const {
|
||||
assert(channel >= 0 && channel < num_mixed_low_pass_channels_);
|
||||
|
||||
return mixed_low_pass_channels_[channel].data;
|
||||
}
|
||||
|
||||
WebRtc_Word16* AudioBuffer::low_pass_reference(int channel) const {
|
||||
assert(channel >= 0 && channel < num_channels_);
|
||||
const int16_t* AudioBuffer::low_pass_reference(int channel) const {
|
||||
if (!reference_copied_) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return low_pass_reference_channels_[channel].data;
|
||||
return low_pass_reference_channels_->channels()[channel];
|
||||
}
|
||||
|
||||
WebRtc_Word32* AudioBuffer::analysis_filter_state1(int channel) const {
|
||||
assert(channel >= 0 && channel < num_channels_);
|
||||
return split_channels_[channel].analysis_filter_state1;
|
||||
}
|
||||
|
||||
WebRtc_Word32* AudioBuffer::analysis_filter_state2(int channel) const {
|
||||
assert(channel >= 0 && channel < num_channels_);
|
||||
return split_channels_[channel].analysis_filter_state2;
|
||||
}
|
||||
|
||||
WebRtc_Word32* AudioBuffer::synthesis_filter_state1(int channel) const {
|
||||
assert(channel >= 0 && channel < num_channels_);
|
||||
return split_channels_[channel].synthesis_filter_state1;
|
||||
}
|
||||
|
||||
WebRtc_Word32* AudioBuffer::synthesis_filter_state2(int channel) const {
|
||||
assert(channel >= 0 && channel < num_channels_);
|
||||
return split_channels_[channel].synthesis_filter_state2;
|
||||
const float* AudioBuffer::keyboard_data() const {
|
||||
return keyboard_data_;
|
||||
}
|
||||
|
||||
void AudioBuffer::set_activity(AudioFrame::VADActivity activity) {
|
||||
activity_ = activity;
|
||||
}
|
||||
|
||||
AudioFrame::VADActivity AudioBuffer::activity() {
|
||||
AudioFrame::VADActivity AudioBuffer::activity() const {
|
||||
return activity_;
|
||||
}
|
||||
|
||||
@@ -182,107 +340,123 @@ int AudioBuffer::num_channels() const {
|
||||
return num_channels_;
|
||||
}
|
||||
|
||||
int AudioBuffer::samples_per_channel() const {
|
||||
return samples_per_channel_;
|
||||
void AudioBuffer::set_num_channels(int num_channels) {
|
||||
num_channels_ = num_channels;
|
||||
}
|
||||
|
||||
int AudioBuffer::samples_per_split_channel() const {
|
||||
return samples_per_split_channel_;
|
||||
size_t AudioBuffer::num_frames() const {
|
||||
return proc_num_frames_;
|
||||
}
|
||||
|
||||
// TODO(andrew): Do deinterleaving and mixing in one step?
|
||||
size_t AudioBuffer::num_frames_per_band() const {
|
||||
return num_split_frames_;
|
||||
}
|
||||
|
||||
size_t AudioBuffer::num_keyboard_frames() const {
|
||||
// We don't resample the keyboard channel.
|
||||
return input_num_frames_;
|
||||
}
|
||||
|
||||
size_t AudioBuffer::num_bands() const {
|
||||
return num_bands_;
|
||||
}
|
||||
|
||||
// The resampler is only for supporting 48kHz to 16kHz in the reverse stream.
|
||||
void AudioBuffer::DeinterleaveFrom(AudioFrame* frame) {
|
||||
assert(frame->_audioChannel <= max_num_channels_);
|
||||
assert(frame->_payloadDataLengthInSamples == samples_per_channel_);
|
||||
assert(frame->num_channels_ == num_input_channels_);
|
||||
assert(frame->samples_per_channel_ == input_num_frames_);
|
||||
InitForNewData();
|
||||
// Initialized lazily because there's a different condition in CopyFrom.
|
||||
if ((input_num_frames_ != proc_num_frames_) && !input_buffer_) {
|
||||
input_buffer_.reset(
|
||||
new IFChannelBuffer(input_num_frames_, num_proc_channels_));
|
||||
}
|
||||
activity_ = frame->vad_activity_;
|
||||
|
||||
num_channels_ = frame->_audioChannel;
|
||||
num_mixed_channels_ = 0;
|
||||
num_mixed_low_pass_channels_ = 0;
|
||||
reference_copied_ = false;
|
||||
activity_ = frame->_vadActivity;
|
||||
int16_t* const* deinterleaved;
|
||||
if (input_num_frames_ == proc_num_frames_) {
|
||||
deinterleaved = data_->ibuf()->channels();
|
||||
} else {
|
||||
deinterleaved = input_buffer_->ibuf()->channels();
|
||||
}
|
||||
if (num_proc_channels_ == 1) {
|
||||
// Downmix and deinterleave simultaneously.
|
||||
DownmixInterleavedToMono(frame->data_, input_num_frames_,
|
||||
num_input_channels_, deinterleaved[0]);
|
||||
} else {
|
||||
assert(num_proc_channels_ == num_input_channels_);
|
||||
Deinterleave(frame->data_,
|
||||
input_num_frames_,
|
||||
num_proc_channels_,
|
||||
deinterleaved);
|
||||
}
|
||||
|
||||
if (num_channels_ == 1) {
|
||||
// We can get away with a pointer assignment in this case.
|
||||
data_ = frame->_payloadData;
|
||||
// Resample.
|
||||
if (input_num_frames_ != proc_num_frames_) {
|
||||
for (int i = 0; i < num_proc_channels_; ++i) {
|
||||
input_resamplers_[i]->Resample(input_buffer_->fbuf_const()->channels()[i],
|
||||
input_num_frames_,
|
||||
data_->fbuf()->channels()[i],
|
||||
proc_num_frames_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBuffer::InterleaveTo(AudioFrame* frame, bool data_changed) {
|
||||
frame->vad_activity_ = activity_;
|
||||
if (!data_changed) {
|
||||
return;
|
||||
}
|
||||
|
||||
WebRtc_Word16* interleaved = frame->_payloadData;
|
||||
for (int i = 0; i < num_channels_; i++) {
|
||||
WebRtc_Word16* deinterleaved = channels_[i].data;
|
||||
int interleaved_idx = i;
|
||||
for (int j = 0; j < samples_per_channel_; j++) {
|
||||
deinterleaved[j] = interleaved[interleaved_idx];
|
||||
interleaved_idx += num_channels_;
|
||||
assert(frame->num_channels_ == num_channels_ || num_channels_ == 1);
|
||||
assert(frame->samples_per_channel_ == output_num_frames_);
|
||||
|
||||
// Resample if necessary.
|
||||
IFChannelBuffer* data_ptr = data_.get();
|
||||
if (proc_num_frames_ != output_num_frames_) {
|
||||
if (!output_buffer_) {
|
||||
output_buffer_.reset(
|
||||
new IFChannelBuffer(output_num_frames_, num_channels_));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBuffer::InterleaveTo(AudioFrame* frame) const {
|
||||
assert(frame->_audioChannel == num_channels_);
|
||||
assert(frame->_payloadDataLengthInSamples == samples_per_channel_);
|
||||
frame->_vadActivity = activity_;
|
||||
|
||||
if (num_channels_ == 1) {
|
||||
if (num_mixed_channels_ == 1) {
|
||||
memcpy(frame->_payloadData,
|
||||
channels_[0].data,
|
||||
sizeof(WebRtc_Word16) * samples_per_channel_);
|
||||
} else {
|
||||
// These should point to the same buffer in this case.
|
||||
assert(data_ == frame->_payloadData);
|
||||
for (int i = 0; i < num_channels_; ++i) {
|
||||
output_resamplers_[i]->Resample(
|
||||
data_->fbuf()->channels()[i], proc_num_frames_,
|
||||
output_buffer_->fbuf()->channels()[i], output_num_frames_);
|
||||
}
|
||||
|
||||
return;
|
||||
data_ptr = output_buffer_.get();
|
||||
}
|
||||
|
||||
WebRtc_Word16* interleaved = frame->_payloadData;
|
||||
for (int i = 0; i < num_channels_; i++) {
|
||||
WebRtc_Word16* deinterleaved = channels_[i].data;
|
||||
int interleaved_idx = i;
|
||||
for (int j = 0; j < samples_per_channel_; j++) {
|
||||
interleaved[interleaved_idx] = deinterleaved[j];
|
||||
interleaved_idx += num_channels_;
|
||||
}
|
||||
if (frame->num_channels_ == num_channels_) {
|
||||
Interleave(data_ptr->ibuf()->channels(), proc_num_frames_, num_channels_,
|
||||
frame->data_);
|
||||
} else {
|
||||
UpmixMonoToInterleaved(data_ptr->ibuf()->channels()[0], proc_num_frames_,
|
||||
frame->num_channels_, frame->data_);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(andrew): would be good to support the no-mix case with pointer
|
||||
// assignment.
|
||||
// TODO(andrew): handle mixing to multiple channels?
|
||||
void AudioBuffer::Mix(int num_mixed_channels) {
|
||||
// We currently only support the stereo to mono case.
|
||||
assert(num_channels_ == 2);
|
||||
assert(num_mixed_channels == 1);
|
||||
|
||||
StereoToMono(channels_[0].data,
|
||||
channels_[1].data,
|
||||
channels_[0].data,
|
||||
samples_per_channel_);
|
||||
|
||||
num_channels_ = num_mixed_channels;
|
||||
num_mixed_channels_ = num_mixed_channels;
|
||||
}
|
||||
|
||||
void AudioBuffer::CopyAndMixLowPass(int num_mixed_channels) {
|
||||
// We currently only support the stereo to mono case.
|
||||
assert(num_channels_ == 2);
|
||||
assert(num_mixed_channels == 1);
|
||||
|
||||
StereoToMono(low_pass_split_data(0),
|
||||
low_pass_split_data(1),
|
||||
mixed_low_pass_channels_[0].data,
|
||||
samples_per_split_channel_);
|
||||
|
||||
num_mixed_low_pass_channels_ = num_mixed_channels;
|
||||
}
|
||||
|
||||
void AudioBuffer::CopyLowPassToReference() {
|
||||
reference_copied_ = true;
|
||||
for (int i = 0; i < num_channels_; i++) {
|
||||
memcpy(low_pass_reference_channels_[i].data,
|
||||
low_pass_split_data(i),
|
||||
sizeof(WebRtc_Word16) * samples_per_split_channel_);
|
||||
if (!low_pass_reference_channels_.get() ||
|
||||
low_pass_reference_channels_->num_channels() != num_channels_) {
|
||||
low_pass_reference_channels_.reset(
|
||||
new ChannelBuffer<int16_t>(num_split_frames_,
|
||||
num_proc_channels_));
|
||||
}
|
||||
for (int i = 0; i < num_proc_channels_; i++) {
|
||||
memcpy(low_pass_reference_channels_->channels()[i],
|
||||
split_bands_const(i)[kBand0To8kHz],
|
||||
low_pass_reference_channels_->num_frames_per_band() *
|
||||
sizeof(split_bands_const(i)[kBand0To8kHz][0]));
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBuffer::SplitIntoFrequencyBands() {
|
||||
splitting_filter_->Analysis(data_.get(), split_data_.get());
|
||||
}
|
||||
|
||||
void AudioBuffer::MergeFrequencyBands() {
|
||||
splitting_filter_->Synthesis(split_data_.get(), data_.get());
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@@ -8,64 +8,156 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_BUFFER_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_BUFFER_H_
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AUDIO_BUFFER_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AUDIO_BUFFER_H_
|
||||
|
||||
#include "module_common_types.h"
|
||||
#include "typedefs.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/common_audio/channel_buffer.h"
|
||||
#include "webrtc/modules/audio_processing/include/audio_processing.h"
|
||||
#include "webrtc/modules/audio_processing/splitting_filter.h"
|
||||
#include "webrtc/modules/interface/module_common_types.h"
|
||||
#include "webrtc/system_wrappers/interface/scoped_vector.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
struct AudioChannel;
|
||||
struct SplitAudioChannel;
|
||||
class PushSincResampler;
|
||||
class IFChannelBuffer;
|
||||
|
||||
enum Band {
|
||||
kBand0To8kHz = 0,
|
||||
kBand8To16kHz = 1,
|
||||
kBand16To24kHz = 2
|
||||
};
|
||||
|
||||
class AudioBuffer {
|
||||
public:
|
||||
AudioBuffer(int max_num_channels, int samples_per_channel);
|
||||
// TODO(ajm): Switch to take ChannelLayouts.
|
||||
AudioBuffer(size_t input_num_frames,
|
||||
int num_input_channels,
|
||||
size_t process_num_frames,
|
||||
int num_process_channels,
|
||||
size_t output_num_frames);
|
||||
virtual ~AudioBuffer();
|
||||
|
||||
int num_channels() const;
|
||||
int samples_per_channel() const;
|
||||
int samples_per_split_channel() const;
|
||||
void set_num_channels(int num_channels);
|
||||
size_t num_frames() const;
|
||||
size_t num_frames_per_band() const;
|
||||
size_t num_keyboard_frames() const;
|
||||
size_t num_bands() const;
|
||||
|
||||
WebRtc_Word16* data(int channel) const;
|
||||
WebRtc_Word16* low_pass_split_data(int channel) const;
|
||||
WebRtc_Word16* high_pass_split_data(int channel) const;
|
||||
WebRtc_Word16* mixed_low_pass_data(int channel) const;
|
||||
WebRtc_Word16* low_pass_reference(int channel) const;
|
||||
// Returns a pointer array to the full-band channels.
|
||||
// Usage:
|
||||
// channels()[channel][sample].
|
||||
// Where:
|
||||
// 0 <= channel < |num_proc_channels_|
|
||||
// 0 <= sample < |proc_num_frames_|
|
||||
int16_t* const* channels();
|
||||
const int16_t* const* channels_const() const;
|
||||
float* const* channels_f();
|
||||
const float* const* channels_const_f() const;
|
||||
|
||||
WebRtc_Word32* analysis_filter_state1(int channel) const;
|
||||
WebRtc_Word32* analysis_filter_state2(int channel) const;
|
||||
WebRtc_Word32* synthesis_filter_state1(int channel) const;
|
||||
WebRtc_Word32* synthesis_filter_state2(int channel) const;
|
||||
// Returns a pointer array to the bands for a specific channel.
|
||||
// Usage:
|
||||
// split_bands(channel)[band][sample].
|
||||
// Where:
|
||||
// 0 <= channel < |num_proc_channels_|
|
||||
// 0 <= band < |num_bands_|
|
||||
// 0 <= sample < |num_split_frames_|
|
||||
int16_t* const* split_bands(int channel);
|
||||
const int16_t* const* split_bands_const(int channel) const;
|
||||
float* const* split_bands_f(int channel);
|
||||
const float* const* split_bands_const_f(int channel) const;
|
||||
|
||||
// Returns a pointer array to the channels for a specific band.
|
||||
// Usage:
|
||||
// split_channels(band)[channel][sample].
|
||||
// Where:
|
||||
// 0 <= band < |num_bands_|
|
||||
// 0 <= channel < |num_proc_channels_|
|
||||
// 0 <= sample < |num_split_frames_|
|
||||
int16_t* const* split_channels(Band band);
|
||||
const int16_t* const* split_channels_const(Band band) const;
|
||||
float* const* split_channels_f(Band band);
|
||||
const float* const* split_channels_const_f(Band band) const;
|
||||
|
||||
// Returns a pointer to the ChannelBuffer that encapsulates the full-band
|
||||
// data.
|
||||
ChannelBuffer<int16_t>* data();
|
||||
const ChannelBuffer<int16_t>* data() const;
|
||||
ChannelBuffer<float>* data_f();
|
||||
const ChannelBuffer<float>* data_f() const;
|
||||
|
||||
// Returns a pointer to the ChannelBuffer that encapsulates the split data.
|
||||
ChannelBuffer<int16_t>* split_data();
|
||||
const ChannelBuffer<int16_t>* split_data() const;
|
||||
ChannelBuffer<float>* split_data_f();
|
||||
const ChannelBuffer<float>* split_data_f() const;
|
||||
|
||||
// Returns a pointer to the low-pass data downmixed to mono. If this data
|
||||
// isn't already available it re-calculates it.
|
||||
const int16_t* mixed_low_pass_data();
|
||||
const int16_t* low_pass_reference(int channel) const;
|
||||
|
||||
const float* keyboard_data() const;
|
||||
|
||||
void set_activity(AudioFrame::VADActivity activity);
|
||||
AudioFrame::VADActivity activity();
|
||||
AudioFrame::VADActivity activity() const;
|
||||
|
||||
// Use for int16 interleaved data.
|
||||
void DeinterleaveFrom(AudioFrame* audioFrame);
|
||||
void InterleaveTo(AudioFrame* audioFrame) const;
|
||||
void Mix(int num_mixed_channels);
|
||||
void CopyAndMixLowPass(int num_mixed_channels);
|
||||
// If |data_changed| is false, only the non-audio data members will be copied
|
||||
// to |frame|.
|
||||
void InterleaveTo(AudioFrame* frame, bool data_changed);
|
||||
|
||||
// Use for float deinterleaved data.
|
||||
void CopyFrom(const float* const* data, const StreamConfig& stream_config);
|
||||
void CopyTo(const StreamConfig& stream_config, float* const* data);
|
||||
void CopyLowPassToReference();
|
||||
|
||||
// Splits the signal into different bands.
|
||||
void SplitIntoFrequencyBands();
|
||||
// Recombine the different bands into one signal.
|
||||
void MergeFrequencyBands();
|
||||
|
||||
private:
|
||||
const int max_num_channels_;
|
||||
// Called from DeinterleaveFrom() and CopyFrom().
|
||||
void InitForNewData();
|
||||
|
||||
// The audio is passed into DeinterleaveFrom() or CopyFrom() with input
|
||||
// format (samples per channel and number of channels).
|
||||
const size_t input_num_frames_;
|
||||
const int num_input_channels_;
|
||||
// The audio is stored by DeinterleaveFrom() or CopyFrom() with processing
|
||||
// format.
|
||||
const size_t proc_num_frames_;
|
||||
const int num_proc_channels_;
|
||||
// The audio is returned by InterleaveTo() and CopyTo() with output samples
|
||||
// per channels and the current number of channels. This last one can be
|
||||
// changed at any time using set_num_channels().
|
||||
const size_t output_num_frames_;
|
||||
int num_channels_;
|
||||
int num_mixed_channels_;
|
||||
int num_mixed_low_pass_channels_;
|
||||
const int samples_per_channel_;
|
||||
int samples_per_split_channel_;
|
||||
|
||||
size_t num_bands_;
|
||||
size_t num_split_frames_;
|
||||
bool mixed_low_pass_valid_;
|
||||
bool reference_copied_;
|
||||
AudioFrame::VADActivity activity_;
|
||||
|
||||
WebRtc_Word16* data_;
|
||||
// TODO(andrew): use vectors here.
|
||||
AudioChannel* channels_;
|
||||
SplitAudioChannel* split_channels_;
|
||||
// TODO(andrew): improve this, we don't need the full 32 kHz space here.
|
||||
AudioChannel* mixed_low_pass_channels_;
|
||||
AudioChannel* low_pass_reference_channels_;
|
||||
const float* keyboard_data_;
|
||||
rtc::scoped_ptr<IFChannelBuffer> data_;
|
||||
rtc::scoped_ptr<IFChannelBuffer> split_data_;
|
||||
rtc::scoped_ptr<SplittingFilter> splitting_filter_;
|
||||
rtc::scoped_ptr<ChannelBuffer<int16_t> > mixed_low_pass_channels_;
|
||||
rtc::scoped_ptr<ChannelBuffer<int16_t> > low_pass_reference_channels_;
|
||||
rtc::scoped_ptr<IFChannelBuffer> input_buffer_;
|
||||
rtc::scoped_ptr<IFChannelBuffer> output_buffer_;
|
||||
rtc::scoped_ptr<ChannelBuffer<float> > process_buffer_;
|
||||
ScopedVector<PushSincResampler> input_resamplers_;
|
||||
ScopedVector<PushSincResampler> output_resamplers_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_BUFFER_H_
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AUDIO_BUFFER_H_
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
* 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
|
||||
@@ -8,81 +8,140 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_PROCESSING_IMPL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_PROCESSING_IMPL_H_
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AUDIO_PROCESSING_IMPL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AUDIO_PROCESSING_IMPL_H_
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "audio_processing.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/base/thread_annotations.h"
|
||||
#include "webrtc/modules/audio_processing/include/audio_processing.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace audioproc {
|
||||
class Event;
|
||||
} // audioproc
|
||||
|
||||
class AgcManagerDirect;
|
||||
class AudioBuffer;
|
||||
class AudioConverter;
|
||||
|
||||
template<typename T>
|
||||
class Beamformer;
|
||||
|
||||
class CriticalSectionWrapper;
|
||||
class EchoCancellationImpl;
|
||||
class EchoControlMobileImpl;
|
||||
class FileWrapper;
|
||||
class GainControlImpl;
|
||||
class GainControlForNewAgc;
|
||||
class HighPassFilterImpl;
|
||||
class LevelEstimatorImpl;
|
||||
class NoiseSuppressionImpl;
|
||||
class ProcessingComponent;
|
||||
class TransientSuppressor;
|
||||
class VoiceDetectionImpl;
|
||||
class IntelligibilityEnhancer;
|
||||
|
||||
#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
|
||||
namespace audioproc {
|
||||
|
||||
class Event;
|
||||
|
||||
} // namespace audioproc
|
||||
#endif
|
||||
|
||||
class AudioProcessingImpl : public AudioProcessing {
|
||||
public:
|
||||
enum {
|
||||
kSampleRate8kHz = 8000,
|
||||
kSampleRate16kHz = 16000,
|
||||
kSampleRate32kHz = 32000
|
||||
};
|
||||
explicit AudioProcessingImpl(const Config& config);
|
||||
|
||||
explicit AudioProcessingImpl(int id);
|
||||
// AudioProcessingImpl takes ownership of beamformer.
|
||||
AudioProcessingImpl(const Config& config, Beamformer<float>* beamformer);
|
||||
virtual ~AudioProcessingImpl();
|
||||
|
||||
CriticalSectionWrapper* crit() const;
|
||||
|
||||
int split_sample_rate_hz() const;
|
||||
bool was_stream_delay_set() const;
|
||||
|
||||
// AudioProcessing methods.
|
||||
virtual int Initialize();
|
||||
virtual int InitializeLocked();
|
||||
virtual int set_sample_rate_hz(int rate);
|
||||
virtual int sample_rate_hz() const;
|
||||
virtual int set_num_channels(int input_channels, int output_channels);
|
||||
virtual int num_input_channels() const;
|
||||
virtual int num_output_channels() const;
|
||||
virtual int set_num_reverse_channels(int channels);
|
||||
virtual int num_reverse_channels() const;
|
||||
virtual int ProcessStream(AudioFrame* frame);
|
||||
virtual int AnalyzeReverseStream(AudioFrame* frame);
|
||||
virtual int set_stream_delay_ms(int delay);
|
||||
virtual int stream_delay_ms() const;
|
||||
virtual int StartDebugRecording(const char filename[kMaxFilenameSize]);
|
||||
virtual int StopDebugRecording();
|
||||
virtual EchoCancellation* echo_cancellation() const;
|
||||
virtual EchoControlMobile* echo_control_mobile() const;
|
||||
virtual GainControl* gain_control() const;
|
||||
virtual HighPassFilter* high_pass_filter() const;
|
||||
virtual LevelEstimator* level_estimator() const;
|
||||
virtual NoiseSuppression* noise_suppression() const;
|
||||
virtual VoiceDetection* voice_detection() const;
|
||||
int Initialize() override;
|
||||
int Initialize(int input_sample_rate_hz,
|
||||
int output_sample_rate_hz,
|
||||
int reverse_sample_rate_hz,
|
||||
ChannelLayout input_layout,
|
||||
ChannelLayout output_layout,
|
||||
ChannelLayout reverse_layout) override;
|
||||
int Initialize(const ProcessingConfig& processing_config) override;
|
||||
void SetExtraOptions(const Config& config) override;
|
||||
int proc_sample_rate_hz() const override;
|
||||
int proc_split_sample_rate_hz() const override;
|
||||
int num_input_channels() const override;
|
||||
int num_output_channels() const override;
|
||||
int num_reverse_channels() const override;
|
||||
void set_output_will_be_muted(bool muted) override;
|
||||
int ProcessStream(AudioFrame* frame) override;
|
||||
int ProcessStream(const float* const* src,
|
||||
size_t samples_per_channel,
|
||||
int input_sample_rate_hz,
|
||||
ChannelLayout input_layout,
|
||||
int output_sample_rate_hz,
|
||||
ChannelLayout output_layout,
|
||||
float* const* dest) override;
|
||||
int ProcessStream(const float* const* src,
|
||||
const StreamConfig& input_config,
|
||||
const StreamConfig& output_config,
|
||||
float* const* dest) override;
|
||||
int AnalyzeReverseStream(AudioFrame* frame) override;
|
||||
int ProcessReverseStream(AudioFrame* frame) override;
|
||||
int AnalyzeReverseStream(const float* const* data,
|
||||
size_t samples_per_channel,
|
||||
int sample_rate_hz,
|
||||
ChannelLayout layout) override;
|
||||
int ProcessReverseStream(const float* const* src,
|
||||
const StreamConfig& reverse_input_config,
|
||||
const StreamConfig& reverse_output_config,
|
||||
float* const* dest) override;
|
||||
int set_stream_delay_ms(int delay) override;
|
||||
int stream_delay_ms() const override;
|
||||
bool was_stream_delay_set() const override;
|
||||
void set_delay_offset_ms(int offset) override;
|
||||
int delay_offset_ms() const override;
|
||||
void set_stream_key_pressed(bool key_pressed) override;
|
||||
int StartDebugRecording(const char filename[kMaxFilenameSize]) override;
|
||||
int StartDebugRecording(FILE* handle) override;
|
||||
int StartDebugRecordingForPlatformFile(rtc::PlatformFile handle) override;
|
||||
int StopDebugRecording() override;
|
||||
void UpdateHistogramsOnCallEnd() override;
|
||||
EchoCancellation* echo_cancellation() const override;
|
||||
EchoControlMobile* echo_control_mobile() const override;
|
||||
GainControl* gain_control() const override;
|
||||
HighPassFilter* high_pass_filter() const override;
|
||||
LevelEstimator* level_estimator() const override;
|
||||
NoiseSuppression* noise_suppression() const override;
|
||||
VoiceDetection* voice_detection() const override;
|
||||
|
||||
// Module methods.
|
||||
virtual WebRtc_Word32 Version(WebRtc_Word8* version,
|
||||
WebRtc_UWord32& remainingBufferInBytes,
|
||||
WebRtc_UWord32& position) const;
|
||||
virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id);
|
||||
protected:
|
||||
// Overridden in a mock.
|
||||
virtual int InitializeLocked() EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
|
||||
private:
|
||||
int WriteMessageToDebugFile();
|
||||
int WriteInitMessage();
|
||||
int InitializeLocked(const ProcessingConfig& config)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
int MaybeInitializeLocked(const ProcessingConfig& config)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
// TODO(ekm): Remove once all clients updated to new interface.
|
||||
int AnalyzeReverseStream(const float* const* src,
|
||||
const StreamConfig& input_config,
|
||||
const StreamConfig& output_config);
|
||||
int ProcessStreamLocked() EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
int ProcessReverseStreamLocked() EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
|
||||
int id_;
|
||||
bool is_data_processed() const;
|
||||
bool output_copy_needed(bool is_data_processed) const;
|
||||
bool synthesis_needed(bool is_data_processed) const;
|
||||
bool analysis_needed(bool is_data_processed) const;
|
||||
bool is_rev_processed() const;
|
||||
bool rev_conversion_needed() const;
|
||||
void InitializeExperimentalAgc() EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
void InitializeTransient() EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
void InitializeBeamformer() EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
void InitializeIntelligibility() EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
void MaybeUpdateHistograms() EXCLUSIVE_LOCKS_REQUIRED(crit_);
|
||||
|
||||
EchoCancellationImpl* echo_cancellation_;
|
||||
EchoControlMobileImpl* echo_control_mobile_;
|
||||
@@ -91,27 +150,69 @@ class AudioProcessingImpl : public AudioProcessing {
|
||||
LevelEstimatorImpl* level_estimator_;
|
||||
NoiseSuppressionImpl* noise_suppression_;
|
||||
VoiceDetectionImpl* voice_detection_;
|
||||
rtc::scoped_ptr<GainControlForNewAgc> gain_control_for_new_agc_;
|
||||
|
||||
std::list<ProcessingComponent*> component_list_;
|
||||
|
||||
FileWrapper* debug_file_;
|
||||
audioproc::Event* event_msg_; // Protobuf message.
|
||||
std::string event_str_; // Memory for protobuf serialization.
|
||||
CriticalSectionWrapper* crit_;
|
||||
rtc::scoped_ptr<AudioBuffer> render_audio_;
|
||||
rtc::scoped_ptr<AudioBuffer> capture_audio_;
|
||||
rtc::scoped_ptr<AudioConverter> render_converter_;
|
||||
#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
|
||||
// TODO(andrew): make this more graceful. Ideally we would split this stuff
|
||||
// out into a separate class with an "enabled" and "disabled" implementation.
|
||||
int WriteMessageToDebugFile();
|
||||
int WriteInitMessage();
|
||||
|
||||
AudioBuffer* render_audio_;
|
||||
AudioBuffer* capture_audio_;
|
||||
// Writes Config message. If not |forced|, only writes the current config if
|
||||
// it is different from the last saved one; if |forced|, writes the config
|
||||
// regardless of the last saved.
|
||||
int WriteConfigMessage(bool forced);
|
||||
|
||||
rtc::scoped_ptr<FileWrapper> debug_file_;
|
||||
rtc::scoped_ptr<audioproc::Event> event_msg_; // Protobuf message.
|
||||
std::string event_str_; // Memory for protobuf serialization.
|
||||
|
||||
// Serialized string of last saved APM configuration.
|
||||
std::string last_serialized_config_;
|
||||
#endif
|
||||
|
||||
// Format of processing streams at input/output call sites.
|
||||
ProcessingConfig api_format_;
|
||||
|
||||
// Only the rate and samples fields of fwd_proc_format_ are used because the
|
||||
// forward processing number of channels is mutable and is tracked by the
|
||||
// capture_audio_.
|
||||
StreamConfig fwd_proc_format_;
|
||||
StreamConfig rev_proc_format_;
|
||||
int split_rate_;
|
||||
|
||||
int sample_rate_hz_;
|
||||
int split_sample_rate_hz_;
|
||||
int samples_per_channel_;
|
||||
int stream_delay_ms_;
|
||||
int delay_offset_ms_;
|
||||
bool was_stream_delay_set_;
|
||||
int last_stream_delay_ms_;
|
||||
int last_aec_system_delay_ms_;
|
||||
int stream_delay_jumps_;
|
||||
int aec_system_delay_jumps_;
|
||||
|
||||
int num_reverse_channels_;
|
||||
int num_input_channels_;
|
||||
int num_output_channels_;
|
||||
bool output_will_be_muted_ GUARDED_BY(crit_);
|
||||
|
||||
bool key_pressed_;
|
||||
|
||||
// Only set through the constructor's Config parameter.
|
||||
const bool use_new_agc_;
|
||||
rtc::scoped_ptr<AgcManagerDirect> agc_manager_ GUARDED_BY(crit_);
|
||||
int agc_startup_min_volume_;
|
||||
|
||||
bool transient_suppressor_enabled_;
|
||||
rtc::scoped_ptr<TransientSuppressor> transient_suppressor_;
|
||||
const bool beamformer_enabled_;
|
||||
rtc::scoped_ptr<Beamformer<float>> beamformer_;
|
||||
const std::vector<Point> array_geometry_;
|
||||
|
||||
bool intelligibility_enabled_;
|
||||
rtc::scoped_ptr<IntelligibilityEnhancer> intelligibility_enhancer_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_PROCESSING_IMPL_H_
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AUDIO_PROCESSING_IMPL_H_
|
||||
|
||||
58
webrtc/modules/audio_processing/beamformer/array_util.h
Normal file
58
webrtc/modules/audio_processing/beamformer/array_util.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_ARRAY_UTIL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_ARRAY_UTIL_H_
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Coordinates in meters.
|
||||
template<typename T>
|
||||
struct CartesianPoint {
|
||||
CartesianPoint(T x, T y, T z) {
|
||||
c[0] = x;
|
||||
c[1] = y;
|
||||
c[2] = z;
|
||||
}
|
||||
T x() const { return c[0]; }
|
||||
T y() const { return c[1]; }
|
||||
T z() const { return c[2]; }
|
||||
T c[3];
|
||||
};
|
||||
|
||||
using Point = CartesianPoint<float>;
|
||||
|
||||
template<typename T>
|
||||
float Distance(CartesianPoint<T> a, CartesianPoint<T> b) {
|
||||
return std::sqrt((a.x() - b.x()) * (a.x() - b.x()) +
|
||||
(a.y() - b.y()) * (a.y() - b.y()) +
|
||||
(a.z() - b.z()) * (a.z() - b.z()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct SphericalPoint {
|
||||
SphericalPoint(T azimuth, T elevation, T radius) {
|
||||
s[0] = azimuth;
|
||||
s[1] = elevation;
|
||||
s[2] = radius;
|
||||
}
|
||||
T azimuth() const { return s[0]; }
|
||||
T elevation() const { return s[1]; }
|
||||
T distance() const { return s[2]; }
|
||||
T s[3];
|
||||
};
|
||||
|
||||
using SphericalPointf = SphericalPoint<float>;
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_ARRAY_UTIL_H_
|
||||
45
webrtc/modules/audio_processing/beamformer/beamformer.h
Normal file
45
webrtc/modules/audio_processing/beamformer/beamformer.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_BEAMFORMER_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_BEAMFORMER_H_
|
||||
|
||||
#include "webrtc/common_audio/channel_buffer.h"
|
||||
#include "webrtc/modules/audio_processing/beamformer/array_util.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
template<typename T>
|
||||
class Beamformer {
|
||||
public:
|
||||
virtual ~Beamformer() {}
|
||||
|
||||
// Process one time-domain chunk of audio. The audio is expected to be split
|
||||
// into frequency bands inside the ChannelBuffer. The number of frames and
|
||||
// channels must correspond to the constructor parameters. The same
|
||||
// ChannelBuffer can be passed in as |input| and |output|.
|
||||
virtual void ProcessChunk(const ChannelBuffer<T>& input,
|
||||
ChannelBuffer<T>* output) = 0;
|
||||
|
||||
// Sample rate corresponds to the lower band.
|
||||
// Needs to be called before the the Beamformer can be used.
|
||||
virtual void Initialize(int chunk_size_ms, int sample_rate_hz) = 0;
|
||||
|
||||
// Indicates whether a given point is inside of the beam.
|
||||
virtual bool IsInBeam(const SphericalPointf& spherical_point) { return true; }
|
||||
|
||||
// Returns true if the current data contains the target signal.
|
||||
// Which signals are considered "targets" is implementation dependent.
|
||||
virtual bool is_target_present() = 0;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_BEAMFORMER_H_
|
||||
97
webrtc/modules/audio_processing/beamformer/complex_matrix.h
Normal file
97
webrtc/modules/audio_processing/beamformer/complex_matrix.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_COMPLEX_MATRIX_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_COMPLEX_MATRIX_H_
|
||||
|
||||
#include <complex>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
#include "webrtc/modules/audio_processing/beamformer/matrix.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
using std::complex;
|
||||
|
||||
// An extension of Matrix for operations that only work on a complex type.
|
||||
template <typename T>
|
||||
class ComplexMatrix : public Matrix<complex<T> > {
|
||||
public:
|
||||
ComplexMatrix() : Matrix<complex<T> >() {}
|
||||
|
||||
ComplexMatrix(int num_rows, int num_columns)
|
||||
: Matrix<complex<T> >(num_rows, num_columns) {}
|
||||
|
||||
ComplexMatrix(const complex<T>* data, int num_rows, int num_columns)
|
||||
: Matrix<complex<T> >(data, num_rows, num_columns) {}
|
||||
|
||||
// Complex Matrix operations.
|
||||
ComplexMatrix& PointwiseConjugate() {
|
||||
complex<T>* const data = this->data();
|
||||
size_t size = this->num_rows() * this->num_columns();
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
data[i] = conj(data[i]);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ComplexMatrix& PointwiseConjugate(const ComplexMatrix& operand) {
|
||||
this->CopyFrom(operand);
|
||||
return PointwiseConjugate();
|
||||
}
|
||||
|
||||
ComplexMatrix& ConjugateTranspose() {
|
||||
this->CopyDataToScratch();
|
||||
int num_rows = this->num_rows();
|
||||
this->SetNumRows(this->num_columns());
|
||||
this->SetNumColumns(num_rows);
|
||||
this->Resize();
|
||||
return ConjugateTranspose(this->scratch_elements());
|
||||
}
|
||||
|
||||
ComplexMatrix& ConjugateTranspose(const ComplexMatrix& operand) {
|
||||
RTC_CHECK_EQ(operand.num_rows(), this->num_columns());
|
||||
RTC_CHECK_EQ(operand.num_columns(), this->num_rows());
|
||||
return ConjugateTranspose(operand.elements());
|
||||
}
|
||||
|
||||
ComplexMatrix& ZeroImag() {
|
||||
complex<T>* const data = this->data();
|
||||
size_t size = this->num_rows() * this->num_columns();
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
data[i] = complex<T>(data[i].real(), 0);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ComplexMatrix& ZeroImag(const ComplexMatrix& operand) {
|
||||
this->CopyFrom(operand);
|
||||
return ZeroImag();
|
||||
}
|
||||
|
||||
private:
|
||||
ComplexMatrix& ConjugateTranspose(const complex<T>* const* src) {
|
||||
complex<T>* const* elements = this->elements();
|
||||
for (int i = 0; i < this->num_rows(); ++i) {
|
||||
for (int j = 0; j < this->num_columns(); ++j) {
|
||||
elements[i][j] = conj(src[j][i]);
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_COMPLEX_MATRIX_H_
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
|
||||
#include "webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace {
|
||||
|
||||
float BesselJ0(float x) {
|
||||
#if WEBRTC_WIN
|
||||
return _j0(x);
|
||||
#else
|
||||
return j0(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
void CovarianceMatrixGenerator::UniformCovarianceMatrix(
|
||||
float wave_number,
|
||||
const std::vector<Point>& geometry,
|
||||
ComplexMatrix<float>* mat) {
|
||||
RTC_CHECK_EQ(static_cast<int>(geometry.size()), mat->num_rows());
|
||||
RTC_CHECK_EQ(static_cast<int>(geometry.size()), mat->num_columns());
|
||||
|
||||
complex<float>* const* mat_els = mat->elements();
|
||||
for (size_t i = 0; i < geometry.size(); ++i) {
|
||||
for (size_t j = 0; j < geometry.size(); ++j) {
|
||||
if (wave_number > 0.f) {
|
||||
mat_els[i][j] =
|
||||
BesselJ0(wave_number * Distance(geometry[i], geometry[j]));
|
||||
} else {
|
||||
mat_els[i][j] = i == j ? 1.f : 0.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CovarianceMatrixGenerator::AngledCovarianceMatrix(
|
||||
float sound_speed,
|
||||
float angle,
|
||||
size_t frequency_bin,
|
||||
size_t fft_size,
|
||||
size_t num_freq_bins,
|
||||
int sample_rate,
|
||||
const std::vector<Point>& geometry,
|
||||
ComplexMatrix<float>* mat) {
|
||||
RTC_CHECK_EQ(static_cast<int>(geometry.size()), mat->num_rows());
|
||||
RTC_CHECK_EQ(static_cast<int>(geometry.size()), mat->num_columns());
|
||||
|
||||
ComplexMatrix<float> interf_cov_vector(1, geometry.size());
|
||||
ComplexMatrix<float> interf_cov_vector_transposed(geometry.size(), 1);
|
||||
PhaseAlignmentMasks(frequency_bin,
|
||||
fft_size,
|
||||
sample_rate,
|
||||
sound_speed,
|
||||
geometry,
|
||||
angle,
|
||||
&interf_cov_vector);
|
||||
interf_cov_vector_transposed.Transpose(interf_cov_vector);
|
||||
interf_cov_vector.PointwiseConjugate();
|
||||
mat->Multiply(interf_cov_vector_transposed, interf_cov_vector);
|
||||
}
|
||||
|
||||
void CovarianceMatrixGenerator::PhaseAlignmentMasks(
|
||||
size_t frequency_bin,
|
||||
size_t fft_size,
|
||||
int sample_rate,
|
||||
float sound_speed,
|
||||
const std::vector<Point>& geometry,
|
||||
float angle,
|
||||
ComplexMatrix<float>* mat) {
|
||||
RTC_CHECK_EQ(1, mat->num_rows());
|
||||
RTC_CHECK_EQ(static_cast<int>(geometry.size()), mat->num_columns());
|
||||
|
||||
float freq_in_hertz =
|
||||
(static_cast<float>(frequency_bin) / fft_size) * sample_rate;
|
||||
|
||||
complex<float>* const* mat_els = mat->elements();
|
||||
for (size_t c_ix = 0; c_ix < geometry.size(); ++c_ix) {
|
||||
float distance = std::cos(angle) * geometry[c_ix].x() +
|
||||
std::sin(angle) * geometry[c_ix].y();
|
||||
float phase_shift = -2.f * M_PI * distance * freq_in_hertz / sound_speed;
|
||||
|
||||
// Euler's formula for mat[0][c_ix] = e^(j * phase_shift).
|
||||
mat_els[0][c_ix] = complex<float>(cos(phase_shift), sin(phase_shift));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_COVARIANCE_MATRIX_GENERATOR_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_COVARIANCE_MATRIX_GENERATOR_H_
|
||||
|
||||
#include "webrtc/modules/audio_processing/beamformer/complex_matrix.h"
|
||||
#include "webrtc/modules/audio_processing/beamformer/array_util.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Helper class for Beamformer in charge of generating covariance matrices. For
|
||||
// each function, the passed-in ComplexMatrix is expected to be of size
|
||||
// |num_input_channels| x |num_input_channels|.
|
||||
class CovarianceMatrixGenerator {
|
||||
public:
|
||||
// A uniform covariance matrix with a gap at the target location. WARNING:
|
||||
// The target angle is assumed to be 0.
|
||||
static void UniformCovarianceMatrix(float wave_number,
|
||||
const std::vector<Point>& geometry,
|
||||
ComplexMatrix<float>* mat);
|
||||
|
||||
// The covariance matrix of a source at the given angle.
|
||||
static void AngledCovarianceMatrix(float sound_speed,
|
||||
float angle,
|
||||
size_t frequency_bin,
|
||||
size_t fft_size,
|
||||
size_t num_freq_bins,
|
||||
int sample_rate,
|
||||
const std::vector<Point>& geometry,
|
||||
ComplexMatrix<float>* mat);
|
||||
|
||||
// Calculates phase shifts that, when applied to a multichannel signal and
|
||||
// added together, cause constructive interferernce for sources located at
|
||||
// the given angle.
|
||||
static void PhaseAlignmentMasks(size_t frequency_bin,
|
||||
size_t fft_size,
|
||||
int sample_rate,
|
||||
float sound_speed,
|
||||
const std::vector<Point>& geometry,
|
||||
float angle,
|
||||
ComplexMatrix<float>* mat);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_BF_HELPERS_H_
|
||||
368
webrtc/modules/audio_processing/beamformer/matrix.h
Normal file
368
webrtc/modules/audio_processing/beamformer/matrix.h
Normal file
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/base/constructormagic.h"
|
||||
#include "webrtc/base/scoped_ptr.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Wrappers to get around the compiler warning resulting from the fact that
|
||||
// there's no std::sqrt overload for ints. We cast all non-complex types to
|
||||
// a double for the sqrt method.
|
||||
template <typename T>
|
||||
T sqrt_wrapper(T x) {
|
||||
return sqrt(static_cast<double>(x));
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
std::complex<S> sqrt_wrapper(std::complex<S> x) {
|
||||
return sqrt(x);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Matrix is a class for doing standard matrix operations on 2 dimensional
|
||||
// matrices of any size. Results of matrix operations are stored in the
|
||||
// calling object. Function overloads exist for both in-place (the calling
|
||||
// object is used as both an operand and the result) and out-of-place (all
|
||||
// operands are passed in as parameters) operations. If operand dimensions
|
||||
// mismatch, the program crashes. Out-of-place operations change the size of
|
||||
// the calling object, if necessary, before operating.
|
||||
//
|
||||
// 'In-place' operations that inherently change the size of the matrix (eg.
|
||||
// Transpose, Multiply on different-sized matrices) must make temporary copies
|
||||
// (|scratch_elements_| and |scratch_data_|) of existing data to complete the
|
||||
// operations.
|
||||
//
|
||||
// The data is stored contiguously. Data can be accessed internally as a flat
|
||||
// array, |data_|, or as an array of row pointers, |elements_|, but is
|
||||
// available to users only as an array of row pointers through |elements()|.
|
||||
// Memory for storage is allocated when a matrix is resized only if the new
|
||||
// size overflows capacity. Memory needed temporarily for any operations is
|
||||
// similarly resized only if the new size overflows capacity.
|
||||
//
|
||||
// If you pass in storage through the ctor, that storage is copied into the
|
||||
// matrix. TODO(claguna): albeit tricky, allow for data to be referenced
|
||||
// instead of copied, and owned by the user.
|
||||
template <typename T>
|
||||
class Matrix {
|
||||
public:
|
||||
Matrix() : num_rows_(0), num_columns_(0) {}
|
||||
|
||||
// Allocates space for the elements and initializes all values to zero.
|
||||
Matrix(int num_rows, int num_columns)
|
||||
: num_rows_(num_rows), num_columns_(num_columns) {
|
||||
Resize();
|
||||
scratch_data_.resize(num_rows_ * num_columns_);
|
||||
scratch_elements_.resize(num_rows_);
|
||||
}
|
||||
|
||||
// Copies |data| into the new Matrix.
|
||||
Matrix(const T* data, int num_rows, int num_columns)
|
||||
: num_rows_(0), num_columns_(0) {
|
||||
CopyFrom(data, num_rows, num_columns);
|
||||
scratch_data_.resize(num_rows_ * num_columns_);
|
||||
scratch_elements_.resize(num_rows_);
|
||||
}
|
||||
|
||||
virtual ~Matrix() {}
|
||||
|
||||
// Deep copy an existing matrix.
|
||||
void CopyFrom(const Matrix& other) {
|
||||
CopyFrom(&other.data_[0], other.num_rows_, other.num_columns_);
|
||||
}
|
||||
|
||||
// Copy |data| into the Matrix. The current data is lost.
|
||||
void CopyFrom(const T* const data, int num_rows, int num_columns) {
|
||||
Resize(num_rows, num_columns);
|
||||
memcpy(&data_[0], data, num_rows_ * num_columns_ * sizeof(data_[0]));
|
||||
}
|
||||
|
||||
Matrix& CopyFromColumn(const T* const* src,
|
||||
size_t column_index,
|
||||
int num_rows) {
|
||||
Resize(1, num_rows);
|
||||
for (int i = 0; i < num_columns_; ++i) {
|
||||
data_[i] = src[i][column_index];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Resize(int num_rows, int num_columns) {
|
||||
if (num_rows != num_rows_ || num_columns != num_columns_) {
|
||||
num_rows_ = num_rows;
|
||||
num_columns_ = num_columns;
|
||||
Resize();
|
||||
}
|
||||
}
|
||||
|
||||
// Accessors and mutators.
|
||||
int num_rows() const { return num_rows_; }
|
||||
int num_columns() const { return num_columns_; }
|
||||
T* const* elements() { return &elements_[0]; }
|
||||
const T* const* elements() const { return &elements_[0]; }
|
||||
|
||||
T Trace() {
|
||||
RTC_CHECK_EQ(num_rows_, num_columns_);
|
||||
|
||||
T trace = 0;
|
||||
for (int i = 0; i < num_rows_; ++i) {
|
||||
trace += elements_[i][i];
|
||||
}
|
||||
return trace;
|
||||
}
|
||||
|
||||
// Matrix Operations. Returns *this to support method chaining.
|
||||
Matrix& Transpose() {
|
||||
CopyDataToScratch();
|
||||
Resize(num_columns_, num_rows_);
|
||||
return Transpose(scratch_elements());
|
||||
}
|
||||
|
||||
Matrix& Transpose(const Matrix& operand) {
|
||||
RTC_CHECK_EQ(operand.num_rows_, num_columns_);
|
||||
RTC_CHECK_EQ(operand.num_columns_, num_rows_);
|
||||
|
||||
return Transpose(operand.elements());
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
Matrix& Scale(const S& scalar) {
|
||||
for (size_t i = 0; i < data_.size(); ++i) {
|
||||
data_[i] *= scalar;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
Matrix& Scale(const Matrix& operand, const S& scalar) {
|
||||
CopyFrom(operand);
|
||||
return Scale(scalar);
|
||||
}
|
||||
|
||||
Matrix& Add(const Matrix& operand) {
|
||||
RTC_CHECK_EQ(num_rows_, operand.num_rows_);
|
||||
RTC_CHECK_EQ(num_columns_, operand.num_columns_);
|
||||
|
||||
for (size_t i = 0; i < data_.size(); ++i) {
|
||||
data_[i] += operand.data_[i];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Matrix& Add(const Matrix& lhs, const Matrix& rhs) {
|
||||
CopyFrom(lhs);
|
||||
return Add(rhs);
|
||||
}
|
||||
|
||||
Matrix& Subtract(const Matrix& operand) {
|
||||
RTC_CHECK_EQ(num_rows_, operand.num_rows_);
|
||||
RTC_CHECK_EQ(num_columns_, operand.num_columns_);
|
||||
|
||||
for (size_t i = 0; i < data_.size(); ++i) {
|
||||
data_[i] -= operand.data_[i];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Matrix& Subtract(const Matrix& lhs, const Matrix& rhs) {
|
||||
CopyFrom(lhs);
|
||||
return Subtract(rhs);
|
||||
}
|
||||
|
||||
Matrix& PointwiseMultiply(const Matrix& operand) {
|
||||
RTC_CHECK_EQ(num_rows_, operand.num_rows_);
|
||||
RTC_CHECK_EQ(num_columns_, operand.num_columns_);
|
||||
|
||||
for (size_t i = 0; i < data_.size(); ++i) {
|
||||
data_[i] *= operand.data_[i];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Matrix& PointwiseMultiply(const Matrix& lhs, const Matrix& rhs) {
|
||||
CopyFrom(lhs);
|
||||
return PointwiseMultiply(rhs);
|
||||
}
|
||||
|
||||
Matrix& PointwiseDivide(const Matrix& operand) {
|
||||
RTC_CHECK_EQ(num_rows_, operand.num_rows_);
|
||||
RTC_CHECK_EQ(num_columns_, operand.num_columns_);
|
||||
|
||||
for (size_t i = 0; i < data_.size(); ++i) {
|
||||
data_[i] /= operand.data_[i];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Matrix& PointwiseDivide(const Matrix& lhs, const Matrix& rhs) {
|
||||
CopyFrom(lhs);
|
||||
return PointwiseDivide(rhs);
|
||||
}
|
||||
|
||||
Matrix& PointwiseSquareRoot() {
|
||||
for (size_t i = 0; i < data_.size(); ++i) {
|
||||
data_[i] = sqrt_wrapper(data_[i]);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Matrix& PointwiseSquareRoot(const Matrix& operand) {
|
||||
CopyFrom(operand);
|
||||
return PointwiseSquareRoot();
|
||||
}
|
||||
|
||||
Matrix& PointwiseAbsoluteValue() {
|
||||
for (size_t i = 0; i < data_.size(); ++i) {
|
||||
data_[i] = abs(data_[i]);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Matrix& PointwiseAbsoluteValue(const Matrix& operand) {
|
||||
CopyFrom(operand);
|
||||
return PointwiseAbsoluteValue();
|
||||
}
|
||||
|
||||
Matrix& PointwiseSquare() {
|
||||
for (size_t i = 0; i < data_.size(); ++i) {
|
||||
data_[i] *= data_[i];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Matrix& PointwiseSquare(const Matrix& operand) {
|
||||
CopyFrom(operand);
|
||||
return PointwiseSquare();
|
||||
}
|
||||
|
||||
Matrix& Multiply(const Matrix& lhs, const Matrix& rhs) {
|
||||
RTC_CHECK_EQ(lhs.num_columns_, rhs.num_rows_);
|
||||
RTC_CHECK_EQ(num_rows_, lhs.num_rows_);
|
||||
RTC_CHECK_EQ(num_columns_, rhs.num_columns_);
|
||||
|
||||
return Multiply(lhs.elements(), rhs.num_rows_, rhs.elements());
|
||||
}
|
||||
|
||||
Matrix& Multiply(const Matrix& rhs) {
|
||||
RTC_CHECK_EQ(num_columns_, rhs.num_rows_);
|
||||
|
||||
CopyDataToScratch();
|
||||
Resize(num_rows_, rhs.num_columns_);
|
||||
return Multiply(scratch_elements(), rhs.num_rows_, rhs.elements());
|
||||
}
|
||||
|
||||
std::string ToString() const {
|
||||
std::ostringstream ss;
|
||||
ss << std::endl << "Matrix" << std::endl;
|
||||
|
||||
for (int i = 0; i < num_rows_; ++i) {
|
||||
for (int j = 0; j < num_columns_; ++j) {
|
||||
ss << elements_[i][j] << " ";
|
||||
}
|
||||
ss << std::endl;
|
||||
}
|
||||
ss << std::endl;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetNumRows(const int num_rows) { num_rows_ = num_rows; }
|
||||
void SetNumColumns(const int num_columns) { num_columns_ = num_columns; }
|
||||
T* data() { return &data_[0]; }
|
||||
const T* data() const { return &data_[0]; }
|
||||
const T* const* scratch_elements() const { return &scratch_elements_[0]; }
|
||||
|
||||
// Resize the matrix. If an increase in capacity is required, the current
|
||||
// data is lost.
|
||||
void Resize() {
|
||||
size_t size = num_rows_ * num_columns_;
|
||||
data_.resize(size);
|
||||
elements_.resize(num_rows_);
|
||||
|
||||
for (int i = 0; i < num_rows_; ++i) {
|
||||
elements_[i] = &data_[i * num_columns_];
|
||||
}
|
||||
}
|
||||
|
||||
// Copies data_ into scratch_data_ and updates scratch_elements_ accordingly.
|
||||
void CopyDataToScratch() {
|
||||
scratch_data_ = data_;
|
||||
scratch_elements_.resize(num_rows_);
|
||||
|
||||
for (int i = 0; i < num_rows_; ++i) {
|
||||
scratch_elements_[i] = &scratch_data_[i * num_columns_];
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int num_rows_;
|
||||
int num_columns_;
|
||||
std::vector<T> data_;
|
||||
std::vector<T*> elements_;
|
||||
|
||||
// Stores temporary copies of |data_| and |elements_| for in-place operations
|
||||
// where referring to original data is necessary.
|
||||
std::vector<T> scratch_data_;
|
||||
std::vector<T*> scratch_elements_;
|
||||
|
||||
// Helpers for Transpose and Multiply operations that unify in-place and
|
||||
// out-of-place solutions.
|
||||
Matrix& Transpose(const T* const* src) {
|
||||
for (int i = 0; i < num_rows_; ++i) {
|
||||
for (int j = 0; j < num_columns_; ++j) {
|
||||
elements_[i][j] = src[j][i];
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Matrix& Multiply(const T* const* lhs, int num_rows_rhs, const T* const* rhs) {
|
||||
for (int row = 0; row < num_rows_; ++row) {
|
||||
for (int col = 0; col < num_columns_; ++col) {
|
||||
T cur_element = 0;
|
||||
for (int i = 0; i < num_rows_rhs; ++i) {
|
||||
cur_element += lhs[row][i] * rhs[i][col];
|
||||
}
|
||||
|
||||
elements_[row][col] = cur_element;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(Matrix);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_H_
|
||||
102
webrtc/modules/audio_processing/beamformer/matrix_test_helpers.h
Normal file
102
webrtc/modules/audio_processing/beamformer/matrix_test_helpers.h
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_TEST_HELPERS_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_TEST_HELPERS_H_
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/modules/audio_processing/beamformer/complex_matrix.h"
|
||||
#include "webrtc/modules/audio_processing/beamformer/matrix.h"
|
||||
|
||||
namespace {
|
||||
const float kTolerance = 0.001f;
|
||||
}
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
using std::complex;
|
||||
|
||||
// Functions used in both matrix_unittest and complex_matrix_unittest.
|
||||
class MatrixTestHelpers {
|
||||
public:
|
||||
template <typename T>
|
||||
static void ValidateMatrixEquality(const Matrix<T>& expected,
|
||||
const Matrix<T>& actual) {
|
||||
EXPECT_EQ(expected.num_rows(), actual.num_rows());
|
||||
EXPECT_EQ(expected.num_columns(), actual.num_columns());
|
||||
|
||||
const T* const* expected_elements = expected.elements();
|
||||
const T* const* actual_elements = actual.elements();
|
||||
for (int i = 0; i < expected.num_rows(); ++i) {
|
||||
for (int j = 0; j < expected.num_columns(); ++j) {
|
||||
EXPECT_EQ(expected_elements[i][j], actual_elements[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ValidateMatrixEqualityFloat(const Matrix<float>& expected,
|
||||
const Matrix<float>& actual) {
|
||||
EXPECT_EQ(expected.num_rows(), actual.num_rows());
|
||||
EXPECT_EQ(expected.num_columns(), actual.num_columns());
|
||||
|
||||
const float* const* expected_elements = expected.elements();
|
||||
const float* const* actual_elements = actual.elements();
|
||||
for (int i = 0; i < expected.num_rows(); ++i) {
|
||||
for (int j = 0; j < expected.num_columns(); ++j) {
|
||||
EXPECT_NEAR(expected_elements[i][j], actual_elements[i][j], kTolerance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ValidateMatrixEqualityComplexFloat(
|
||||
const Matrix<complex<float> >& expected,
|
||||
const Matrix<complex<float> >& actual) {
|
||||
EXPECT_EQ(expected.num_rows(), actual.num_rows());
|
||||
EXPECT_EQ(expected.num_columns(), actual.num_columns());
|
||||
|
||||
const complex<float>* const* expected_elements = expected.elements();
|
||||
const complex<float>* const* actual_elements = actual.elements();
|
||||
for (int i = 0; i < expected.num_rows(); ++i) {
|
||||
for (int j = 0; j < expected.num_columns(); ++j) {
|
||||
EXPECT_NEAR(expected_elements[i][j].real(),
|
||||
actual_elements[i][j].real(),
|
||||
kTolerance);
|
||||
EXPECT_NEAR(expected_elements[i][j].imag(),
|
||||
actual_elements[i][j].imag(),
|
||||
kTolerance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ValidateMatrixNearEqualityComplexFloat(
|
||||
const Matrix<complex<float> >& expected,
|
||||
const Matrix<complex<float> >& actual,
|
||||
float tolerance) {
|
||||
EXPECT_EQ(expected.num_rows(), actual.num_rows());
|
||||
EXPECT_EQ(expected.num_columns(), actual.num_columns());
|
||||
|
||||
const complex<float>* const* expected_elements = expected.elements();
|
||||
const complex<float>* const* actual_elements = actual.elements();
|
||||
for (int i = 0; i < expected.num_rows(); ++i) {
|
||||
for (int j = 0; j < expected.num_columns(); ++j) {
|
||||
EXPECT_NEAR(expected_elements[i][j].real(),
|
||||
actual_elements[i][j].real(),
|
||||
tolerance);
|
||||
EXPECT_NEAR(expected_elements[i][j].imag(),
|
||||
actual_elements[i][j].imag(),
|
||||
tolerance);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_MATRIX_TEST_HELPERS_H_
|
||||
@@ -0,0 +1,516 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
|
||||
#include "webrtc/modules/audio_processing/beamformer/nonlinear_beamformer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/base/arraysize.h"
|
||||
#include "webrtc/common_audio/window_generator.h"
|
||||
#include "webrtc/modules/audio_processing/beamformer/covariance_matrix_generator.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
// Alpha for the Kaiser Bessel Derived window.
|
||||
const float kKbdAlpha = 1.5f;
|
||||
|
||||
// The minimum value a post-processing mask can take.
|
||||
const float kMaskMinimum = 0.01f;
|
||||
|
||||
const float kSpeedOfSoundMeterSeconds = 343;
|
||||
|
||||
// For both target and interference angles, PI / 2 is perpendicular to the
|
||||
// microphone array, facing forwards. The positive direction goes
|
||||
// counterclockwise.
|
||||
// The angle at which we amplify sound.
|
||||
const float kTargetAngleRadians = static_cast<float>(M_PI) / 2.f;
|
||||
|
||||
// The angle at which we suppress sound. Suppression is symmetric around PI / 2
|
||||
// radians, so sound is suppressed at both +|kInterfAngleRadians| and
|
||||
// PI - |kInterfAngleRadians|. Since the beamformer is robust, this should
|
||||
// suppress sound coming from close angles as well.
|
||||
const float kInterfAngleRadians = static_cast<float>(M_PI) / 4.f;
|
||||
|
||||
// When calculating the interference covariance matrix, this is the weight for
|
||||
// the weighted average between the uniform covariance matrix and the angled
|
||||
// covariance matrix.
|
||||
// Rpsi = Rpsi_angled * kBalance + Rpsi_uniform * (1 - kBalance)
|
||||
const float kBalance = 0.4f;
|
||||
|
||||
const float kHalfBeamWidthRadians = static_cast<float>(M_PI) * 20.f / 180.f;
|
||||
|
||||
// TODO(claguna): need comment here.
|
||||
const float kBeamwidthConstant = 0.00002f;
|
||||
|
||||
// Alpha coefficients for mask smoothing.
|
||||
const float kMaskTimeSmoothAlpha = 0.2f;
|
||||
const float kMaskFrequencySmoothAlpha = 0.6f;
|
||||
|
||||
// The average mask is computed from masks in this mid-frequency range. If these
|
||||
// ranges are changed |kMaskQuantile| might need to be adjusted.
|
||||
const int kLowMeanStartHz = 200;
|
||||
const int kLowMeanEndHz = 400;
|
||||
|
||||
const int kHighMeanStartHz = 3000;
|
||||
const int kHighMeanEndHz = 5000;
|
||||
|
||||
// Quantile of mask values which is used to estimate target presence.
|
||||
const float kMaskQuantile = 0.7f;
|
||||
// Mask threshold over which the data is considered signal and not interference.
|
||||
const float kMaskTargetThreshold = 0.3f;
|
||||
// Time in seconds after which the data is considered interference if the mask
|
||||
// does not pass |kMaskTargetThreshold|.
|
||||
const float kHoldTargetSeconds = 0.25f;
|
||||
|
||||
// Does conjugate(|norm_mat|) * |mat| * transpose(|norm_mat|). No extra space is
|
||||
// used; to accomplish this, we compute both multiplications in the same loop.
|
||||
// The returned norm is clamped to be non-negative.
|
||||
float Norm(const ComplexMatrix<float>& mat,
|
||||
const ComplexMatrix<float>& norm_mat) {
|
||||
RTC_CHECK_EQ(norm_mat.num_rows(), 1);
|
||||
RTC_CHECK_EQ(norm_mat.num_columns(), mat.num_rows());
|
||||
RTC_CHECK_EQ(norm_mat.num_columns(), mat.num_columns());
|
||||
|
||||
complex<float> first_product = complex<float>(0.f, 0.f);
|
||||
complex<float> second_product = complex<float>(0.f, 0.f);
|
||||
|
||||
const complex<float>* const* mat_els = mat.elements();
|
||||
const complex<float>* const* norm_mat_els = norm_mat.elements();
|
||||
|
||||
for (int i = 0; i < norm_mat.num_columns(); ++i) {
|
||||
for (int j = 0; j < norm_mat.num_columns(); ++j) {
|
||||
first_product += conj(norm_mat_els[0][j]) * mat_els[j][i];
|
||||
}
|
||||
second_product += first_product * norm_mat_els[0][i];
|
||||
first_product = 0.f;
|
||||
}
|
||||
return std::max(second_product.real(), 0.f);
|
||||
}
|
||||
|
||||
// Does conjugate(|lhs|) * |rhs| for row vectors |lhs| and |rhs|.
|
||||
complex<float> ConjugateDotProduct(const ComplexMatrix<float>& lhs,
|
||||
const ComplexMatrix<float>& rhs) {
|
||||
RTC_CHECK_EQ(lhs.num_rows(), 1);
|
||||
RTC_CHECK_EQ(rhs.num_rows(), 1);
|
||||
RTC_CHECK_EQ(lhs.num_columns(), rhs.num_columns());
|
||||
|
||||
const complex<float>* const* lhs_elements = lhs.elements();
|
||||
const complex<float>* const* rhs_elements = rhs.elements();
|
||||
|
||||
complex<float> result = complex<float>(0.f, 0.f);
|
||||
for (int i = 0; i < lhs.num_columns(); ++i) {
|
||||
result += conj(lhs_elements[0][i]) * rhs_elements[0][i];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Works for positive numbers only.
|
||||
size_t Round(float x) {
|
||||
return static_cast<size_t>(std::floor(x + 0.5f));
|
||||
}
|
||||
|
||||
// Calculates the sum of absolute values of a complex matrix.
|
||||
float SumAbs(const ComplexMatrix<float>& mat) {
|
||||
float sum_abs = 0.f;
|
||||
const complex<float>* const* mat_els = mat.elements();
|
||||
for (int i = 0; i < mat.num_rows(); ++i) {
|
||||
for (int j = 0; j < mat.num_columns(); ++j) {
|
||||
sum_abs += std::abs(mat_els[i][j]);
|
||||
}
|
||||
}
|
||||
return sum_abs;
|
||||
}
|
||||
|
||||
// Calculates the sum of squares of a complex matrix.
|
||||
float SumSquares(const ComplexMatrix<float>& mat) {
|
||||
float sum_squares = 0.f;
|
||||
const complex<float>* const* mat_els = mat.elements();
|
||||
for (int i = 0; i < mat.num_rows(); ++i) {
|
||||
for (int j = 0; j < mat.num_columns(); ++j) {
|
||||
float abs_value = std::abs(mat_els[i][j]);
|
||||
sum_squares += abs_value * abs_value;
|
||||
}
|
||||
}
|
||||
return sum_squares;
|
||||
}
|
||||
|
||||
// Does |out| = |in|.' * conj(|in|) for row vector |in|.
|
||||
void TransposedConjugatedProduct(const ComplexMatrix<float>& in,
|
||||
ComplexMatrix<float>* out) {
|
||||
RTC_CHECK_EQ(in.num_rows(), 1);
|
||||
RTC_CHECK_EQ(out->num_rows(), in.num_columns());
|
||||
RTC_CHECK_EQ(out->num_columns(), in.num_columns());
|
||||
const complex<float>* in_elements = in.elements()[0];
|
||||
complex<float>* const* out_elements = out->elements();
|
||||
for (int i = 0; i < out->num_rows(); ++i) {
|
||||
for (int j = 0; j < out->num_columns(); ++j) {
|
||||
out_elements[i][j] = in_elements[i] * conj(in_elements[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Point> GetCenteredArray(std::vector<Point> array_geometry) {
|
||||
for (int dim = 0; dim < 3; ++dim) {
|
||||
float center = 0.f;
|
||||
for (size_t i = 0; i < array_geometry.size(); ++i) {
|
||||
center += array_geometry[i].c[dim];
|
||||
}
|
||||
center /= array_geometry.size();
|
||||
for (size_t i = 0; i < array_geometry.size(); ++i) {
|
||||
array_geometry[i].c[dim] -= center;
|
||||
}
|
||||
}
|
||||
return array_geometry;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
const size_t NonlinearBeamformer::kNumFreqBins;
|
||||
|
||||
NonlinearBeamformer::NonlinearBeamformer(
|
||||
const std::vector<Point>& array_geometry)
|
||||
: num_input_channels_(array_geometry.size()),
|
||||
array_geometry_(GetCenteredArray(array_geometry)) {
|
||||
WindowGenerator::KaiserBesselDerived(kKbdAlpha, kFftSize, window_);
|
||||
}
|
||||
|
||||
void NonlinearBeamformer::Initialize(int chunk_size_ms, int sample_rate_hz) {
|
||||
chunk_length_ =
|
||||
static_cast<size_t>(sample_rate_hz / (1000.f / chunk_size_ms));
|
||||
sample_rate_hz_ = sample_rate_hz;
|
||||
low_mean_start_bin_ = Round(kLowMeanStartHz * kFftSize / sample_rate_hz_);
|
||||
low_mean_end_bin_ = Round(kLowMeanEndHz * kFftSize / sample_rate_hz_);
|
||||
high_mean_start_bin_ = Round(kHighMeanStartHz * kFftSize / sample_rate_hz_);
|
||||
high_mean_end_bin_ = Round(kHighMeanEndHz * kFftSize / sample_rate_hz_);
|
||||
// These bin indexes determine the regions over which a mean is taken. This
|
||||
// is applied as a constant value over the adjacent end "frequency correction"
|
||||
// regions.
|
||||
//
|
||||
// low_mean_start_bin_ high_mean_start_bin_
|
||||
// v v constant
|
||||
// |----------------|--------|----------------|-------|----------------|
|
||||
// constant ^ ^
|
||||
// low_mean_end_bin_ high_mean_end_bin_
|
||||
//
|
||||
RTC_DCHECK_GT(low_mean_start_bin_, 0U);
|
||||
RTC_DCHECK_LT(low_mean_start_bin_, low_mean_end_bin_);
|
||||
RTC_DCHECK_LT(low_mean_end_bin_, high_mean_end_bin_);
|
||||
RTC_DCHECK_LT(high_mean_start_bin_, high_mean_end_bin_);
|
||||
RTC_DCHECK_LT(high_mean_end_bin_, kNumFreqBins - 1);
|
||||
|
||||
high_pass_postfilter_mask_ = 1.f;
|
||||
is_target_present_ = false;
|
||||
hold_target_blocks_ = kHoldTargetSeconds * 2 * sample_rate_hz / kFftSize;
|
||||
interference_blocks_count_ = hold_target_blocks_;
|
||||
|
||||
|
||||
lapped_transform_.reset(new LappedTransform(num_input_channels_,
|
||||
1,
|
||||
chunk_length_,
|
||||
window_,
|
||||
kFftSize,
|
||||
kFftSize / 2,
|
||||
this));
|
||||
for (size_t i = 0; i < kNumFreqBins; ++i) {
|
||||
time_smooth_mask_[i] = 1.f;
|
||||
final_mask_[i] = 1.f;
|
||||
float freq_hz = (static_cast<float>(i) / kFftSize) * sample_rate_hz_;
|
||||
wave_numbers_[i] = 2 * M_PI * freq_hz / kSpeedOfSoundMeterSeconds;
|
||||
mask_thresholds_[i] = num_input_channels_ * num_input_channels_ *
|
||||
kBeamwidthConstant * wave_numbers_[i] *
|
||||
wave_numbers_[i];
|
||||
}
|
||||
|
||||
// Initialize all nonadaptive values before looping through the frames.
|
||||
InitDelaySumMasks();
|
||||
InitTargetCovMats();
|
||||
InitInterfCovMats();
|
||||
|
||||
for (size_t i = 0; i < kNumFreqBins; ++i) {
|
||||
rxiws_[i] = Norm(target_cov_mats_[i], delay_sum_masks_[i]);
|
||||
rpsiws_[i] = Norm(interf_cov_mats_[i], delay_sum_masks_[i]);
|
||||
reflected_rpsiws_[i] =
|
||||
Norm(reflected_interf_cov_mats_[i], delay_sum_masks_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void NonlinearBeamformer::InitDelaySumMasks() {
|
||||
for (size_t f_ix = 0; f_ix < kNumFreqBins; ++f_ix) {
|
||||
delay_sum_masks_[f_ix].Resize(1, num_input_channels_);
|
||||
CovarianceMatrixGenerator::PhaseAlignmentMasks(f_ix,
|
||||
kFftSize,
|
||||
sample_rate_hz_,
|
||||
kSpeedOfSoundMeterSeconds,
|
||||
array_geometry_,
|
||||
kTargetAngleRadians,
|
||||
&delay_sum_masks_[f_ix]);
|
||||
|
||||
complex_f norm_factor = sqrt(
|
||||
ConjugateDotProduct(delay_sum_masks_[f_ix], delay_sum_masks_[f_ix]));
|
||||
delay_sum_masks_[f_ix].Scale(1.f / norm_factor);
|
||||
normalized_delay_sum_masks_[f_ix].CopyFrom(delay_sum_masks_[f_ix]);
|
||||
normalized_delay_sum_masks_[f_ix].Scale(1.f / SumAbs(
|
||||
normalized_delay_sum_masks_[f_ix]));
|
||||
}
|
||||
}
|
||||
|
||||
void NonlinearBeamformer::InitTargetCovMats() {
|
||||
for (size_t i = 0; i < kNumFreqBins; ++i) {
|
||||
target_cov_mats_[i].Resize(num_input_channels_, num_input_channels_);
|
||||
TransposedConjugatedProduct(delay_sum_masks_[i], &target_cov_mats_[i]);
|
||||
complex_f normalization_factor = target_cov_mats_[i].Trace();
|
||||
target_cov_mats_[i].Scale(1.f / normalization_factor);
|
||||
}
|
||||
}
|
||||
|
||||
void NonlinearBeamformer::InitInterfCovMats() {
|
||||
for (size_t i = 0; i < kNumFreqBins; ++i) {
|
||||
interf_cov_mats_[i].Resize(num_input_channels_, num_input_channels_);
|
||||
ComplexMatrixF uniform_cov_mat(num_input_channels_, num_input_channels_);
|
||||
ComplexMatrixF angled_cov_mat(num_input_channels_, num_input_channels_);
|
||||
|
||||
CovarianceMatrixGenerator::UniformCovarianceMatrix(wave_numbers_[i],
|
||||
array_geometry_,
|
||||
&uniform_cov_mat);
|
||||
|
||||
CovarianceMatrixGenerator::AngledCovarianceMatrix(kSpeedOfSoundMeterSeconds,
|
||||
kInterfAngleRadians,
|
||||
i,
|
||||
kFftSize,
|
||||
kNumFreqBins,
|
||||
sample_rate_hz_,
|
||||
array_geometry_,
|
||||
&angled_cov_mat);
|
||||
// Normalize matrices before averaging them.
|
||||
complex_f normalization_factor = uniform_cov_mat.Trace();
|
||||
uniform_cov_mat.Scale(1.f / normalization_factor);
|
||||
normalization_factor = angled_cov_mat.Trace();
|
||||
angled_cov_mat.Scale(1.f / normalization_factor);
|
||||
|
||||
// Average matrices.
|
||||
uniform_cov_mat.Scale(1 - kBalance);
|
||||
angled_cov_mat.Scale(kBalance);
|
||||
interf_cov_mats_[i].Add(uniform_cov_mat, angled_cov_mat);
|
||||
reflected_interf_cov_mats_[i].PointwiseConjugate(interf_cov_mats_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void NonlinearBeamformer::ProcessChunk(const ChannelBuffer<float>& input,
|
||||
ChannelBuffer<float>* output) {
|
||||
RTC_DCHECK_EQ(input.num_channels(), num_input_channels_);
|
||||
RTC_DCHECK_EQ(input.num_frames_per_band(), chunk_length_);
|
||||
|
||||
float old_high_pass_mask = high_pass_postfilter_mask_;
|
||||
lapped_transform_->ProcessChunk(input.channels(0), output->channels(0));
|
||||
// Ramp up/down for smoothing. 1 mask per 10ms results in audible
|
||||
// discontinuities.
|
||||
const float ramp_increment =
|
||||
(high_pass_postfilter_mask_ - old_high_pass_mask) /
|
||||
input.num_frames_per_band();
|
||||
// Apply delay and sum and post-filter in the time domain. WARNING: only works
|
||||
// because delay-and-sum is not frequency dependent.
|
||||
for (size_t i = 1; i < input.num_bands(); ++i) {
|
||||
float smoothed_mask = old_high_pass_mask;
|
||||
for (size_t j = 0; j < input.num_frames_per_band(); ++j) {
|
||||
smoothed_mask += ramp_increment;
|
||||
|
||||
// Applying the delay and sum (at zero degrees, this is equivalent to
|
||||
// averaging).
|
||||
float sum = 0.f;
|
||||
for (int k = 0; k < input.num_channels(); ++k) {
|
||||
sum += input.channels(i)[k][j];
|
||||
}
|
||||
output->channels(i)[0][j] = sum / input.num_channels() * smoothed_mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool NonlinearBeamformer::IsInBeam(const SphericalPointf& spherical_point) {
|
||||
// If more than half-beamwidth degrees away from the beam's center,
|
||||
// you are out of the beam.
|
||||
return fabs(spherical_point.azimuth() - kTargetAngleRadians) <
|
||||
kHalfBeamWidthRadians;
|
||||
}
|
||||
|
||||
void NonlinearBeamformer::ProcessAudioBlock(const complex_f* const* input,
|
||||
int num_input_channels,
|
||||
size_t num_freq_bins,
|
||||
int num_output_channels,
|
||||
complex_f* const* output) {
|
||||
RTC_CHECK_EQ(num_freq_bins, kNumFreqBins);
|
||||
RTC_CHECK_EQ(num_input_channels, num_input_channels_);
|
||||
RTC_CHECK_EQ(num_output_channels, 1);
|
||||
|
||||
// Calculating the post-filter masks. Note that we need two for each
|
||||
// frequency bin to account for the positive and negative interferer
|
||||
// angle.
|
||||
for (size_t i = low_mean_start_bin_; i <= high_mean_end_bin_; ++i) {
|
||||
eig_m_.CopyFromColumn(input, i, num_input_channels_);
|
||||
float eig_m_norm_factor = std::sqrt(SumSquares(eig_m_));
|
||||
if (eig_m_norm_factor != 0.f) {
|
||||
eig_m_.Scale(1.f / eig_m_norm_factor);
|
||||
}
|
||||
|
||||
float rxim = Norm(target_cov_mats_[i], eig_m_);
|
||||
float ratio_rxiw_rxim = 0.f;
|
||||
if (rxim > 0.f) {
|
||||
ratio_rxiw_rxim = rxiws_[i] / rxim;
|
||||
}
|
||||
|
||||
complex_f rmw = abs(ConjugateDotProduct(delay_sum_masks_[i], eig_m_));
|
||||
rmw *= rmw;
|
||||
float rmw_r = rmw.real();
|
||||
|
||||
new_mask_[i] = CalculatePostfilterMask(interf_cov_mats_[i],
|
||||
rpsiws_[i],
|
||||
ratio_rxiw_rxim,
|
||||
rmw_r,
|
||||
mask_thresholds_[i]);
|
||||
|
||||
new_mask_[i] *= CalculatePostfilterMask(reflected_interf_cov_mats_[i],
|
||||
reflected_rpsiws_[i],
|
||||
ratio_rxiw_rxim,
|
||||
rmw_r,
|
||||
mask_thresholds_[i]);
|
||||
}
|
||||
|
||||
ApplyMaskTimeSmoothing();
|
||||
EstimateTargetPresence();
|
||||
ApplyLowFrequencyCorrection();
|
||||
ApplyHighFrequencyCorrection();
|
||||
ApplyMaskFrequencySmoothing();
|
||||
ApplyMasks(input, output);
|
||||
}
|
||||
|
||||
float NonlinearBeamformer::CalculatePostfilterMask(
|
||||
const ComplexMatrixF& interf_cov_mat,
|
||||
float rpsiw,
|
||||
float ratio_rxiw_rxim,
|
||||
float rmw_r,
|
||||
float mask_threshold) {
|
||||
float rpsim = Norm(interf_cov_mat, eig_m_);
|
||||
|
||||
// Find lambda.
|
||||
float ratio = 0.f;
|
||||
if (rpsim > 0.f) {
|
||||
ratio = rpsiw / rpsim;
|
||||
}
|
||||
float numerator = rmw_r - ratio;
|
||||
float denominator = ratio_rxiw_rxim - ratio;
|
||||
|
||||
float mask = 1.f;
|
||||
if (denominator > mask_threshold) {
|
||||
float lambda = numerator / denominator;
|
||||
mask = std::max(lambda * ratio_rxiw_rxim / rmw_r, kMaskMinimum);
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
void NonlinearBeamformer::ApplyMasks(const complex_f* const* input,
|
||||
complex_f* const* output) {
|
||||
complex_f* output_channel = output[0];
|
||||
for (size_t f_ix = 0; f_ix < kNumFreqBins; ++f_ix) {
|
||||
output_channel[f_ix] = complex_f(0.f, 0.f);
|
||||
|
||||
const complex_f* delay_sum_mask_els =
|
||||
normalized_delay_sum_masks_[f_ix].elements()[0];
|
||||
for (int c_ix = 0; c_ix < num_input_channels_; ++c_ix) {
|
||||
output_channel[f_ix] += input[c_ix][f_ix] * delay_sum_mask_els[c_ix];
|
||||
}
|
||||
|
||||
output_channel[f_ix] *= final_mask_[f_ix];
|
||||
}
|
||||
}
|
||||
|
||||
// Smooth new_mask_ into time_smooth_mask_.
|
||||
void NonlinearBeamformer::ApplyMaskTimeSmoothing() {
|
||||
for (size_t i = low_mean_start_bin_; i <= high_mean_end_bin_; ++i) {
|
||||
time_smooth_mask_[i] = kMaskTimeSmoothAlpha * new_mask_[i] +
|
||||
(1 - kMaskTimeSmoothAlpha) * time_smooth_mask_[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Copy time_smooth_mask_ to final_mask_ and smooth over frequency.
|
||||
void NonlinearBeamformer::ApplyMaskFrequencySmoothing() {
|
||||
// Smooth over frequency in both directions. The "frequency correction"
|
||||
// regions have constant value, but we enter them to smooth over the jump
|
||||
// that exists at the boundary. However, this does mean when smoothing "away"
|
||||
// from the region that we only need to use the last element.
|
||||
//
|
||||
// Upward smoothing:
|
||||
// low_mean_start_bin_
|
||||
// v
|
||||
// |------|------------|------|
|
||||
// ^------------------>^
|
||||
//
|
||||
// Downward smoothing:
|
||||
// high_mean_end_bin_
|
||||
// v
|
||||
// |------|------------|------|
|
||||
// ^<------------------^
|
||||
std::copy(time_smooth_mask_, time_smooth_mask_ + kNumFreqBins, final_mask_);
|
||||
for (size_t i = low_mean_start_bin_; i < kNumFreqBins; ++i) {
|
||||
final_mask_[i] = kMaskFrequencySmoothAlpha * final_mask_[i] +
|
||||
(1 - kMaskFrequencySmoothAlpha) * final_mask_[i - 1];
|
||||
}
|
||||
for (size_t i = high_mean_end_bin_ + 1; i > 0; --i) {
|
||||
final_mask_[i - 1] = kMaskFrequencySmoothAlpha * final_mask_[i - 1] +
|
||||
(1 - kMaskFrequencySmoothAlpha) * final_mask_[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Apply low frequency correction to time_smooth_mask_.
|
||||
void NonlinearBeamformer::ApplyLowFrequencyCorrection() {
|
||||
const float low_frequency_mask =
|
||||
MaskRangeMean(low_mean_start_bin_, low_mean_end_bin_ + 1);
|
||||
std::fill(time_smooth_mask_, time_smooth_mask_ + low_mean_start_bin_,
|
||||
low_frequency_mask);
|
||||
}
|
||||
|
||||
// Apply high frequency correction to time_smooth_mask_. Update
|
||||
// high_pass_postfilter_mask_ to use for the high frequency time-domain bands.
|
||||
void NonlinearBeamformer::ApplyHighFrequencyCorrection() {
|
||||
high_pass_postfilter_mask_ =
|
||||
MaskRangeMean(high_mean_start_bin_, high_mean_end_bin_ + 1);
|
||||
std::fill(time_smooth_mask_ + high_mean_end_bin_ + 1,
|
||||
time_smooth_mask_ + kNumFreqBins, high_pass_postfilter_mask_);
|
||||
}
|
||||
|
||||
// Compute mean over the given range of time_smooth_mask_, [first, last).
|
||||
float NonlinearBeamformer::MaskRangeMean(size_t first, size_t last) {
|
||||
RTC_DCHECK_GT(last, first);
|
||||
const float sum = std::accumulate(time_smooth_mask_ + first,
|
||||
time_smooth_mask_ + last, 0.f);
|
||||
return sum / (last - first);
|
||||
}
|
||||
|
||||
void NonlinearBeamformer::EstimateTargetPresence() {
|
||||
const size_t quantile = static_cast<size_t>(
|
||||
(high_mean_end_bin_ - low_mean_start_bin_) * kMaskQuantile +
|
||||
low_mean_start_bin_);
|
||||
std::nth_element(new_mask_ + low_mean_start_bin_, new_mask_ + quantile,
|
||||
new_mask_ + high_mean_end_bin_ + 1);
|
||||
if (new_mask_[quantile] > kMaskTargetThreshold) {
|
||||
is_target_present_ = true;
|
||||
interference_blocks_count_ = 0;
|
||||
} else {
|
||||
is_target_present_ = interference_blocks_count_++ < hold_target_blocks_;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_NONLINEAR_BEAMFORMER_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_NONLINEAR_BEAMFORMER_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/common_audio/lapped_transform.h"
|
||||
#include "webrtc/common_audio/channel_buffer.h"
|
||||
#include "webrtc/modules/audio_processing/beamformer/beamformer.h"
|
||||
#include "webrtc/modules/audio_processing/beamformer/complex_matrix.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Enhances sound sources coming directly in front of a uniform linear array
|
||||
// and suppresses sound sources coming from all other directions. Operates on
|
||||
// multichannel signals and produces single-channel output.
|
||||
//
|
||||
// The implemented nonlinear postfilter algorithm taken from "A Robust Nonlinear
|
||||
// Beamforming Postprocessor" by Bastiaan Kleijn.
|
||||
//
|
||||
// TODO(aluebs): Target angle assumed to be 0. Parameterize target angle.
|
||||
class NonlinearBeamformer
|
||||
: public Beamformer<float>,
|
||||
public LappedTransform::Callback {
|
||||
public:
|
||||
// At the moment it only accepts uniform linear microphone arrays. Using the
|
||||
// first microphone as a reference position [0, 0, 0] is a natural choice.
|
||||
explicit NonlinearBeamformer(const std::vector<Point>& array_geometry);
|
||||
|
||||
// Sample rate corresponds to the lower band.
|
||||
// Needs to be called before the NonlinearBeamformer can be used.
|
||||
void Initialize(int chunk_size_ms, int sample_rate_hz) override;
|
||||
|
||||
// Process one time-domain chunk of audio. The audio is expected to be split
|
||||
// into frequency bands inside the ChannelBuffer. The number of frames and
|
||||
// channels must correspond to the constructor parameters. The same
|
||||
// ChannelBuffer can be passed in as |input| and |output|.
|
||||
void ProcessChunk(const ChannelBuffer<float>& input,
|
||||
ChannelBuffer<float>* output) override;
|
||||
|
||||
bool IsInBeam(const SphericalPointf& spherical_point) override;
|
||||
|
||||
// After processing each block |is_target_present_| is set to true if the
|
||||
// target signal es present and to false otherwise. This methods can be called
|
||||
// to know if the data is target signal or interference and process it
|
||||
// accordingly.
|
||||
bool is_target_present() override { return is_target_present_; }
|
||||
|
||||
protected:
|
||||
// Process one frequency-domain block of audio. This is where the fun
|
||||
// happens. Implements LappedTransform::Callback.
|
||||
void ProcessAudioBlock(const complex<float>* const* input,
|
||||
int num_input_channels,
|
||||
size_t num_freq_bins,
|
||||
int num_output_channels,
|
||||
complex<float>* const* output) override;
|
||||
|
||||
private:
|
||||
typedef Matrix<float> MatrixF;
|
||||
typedef ComplexMatrix<float> ComplexMatrixF;
|
||||
typedef complex<float> complex_f;
|
||||
|
||||
void InitDelaySumMasks();
|
||||
void InitTargetCovMats(); // TODO(aluebs): Make this depend on target angle.
|
||||
void InitInterfCovMats();
|
||||
|
||||
// An implementation of equation 18, which calculates postfilter masks that,
|
||||
// when applied, minimize the mean-square error of our estimation of the
|
||||
// desired signal. A sub-task is to calculate lambda, which is solved via
|
||||
// equation 13.
|
||||
float CalculatePostfilterMask(const ComplexMatrixF& interf_cov_mat,
|
||||
float rpsiw,
|
||||
float ratio_rxiw_rxim,
|
||||
float rmxi_r,
|
||||
float mask_threshold);
|
||||
|
||||
// Prevents the postfilter masks from degenerating too quickly (a cause of
|
||||
// musical noise).
|
||||
void ApplyMaskTimeSmoothing();
|
||||
void ApplyMaskFrequencySmoothing();
|
||||
|
||||
// The postfilter masks are unreliable at low frequencies. Calculates a better
|
||||
// mask by averaging mid-low frequency values.
|
||||
void ApplyLowFrequencyCorrection();
|
||||
|
||||
// Postfilter masks are also unreliable at high frequencies. Average mid-high
|
||||
// frequency masks to calculate a single mask per block which can be applied
|
||||
// in the time-domain. Further, we average these block-masks over a chunk,
|
||||
// resulting in one postfilter mask per audio chunk. This allows us to skip
|
||||
// both transforming and blocking the high-frequency signal.
|
||||
void ApplyHighFrequencyCorrection();
|
||||
|
||||
// Compute the means needed for the above frequency correction.
|
||||
float MaskRangeMean(size_t start_bin, size_t end_bin);
|
||||
|
||||
// Applies both sets of masks to |input| and store in |output|.
|
||||
void ApplyMasks(const complex_f* const* input, complex_f* const* output);
|
||||
|
||||
void EstimateTargetPresence();
|
||||
|
||||
static const size_t kFftSize = 256;
|
||||
static const size_t kNumFreqBins = kFftSize / 2 + 1;
|
||||
|
||||
// Deals with the fft transform and blocking.
|
||||
size_t chunk_length_;
|
||||
rtc::scoped_ptr<LappedTransform> lapped_transform_;
|
||||
float window_[kFftSize];
|
||||
|
||||
// Parameters exposed to the user.
|
||||
const int num_input_channels_;
|
||||
int sample_rate_hz_;
|
||||
|
||||
const std::vector<Point> array_geometry_;
|
||||
|
||||
// Calculated based on user-input and constants in the .cc file.
|
||||
size_t low_mean_start_bin_;
|
||||
size_t low_mean_end_bin_;
|
||||
size_t high_mean_start_bin_;
|
||||
size_t high_mean_end_bin_;
|
||||
|
||||
// Quickly varying mask updated every block.
|
||||
float new_mask_[kNumFreqBins];
|
||||
// Time smoothed mask.
|
||||
float time_smooth_mask_[kNumFreqBins];
|
||||
// Time and frequency smoothed mask.
|
||||
float final_mask_[kNumFreqBins];
|
||||
|
||||
// Array of length |kNumFreqBins|, Matrix of size |1| x |num_channels_|.
|
||||
ComplexMatrixF delay_sum_masks_[kNumFreqBins];
|
||||
ComplexMatrixF normalized_delay_sum_masks_[kNumFreqBins];
|
||||
|
||||
// Array of length |kNumFreqBins|, Matrix of size |num_input_channels_| x
|
||||
// |num_input_channels_|.
|
||||
ComplexMatrixF target_cov_mats_[kNumFreqBins];
|
||||
|
||||
// Array of length |kNumFreqBins|, Matrix of size |num_input_channels_| x
|
||||
// |num_input_channels_|.
|
||||
ComplexMatrixF interf_cov_mats_[kNumFreqBins];
|
||||
ComplexMatrixF reflected_interf_cov_mats_[kNumFreqBins];
|
||||
|
||||
// Of length |kNumFreqBins|.
|
||||
float mask_thresholds_[kNumFreqBins];
|
||||
float wave_numbers_[kNumFreqBins];
|
||||
|
||||
// Preallocated for ProcessAudioBlock()
|
||||
// Of length |kNumFreqBins|.
|
||||
float rxiws_[kNumFreqBins];
|
||||
float rpsiws_[kNumFreqBins];
|
||||
float reflected_rpsiws_[kNumFreqBins];
|
||||
|
||||
// The microphone normalization factor.
|
||||
ComplexMatrixF eig_m_;
|
||||
|
||||
// For processing the high-frequency input signal.
|
||||
float high_pass_postfilter_mask_;
|
||||
|
||||
// True when the target signal is present.
|
||||
bool is_target_present_;
|
||||
// Number of blocks after which the data is considered interference if the
|
||||
// mask does not pass |kMaskSignalThreshold|.
|
||||
size_t hold_target_blocks_;
|
||||
// Number of blocks since the last mask that passed |kMaskSignalThreshold|.
|
||||
size_t interference_blocks_count_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_BEAMFORMER_NONLINEAR_BEAMFORMER_H_
|
||||
35
webrtc/modules/audio_processing/common.h
Normal file
35
webrtc/modules/audio_processing/common.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_COMMON_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_COMMON_H_
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "webrtc/modules/audio_processing/include/audio_processing.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
static inline int ChannelsFromLayout(AudioProcessing::ChannelLayout layout) {
|
||||
switch (layout) {
|
||||
case AudioProcessing::kMono:
|
||||
case AudioProcessing::kMonoAndKeyboard:
|
||||
return 1;
|
||||
case AudioProcessing::kStereo:
|
||||
case AudioProcessing::kStereoAndKeyboard:
|
||||
return 2;
|
||||
}
|
||||
assert(false);
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_PROCESSING_COMMON_H_
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user