Update to current webrtc library
This is from the upstream library commit id 3326535126e435f1ba647885ce43a8f0f3d317eb, corresponding to Chromium 88.0.4290.1.
This commit is contained in:
247
webrtc/modules/BUILD.gn
Normal file
247
webrtc/modules/BUILD.gn
Normal file
@ -0,0 +1,247 @@
|
||||
# Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
import("../webrtc.gni")
|
||||
import("audio_coding/audio_coding.gni")
|
||||
|
||||
group("modules") {
|
||||
deps = [
|
||||
"audio_coding",
|
||||
"audio_device",
|
||||
"audio_mixer",
|
||||
"audio_processing",
|
||||
"congestion_controller",
|
||||
"pacing",
|
||||
"remote_bitrate_estimator",
|
||||
"rtp_rtcp",
|
||||
"utility",
|
||||
"video_coding",
|
||||
"video_processing",
|
||||
]
|
||||
|
||||
if (rtc_desktop_capture_supported) {
|
||||
deps += [ "desktop_capture" ]
|
||||
}
|
||||
}
|
||||
|
||||
rtc_source_set("module_api_public") {
|
||||
sources = [ "include/module_common_types_public.h" ]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||
}
|
||||
|
||||
rtc_source_set("module_api") {
|
||||
visibility = [ "*" ]
|
||||
sources = [
|
||||
"include/module.h",
|
||||
"include/module_common_types.h",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_source_set("module_fec_api") {
|
||||
visibility = [ "*" ]
|
||||
sources = [ "include/module_fec_types.h" ]
|
||||
}
|
||||
|
||||
if (rtc_include_tests) {
|
||||
modules_tests_resources = [
|
||||
"../resources/audio_coding/testfile16kHz.pcm",
|
||||
"../resources/audio_coding/testfile32kHz.pcm",
|
||||
"../resources/audio_coding/teststereo32kHz.pcm",
|
||||
"../resources/foreman_cif.yuv",
|
||||
]
|
||||
|
||||
if (is_ios) {
|
||||
bundle_data("modules_tests_bundle_data") {
|
||||
testonly = true
|
||||
sources = modules_tests_resources
|
||||
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
|
||||
}
|
||||
}
|
||||
|
||||
rtc_test("modules_tests") {
|
||||
testonly = true
|
||||
|
||||
deps = [
|
||||
"../test:test_main",
|
||||
"../test:video_test_common",
|
||||
"audio_coding:audio_coding_modules_tests",
|
||||
"rtp_rtcp:rtp_rtcp_modules_tests",
|
||||
"video_coding:video_coding_modules_tests",
|
||||
"//testing/gtest",
|
||||
]
|
||||
|
||||
if (rtc_desktop_capture_supported) {
|
||||
deps += [ "desktop_capture:desktop_capture_modules_tests" ]
|
||||
}
|
||||
|
||||
data = modules_tests_resources
|
||||
|
||||
if (is_android) {
|
||||
deps += [
|
||||
# NOTE(brandtr): Including Java classes seems only to be possible from
|
||||
# rtc_test targets. Therefore we include this target here, instead of
|
||||
# in video_coding_modules_tests, where it is actually used.
|
||||
"../sdk/android:libjingle_peerconnection_java",
|
||||
"//testing/android/native_test:native_test_native_code",
|
||||
]
|
||||
shard_timeout = 900
|
||||
}
|
||||
|
||||
if (is_ios) {
|
||||
deps += [ ":modules_tests_bundle_data" ]
|
||||
}
|
||||
}
|
||||
|
||||
modules_unittests_resources = [
|
||||
"../resources/audio_coding/neteq_opus.rtp",
|
||||
"../resources/audio_coding/neteq_opus_dtx.rtp",
|
||||
"../resources/audio_coding/neteq_universal_new.rtp",
|
||||
"../resources/audio_coding/speech_4_channels_48k_one_second.wav",
|
||||
"../resources/audio_coding/speech_mono_16kHz.pcm",
|
||||
"../resources/audio_coding/speech_mono_32_48kHz.pcm",
|
||||
"../resources/audio_coding/testfile16kHz.pcm",
|
||||
"../resources/audio_coding/testfile32kHz.pcm",
|
||||
"../resources/audio_coding/testfile_fake_stereo_32kHz.pcm",
|
||||
"../resources/audio_coding/teststereo32kHz.pcm",
|
||||
"../resources/audio_device/audio_short16.pcm",
|
||||
"../resources/audio_device/audio_short44.pcm",
|
||||
"../resources/audio_device/audio_short48.pcm",
|
||||
"../resources/audio_processing/agc/agc_audio.pcm",
|
||||
"../resources/audio_processing/agc/agc_no_circular_buffer.dat",
|
||||
"../resources/audio_processing/agc/agc_pitch_gain.dat",
|
||||
"../resources/audio_processing/agc/agc_pitch_lag.dat",
|
||||
"../resources/audio_processing/agc/agc_spectral_peak.dat",
|
||||
"../resources/audio_processing/agc/agc_vad.dat",
|
||||
"../resources/audio_processing/agc/agc_voicing_prob.dat",
|
||||
"../resources/audio_processing/agc/agc_with_circular_buffer.dat",
|
||||
"../resources/audio_processing/output_data_fixed.pb",
|
||||
"../resources/audio_processing/output_data_float.pb",
|
||||
"../resources/audio_processing/output_data_float_avx2.pb",
|
||||
"../resources/audio_processing/output_data_mac.pb",
|
||||
"../resources/audio_processing/transient/ajm-macbook-1-spke16m.pcm",
|
||||
"../resources/audio_processing/transient/audio16kHz.pcm",
|
||||
"../resources/audio_processing/transient/audio32kHz.pcm",
|
||||
"../resources/audio_processing/transient/audio48kHz.pcm",
|
||||
"../resources/audio_processing/transient/audio8kHz.pcm",
|
||||
"../resources/audio_processing/transient/detect16kHz.dat",
|
||||
"../resources/audio_processing/transient/detect32kHz.dat",
|
||||
"../resources/audio_processing/transient/detect48kHz.dat",
|
||||
"../resources/audio_processing/transient/detect8kHz.dat",
|
||||
"../resources/audio_processing/transient/double-utils.dat",
|
||||
"../resources/audio_processing/transient/float-utils.dat",
|
||||
"../resources/audio_processing/transient/suppressed16kHz.pcm",
|
||||
"../resources/audio_processing/transient/suppressed32kHz.pcm",
|
||||
"../resources/audio_processing/transient/suppressed8kHz.pcm",
|
||||
"../resources/audio_processing/transient/wpd0.dat",
|
||||
"../resources/audio_processing/transient/wpd1.dat",
|
||||
"../resources/audio_processing/transient/wpd2.dat",
|
||||
"../resources/audio_processing/transient/wpd3.dat",
|
||||
"../resources/audio_processing/transient/wpd4.dat",
|
||||
"../resources/audio_processing/transient/wpd5.dat",
|
||||
"../resources/audio_processing/transient/wpd6.dat",
|
||||
"../resources/audio_processing/transient/wpd7.dat",
|
||||
"../resources/deflicker_before_cif_short.yuv",
|
||||
"../resources/far16_stereo.pcm",
|
||||
"../resources/far32_stereo.pcm",
|
||||
"../resources/far44_stereo.pcm",
|
||||
"../resources/far48_stereo.pcm",
|
||||
"../resources/far8_stereo.pcm",
|
||||
"../resources/foremanColorEnhanced_cif_short.yuv",
|
||||
"../resources/foreman_cif.yuv",
|
||||
"../resources/foreman_cif_short.yuv",
|
||||
"../resources/near16_stereo.pcm",
|
||||
"../resources/near32_stereo.pcm",
|
||||
"../resources/near44_stereo.pcm",
|
||||
"../resources/near48_stereo.pcm",
|
||||
"../resources/near8_stereo.pcm",
|
||||
"../resources/ref03.aecdump",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke1_0_AST.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke1_0_TOF.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke1_1_AST.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke1_1_TOF.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke2_0_AST.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke2_0_TOF.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke2_1_AST.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingChoke2_1_TOF.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingDelay1_0_AST.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingDelay1_0_TOF.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingLoss1_0_AST.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_IncreasingLoss1_0_TOF.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_Multi1_1_AST.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_Multi1_1_TOF.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyChoke_0_AST.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyChoke_0_TOF.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyChoke_1_AST.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyChoke_1_TOF.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyDelay_0_AST.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyDelay_0_TOF.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyLoss_0_AST.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_SteadyLoss_0_TOF.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_UnlimitedSpeed_0_AST.bin",
|
||||
"../resources/remote_bitrate_estimator/VideoSendersTest_BweTest_UnlimitedSpeed_0_TOF.bin",
|
||||
"../resources/short_mixed_mono_48.dat",
|
||||
"../resources/short_mixed_mono_48.pcm",
|
||||
"../resources/short_mixed_mono_48_arm.dat",
|
||||
"../resources/short_mixed_stereo_48.dat",
|
||||
"../resources/short_mixed_stereo_48.pcm",
|
||||
"../resources/voice_engine/audio_tiny48.wav",
|
||||
]
|
||||
if (is_ios) {
|
||||
bundle_data("modules_unittests_bundle_data") {
|
||||
testonly = true
|
||||
sources = modules_unittests_resources
|
||||
outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
|
||||
}
|
||||
}
|
||||
|
||||
rtc_test("modules_unittests") {
|
||||
testonly = true
|
||||
defines = []
|
||||
sources = [ "module_common_types_unittest.cc" ]
|
||||
|
||||
deps = [
|
||||
":module_api",
|
||||
":module_api_public",
|
||||
"../test:test_main",
|
||||
"../test:test_support",
|
||||
"audio_coding:audio_coding_unittests",
|
||||
"audio_device:audio_device_unittests",
|
||||
"audio_mixer:audio_mixer_unittests",
|
||||
"audio_processing:audio_processing_unittests",
|
||||
"audio_processing/aec3:aec3_unittests",
|
||||
"audio_processing/ns:ns_unittests",
|
||||
"congestion_controller:congestion_controller_unittests",
|
||||
"pacing:pacing_unittests",
|
||||
"remote_bitrate_estimator:remote_bitrate_estimator_unittests",
|
||||
"rtp_rtcp:rtp_rtcp_unittests",
|
||||
"utility:utility_unittests",
|
||||
"video_coding:video_coding_unittests",
|
||||
"video_processing:video_processing_unittests",
|
||||
]
|
||||
|
||||
if (rtc_desktop_capture_supported) {
|
||||
deps += [ "desktop_capture:desktop_capture_unittests" ]
|
||||
}
|
||||
|
||||
data = modules_unittests_resources
|
||||
|
||||
if (is_android) {
|
||||
deps += [
|
||||
"../sdk/android:libjingle_peerconnection_java",
|
||||
"//testing/android/native_test:native_test_support",
|
||||
]
|
||||
shard_timeout = 900
|
||||
}
|
||||
if (is_ios) {
|
||||
info_plist = "../test/ios/Info.plist"
|
||||
deps += [ ":modules_unittests_bundle_data" ]
|
||||
configs += [ "..:common_objc" ]
|
||||
ldflags = [ "-ObjC" ]
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,106 +0,0 @@
|
||||
/*
|
||||
* 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_coding/codecs/audio_decoder.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
int AudioDecoder::Decode(const uint8_t* encoded, size_t encoded_len,
|
||||
int sample_rate_hz, size_t max_decoded_bytes,
|
||||
int16_t* decoded, SpeechType* speech_type) {
|
||||
int duration = PacketDuration(encoded, encoded_len);
|
||||
if (duration >= 0 &&
|
||||
duration * Channels() * sizeof(int16_t) > max_decoded_bytes) {
|
||||
return -1;
|
||||
}
|
||||
return DecodeInternal(encoded, encoded_len, sample_rate_hz, decoded,
|
||||
speech_type);
|
||||
}
|
||||
|
||||
int AudioDecoder::DecodeRedundant(const uint8_t* encoded, size_t encoded_len,
|
||||
int sample_rate_hz, size_t max_decoded_bytes,
|
||||
int16_t* decoded, SpeechType* speech_type) {
|
||||
int duration = PacketDurationRedundant(encoded, encoded_len);
|
||||
if (duration >= 0 &&
|
||||
duration * Channels() * sizeof(int16_t) > max_decoded_bytes) {
|
||||
return -1;
|
||||
}
|
||||
return DecodeRedundantInternal(encoded, encoded_len, sample_rate_hz, decoded,
|
||||
speech_type);
|
||||
}
|
||||
|
||||
int AudioDecoder::DecodeInternal(const uint8_t* encoded, size_t encoded_len,
|
||||
int sample_rate_hz, int16_t* decoded,
|
||||
SpeechType* speech_type) {
|
||||
return kNotImplemented;
|
||||
}
|
||||
|
||||
int AudioDecoder::DecodeRedundantInternal(const uint8_t* encoded,
|
||||
size_t encoded_len,
|
||||
int sample_rate_hz, int16_t* decoded,
|
||||
SpeechType* speech_type) {
|
||||
return DecodeInternal(encoded, encoded_len, sample_rate_hz, decoded,
|
||||
speech_type);
|
||||
}
|
||||
|
||||
bool AudioDecoder::HasDecodePlc() const { return false; }
|
||||
|
||||
size_t AudioDecoder::DecodePlc(size_t num_frames, int16_t* decoded) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AudioDecoder::IncomingPacket(const uint8_t* payload,
|
||||
size_t payload_len,
|
||||
uint16_t rtp_sequence_number,
|
||||
uint32_t rtp_timestamp,
|
||||
uint32_t arrival_timestamp) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AudioDecoder::ErrorCode() { return 0; }
|
||||
|
||||
int AudioDecoder::PacketDuration(const uint8_t* encoded,
|
||||
size_t encoded_len) const {
|
||||
return kNotImplemented;
|
||||
}
|
||||
|
||||
int AudioDecoder::PacketDurationRedundant(const uint8_t* encoded,
|
||||
size_t encoded_len) const {
|
||||
return kNotImplemented;
|
||||
}
|
||||
|
||||
bool AudioDecoder::PacketHasFec(const uint8_t* encoded,
|
||||
size_t encoded_len) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
CNG_dec_inst* AudioDecoder::CngDecoderInstance() {
|
||||
FATAL() << "Not a CNG decoder";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AudioDecoder::SpeechType AudioDecoder::ConvertSpeechType(int16_t type) {
|
||||
switch (type) {
|
||||
case 0: // TODO(hlundin): Both iSAC and Opus return 0 for speech.
|
||||
case 1:
|
||||
return kSpeech;
|
||||
case 2:
|
||||
return kComfortNoise;
|
||||
default:
|
||||
assert(false);
|
||||
return kSpeech;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
@ -8,116 +8,13 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_NETEQ_INCLUDE_AUDIO_DECODER_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_NETEQ_INCLUDE_AUDIO_DECODER_H_
|
||||
// This file is for backwards compatibility only! Use
|
||||
// webrtc/api/audio_codecs/audio_decoder.h instead!
|
||||
// TODO(kwiberg): Remove it.
|
||||
|
||||
#include <stdlib.h> // NULL
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_AUDIO_DECODER_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_AUDIO_DECODER_H_
|
||||
|
||||
#include "webrtc/base/constructormagic.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/cng/include/webrtc_cng.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
#include "api/audio_codecs/audio_decoder.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// This is the interface class for decoders in NetEQ. Each codec type will have
|
||||
// and implementation of this class.
|
||||
class AudioDecoder {
|
||||
public:
|
||||
enum SpeechType {
|
||||
kSpeech = 1,
|
||||
kComfortNoise = 2
|
||||
};
|
||||
|
||||
// Used by PacketDuration below. Save the value -1 for errors.
|
||||
enum { kNotImplemented = -2 };
|
||||
|
||||
AudioDecoder() = default;
|
||||
virtual ~AudioDecoder() = default;
|
||||
|
||||
// Decodes |encode_len| bytes from |encoded| and writes the result in
|
||||
// |decoded|. The maximum bytes allowed to be written into |decoded| is
|
||||
// |max_decoded_bytes|. Returns the total number of samples across all
|
||||
// channels. If the decoder produced comfort noise, |speech_type|
|
||||
// is set to kComfortNoise, otherwise it is kSpeech. The desired output
|
||||
// sample rate is provided in |sample_rate_hz|, which must be valid for the
|
||||
// codec at hand.
|
||||
virtual int Decode(const uint8_t* encoded,
|
||||
size_t encoded_len,
|
||||
int sample_rate_hz,
|
||||
size_t max_decoded_bytes,
|
||||
int16_t* decoded,
|
||||
SpeechType* speech_type);
|
||||
|
||||
// Same as Decode(), but interfaces to the decoders redundant decode function.
|
||||
// The default implementation simply calls the regular Decode() method.
|
||||
virtual int DecodeRedundant(const uint8_t* encoded,
|
||||
size_t encoded_len,
|
||||
int sample_rate_hz,
|
||||
size_t max_decoded_bytes,
|
||||
int16_t* decoded,
|
||||
SpeechType* speech_type);
|
||||
|
||||
// Indicates if the decoder implements the DecodePlc method.
|
||||
virtual bool HasDecodePlc() const;
|
||||
|
||||
// Calls the packet-loss concealment of the decoder to update the state after
|
||||
// one or several lost packets. The caller has to make sure that the
|
||||
// memory allocated in |decoded| should accommodate |num_frames| frames.
|
||||
virtual size_t DecodePlc(size_t num_frames, int16_t* decoded);
|
||||
|
||||
// Resets the decoder state (empty buffers etc.).
|
||||
virtual void Reset() = 0;
|
||||
|
||||
// Notifies the decoder of an incoming packet to NetEQ.
|
||||
virtual int IncomingPacket(const uint8_t* payload,
|
||||
size_t payload_len,
|
||||
uint16_t rtp_sequence_number,
|
||||
uint32_t rtp_timestamp,
|
||||
uint32_t arrival_timestamp);
|
||||
|
||||
// Returns the last error code from the decoder.
|
||||
virtual int ErrorCode();
|
||||
|
||||
// Returns the duration in samples-per-channel of the payload in |encoded|
|
||||
// which is |encoded_len| bytes long. Returns kNotImplemented if no duration
|
||||
// estimate is available, or -1 in case of an error.
|
||||
virtual int PacketDuration(const uint8_t* encoded, size_t encoded_len) const;
|
||||
|
||||
// Returns the duration in samples-per-channel of the redandant payload in
|
||||
// |encoded| which is |encoded_len| bytes long. Returns kNotImplemented if no
|
||||
// duration estimate is available, or -1 in case of an error.
|
||||
virtual int PacketDurationRedundant(const uint8_t* encoded,
|
||||
size_t encoded_len) const;
|
||||
|
||||
// Detects whether a packet has forward error correction. The packet is
|
||||
// comprised of the samples in |encoded| which is |encoded_len| bytes long.
|
||||
// Returns true if the packet has FEC and false otherwise.
|
||||
virtual bool PacketHasFec(const uint8_t* encoded, size_t encoded_len) const;
|
||||
|
||||
// If this is a CNG decoder, return the underlying CNG_dec_inst*. If this
|
||||
// isn't a CNG decoder, don't call this method.
|
||||
virtual CNG_dec_inst* CngDecoderInstance();
|
||||
|
||||
virtual size_t Channels() const = 0;
|
||||
|
||||
protected:
|
||||
static SpeechType ConvertSpeechType(int16_t type);
|
||||
|
||||
virtual int DecodeInternal(const uint8_t* encoded,
|
||||
size_t encoded_len,
|
||||
int sample_rate_hz,
|
||||
int16_t* decoded,
|
||||
SpeechType* speech_type);
|
||||
|
||||
virtual int DecodeRedundantInternal(const uint8_t* encoded,
|
||||
size_t encoded_len,
|
||||
int sample_rate_hz,
|
||||
int16_t* decoded,
|
||||
SpeechType* speech_type);
|
||||
|
||||
private:
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoder);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_NETEQ_INCLUDE_AUDIO_DECODER_H_
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_AUDIO_DECODER_H_
|
||||
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
|
||||
#include "webrtc/base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
AudioEncoder::EncodedInfo::EncodedInfo() = default;
|
||||
|
||||
AudioEncoder::EncodedInfo::~EncodedInfo() = default;
|
||||
|
||||
int AudioEncoder::RtpTimestampRateHz() const {
|
||||
return SampleRateHz();
|
||||
}
|
||||
|
||||
AudioEncoder::EncodedInfo AudioEncoder::Encode(uint32_t rtp_timestamp,
|
||||
const int16_t* audio,
|
||||
size_t num_samples_per_channel,
|
||||
size_t max_encoded_bytes,
|
||||
uint8_t* encoded) {
|
||||
RTC_CHECK_EQ(num_samples_per_channel,
|
||||
static_cast<size_t>(SampleRateHz() / 100));
|
||||
EncodedInfo info =
|
||||
EncodeInternal(rtp_timestamp, audio, max_encoded_bytes, encoded);
|
||||
RTC_CHECK_LE(info.encoded_bytes, max_encoded_bytes);
|
||||
return info;
|
||||
}
|
||||
|
||||
bool AudioEncoder::SetFec(bool enable) {
|
||||
return !enable;
|
||||
}
|
||||
|
||||
bool AudioEncoder::SetDtx(bool enable) {
|
||||
return !enable;
|
||||
}
|
||||
|
||||
bool AudioEncoder::SetApplication(Application application) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void AudioEncoder::SetMaxPlaybackRate(int frequency_hz) {}
|
||||
|
||||
void AudioEncoder::SetProjectedPacketLossRate(double fraction) {}
|
||||
|
||||
void AudioEncoder::SetTargetBitrate(int target_bps) {}
|
||||
|
||||
} // namespace webrtc
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014 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,136 +8,13 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_
|
||||
// This file is for backwards compatibility only! Use
|
||||
// webrtc/api/audio_codecs/audio_encoder.h instead!
|
||||
// TODO(ossu): Remove it.
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
#include "api/audio_codecs/audio_encoder.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// This is the interface class for encoders in AudioCoding module. Each codec
|
||||
// type must have an implementation of this class.
|
||||
class AudioEncoder {
|
||||
public:
|
||||
struct EncodedInfoLeaf {
|
||||
size_t encoded_bytes = 0;
|
||||
uint32_t encoded_timestamp = 0;
|
||||
int payload_type = 0;
|
||||
bool send_even_if_empty = false;
|
||||
bool speech = true;
|
||||
};
|
||||
|
||||
// This is the main struct for auxiliary encoding information. Each encoded
|
||||
// packet should be accompanied by one EncodedInfo struct, containing the
|
||||
// total number of |encoded_bytes|, the |encoded_timestamp| and the
|
||||
// |payload_type|. If the packet contains redundant encodings, the |redundant|
|
||||
// vector will be populated with EncodedInfoLeaf structs. Each struct in the
|
||||
// vector represents one encoding; the order of structs in the vector is the
|
||||
// same as the order in which the actual payloads are written to the byte
|
||||
// stream. When EncoderInfoLeaf structs are present in the vector, the main
|
||||
// struct's |encoded_bytes| will be the sum of all the |encoded_bytes| in the
|
||||
// vector.
|
||||
struct EncodedInfo : public EncodedInfoLeaf {
|
||||
EncodedInfo();
|
||||
~EncodedInfo();
|
||||
|
||||
std::vector<EncodedInfoLeaf> redundant;
|
||||
};
|
||||
|
||||
virtual ~AudioEncoder() = default;
|
||||
|
||||
// Returns the maximum number of bytes that can be produced by the encoder
|
||||
// at each Encode() call. The caller can use the return value to determine
|
||||
// the size of the buffer that needs to be allocated. This value is allowed
|
||||
// to depend on encoder parameters like bitrate, frame size etc., so if
|
||||
// any of these change, the caller of Encode() is responsible for checking
|
||||
// that the buffer is large enough by calling MaxEncodedBytes() again.
|
||||
virtual size_t MaxEncodedBytes() const = 0;
|
||||
|
||||
// Returns the input sample rate in Hz and the number of input channels.
|
||||
// These are constants set at instantiation time.
|
||||
virtual int SampleRateHz() const = 0;
|
||||
virtual int NumChannels() const = 0;
|
||||
|
||||
// Returns the rate at which the RTP timestamps are updated. The default
|
||||
// implementation returns SampleRateHz().
|
||||
virtual int RtpTimestampRateHz() const;
|
||||
|
||||
// Returns the number of 10 ms frames the encoder will put in the next
|
||||
// packet. This value may only change when Encode() outputs a packet; i.e.,
|
||||
// the encoder may vary the number of 10 ms frames from packet to packet, but
|
||||
// it must decide the length of the next packet no later than when outputting
|
||||
// the preceding packet.
|
||||
virtual size_t Num10MsFramesInNextPacket() const = 0;
|
||||
|
||||
// Returns the maximum value that can be returned by
|
||||
// Num10MsFramesInNextPacket().
|
||||
virtual size_t Max10MsFramesInAPacket() const = 0;
|
||||
|
||||
// Returns the current target bitrate in bits/s. The value -1 means that the
|
||||
// codec adapts the target automatically, and a current target cannot be
|
||||
// provided.
|
||||
virtual int GetTargetBitrate() const = 0;
|
||||
|
||||
// Accepts one 10 ms block of input audio (i.e., SampleRateHz() / 100 *
|
||||
// NumChannels() samples). Multi-channel audio must be sample-interleaved.
|
||||
// The encoder produces zero or more bytes of output in |encoded| and
|
||||
// returns additional encoding information.
|
||||
// The caller is responsible for making sure that |max_encoded_bytes| is
|
||||
// not smaller than the number of bytes actually produced by the encoder.
|
||||
// Encode() checks some preconditions, calls EncodeInternal() which does the
|
||||
// actual work, and then checks some postconditions.
|
||||
EncodedInfo Encode(uint32_t rtp_timestamp,
|
||||
const int16_t* audio,
|
||||
size_t num_samples_per_channel,
|
||||
size_t max_encoded_bytes,
|
||||
uint8_t* encoded);
|
||||
|
||||
virtual EncodedInfo EncodeInternal(uint32_t rtp_timestamp,
|
||||
const int16_t* audio,
|
||||
size_t max_encoded_bytes,
|
||||
uint8_t* encoded) = 0;
|
||||
|
||||
// Resets the encoder to its starting state, discarding any input that has
|
||||
// been fed to the encoder but not yet emitted in a packet.
|
||||
virtual void Reset() = 0;
|
||||
|
||||
// Enables or disables codec-internal FEC (forward error correction). Returns
|
||||
// true if the codec was able to comply. The default implementation returns
|
||||
// true when asked to disable FEC and false when asked to enable it (meaning
|
||||
// that FEC isn't supported).
|
||||
virtual bool SetFec(bool enable);
|
||||
|
||||
// Enables or disables codec-internal VAD/DTX. Returns true if the codec was
|
||||
// able to comply. The default implementation returns true when asked to
|
||||
// disable DTX and false when asked to enable it (meaning that DTX isn't
|
||||
// supported).
|
||||
virtual bool SetDtx(bool enable);
|
||||
|
||||
// Sets the application mode. Returns true if the codec was able to comply.
|
||||
// The default implementation just returns false.
|
||||
enum class Application { kSpeech, kAudio };
|
||||
virtual bool SetApplication(Application application);
|
||||
|
||||
// Tells the encoder about the highest sample rate the decoder is expected to
|
||||
// use when decoding the bitstream. The encoder would typically use this
|
||||
// information to adjust the quality of the encoding. The default
|
||||
// implementation just returns true.
|
||||
virtual void SetMaxPlaybackRate(int frequency_hz);
|
||||
|
||||
// Tells the encoder what the projected packet loss rate is. The rate is in
|
||||
// the range [0.0, 1.0]. The encoder would typically use this information to
|
||||
// adjust channel coding efforts, such as FEC. The default implementation
|
||||
// does nothing.
|
||||
virtual void SetProjectedPacketLossRate(double fraction);
|
||||
|
||||
// Tells the encoder what average bitrate we'd like it to produce. The
|
||||
// encoder is free to adjust or disregard the given bitrate (the default
|
||||
// implementation does the latter).
|
||||
virtual void SetTargetBitrate(int target_bps);
|
||||
};
|
||||
} // namespace webrtc
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_AUDIO_ENCODER_H_
|
||||
|
@ -8,32 +8,33 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/modules/audio_coding/codecs/audio_decoder.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/audio_codecs/audio_decoder.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
template <typename T>
|
||||
class AudioDecoderIsacT final : public AudioDecoder {
|
||||
public:
|
||||
AudioDecoderIsacT();
|
||||
explicit AudioDecoderIsacT(LockedIsacBandwidthInfo* bwinfo);
|
||||
~AudioDecoderIsacT() override;
|
||||
struct Config {
|
||||
bool IsOk() const;
|
||||
int sample_rate_hz = 16000;
|
||||
};
|
||||
explicit AudioDecoderIsacT(const Config& config);
|
||||
virtual ~AudioDecoderIsacT() override;
|
||||
|
||||
bool HasDecodePlc() const override;
|
||||
size_t DecodePlc(size_t num_frames, int16_t* decoded) override;
|
||||
void Reset() override;
|
||||
int IncomingPacket(const uint8_t* payload,
|
||||
size_t payload_len,
|
||||
uint16_t rtp_sequence_number,
|
||||
uint32_t rtp_timestamp,
|
||||
uint32_t arrival_timestamp) override;
|
||||
int ErrorCode() override;
|
||||
int SampleRateHz() const override;
|
||||
size_t Channels() const override;
|
||||
int DecodeInternal(const uint8_t* encoded,
|
||||
size_t encoded_len,
|
||||
@ -43,12 +44,11 @@ class AudioDecoderIsacT final : public AudioDecoder {
|
||||
|
||||
private:
|
||||
typename T::instance_type* isac_state_;
|
||||
LockedIsacBandwidthInfo* bwinfo_;
|
||||
int decoder_sample_rate_hz_;
|
||||
int sample_rate_hz_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(AudioDecoderIsacT);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_H_
|
||||
|
@ -8,29 +8,26 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_
|
||||
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h"
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
template <typename T>
|
||||
AudioDecoderIsacT<T>::AudioDecoderIsacT()
|
||||
: AudioDecoderIsacT(nullptr) {}
|
||||
bool AudioDecoderIsacT<T>::Config::IsOk() const {
|
||||
return (sample_rate_hz == 16000 || sample_rate_hz == 32000);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
AudioDecoderIsacT<T>::AudioDecoderIsacT(LockedIsacBandwidthInfo* bwinfo)
|
||||
: bwinfo_(bwinfo), decoder_sample_rate_hz_(-1) {
|
||||
AudioDecoderIsacT<T>::AudioDecoderIsacT(const Config& config)
|
||||
: sample_rate_hz_(config.sample_rate_hz) {
|
||||
RTC_CHECK(config.IsOk()) << "Unsupported sample rate "
|
||||
<< config.sample_rate_hz;
|
||||
RTC_CHECK_EQ(0, T::Create(&isac_state_));
|
||||
T::DecoderInit(isac_state_);
|
||||
if (bwinfo_) {
|
||||
IsacBandwidthInfo bi;
|
||||
T::GetBandwidthInfo(isac_state_, &bi);
|
||||
bwinfo_->Set(bi);
|
||||
}
|
||||
RTC_CHECK_EQ(0, T::SetDecSampRate(isac_state_, sample_rate_hz_));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -44,12 +41,7 @@ int AudioDecoderIsacT<T>::DecodeInternal(const uint8_t* encoded,
|
||||
int sample_rate_hz,
|
||||
int16_t* decoded,
|
||||
SpeechType* speech_type) {
|
||||
RTC_CHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000)
|
||||
<< "Unsupported sample rate " << sample_rate_hz;
|
||||
if (sample_rate_hz != decoder_sample_rate_hz_) {
|
||||
RTC_CHECK_EQ(0, T::SetDecSampRate(isac_state_, sample_rate_hz));
|
||||
decoder_sample_rate_hz_ = sample_rate_hz;
|
||||
}
|
||||
RTC_CHECK_EQ(sample_rate_hz_, sample_rate_hz);
|
||||
int16_t temp_type = 1; // Default is speech.
|
||||
int ret =
|
||||
T::DecodeInternal(isac_state_, encoded, encoded_len, decoded, &temp_type);
|
||||
@ -73,25 +65,13 @@ void AudioDecoderIsacT<T>::Reset() {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int AudioDecoderIsacT<T>::IncomingPacket(const uint8_t* payload,
|
||||
size_t payload_len,
|
||||
uint16_t rtp_sequence_number,
|
||||
uint32_t rtp_timestamp,
|
||||
uint32_t arrival_timestamp) {
|
||||
int ret = T::UpdateBwEstimate(isac_state_, payload, payload_len,
|
||||
rtp_sequence_number, rtp_timestamp,
|
||||
arrival_timestamp);
|
||||
if (bwinfo_) {
|
||||
IsacBandwidthInfo bwinfo;
|
||||
T::GetBandwidthInfo(isac_state_, &bwinfo);
|
||||
bwinfo_->Set(bwinfo);
|
||||
}
|
||||
return ret;
|
||||
int AudioDecoderIsacT<T>::ErrorCode() {
|
||||
return T::GetErrorCode(isac_state_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int AudioDecoderIsacT<T>::ErrorCode() {
|
||||
return T::GetErrorCode(isac_state_);
|
||||
int AudioDecoderIsacT<T>::SampleRateHz() const {
|
||||
return sample_rate_hz_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -101,4 +81,4 @@ size_t AudioDecoderIsacT<T>::Channels() const {
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_DECODER_ISAC_T_IMPL_H_
|
||||
|
@ -8,18 +8,21 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/locked_bandwidth_info.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/audio_codecs/audio_encoder.h"
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
struct CodecInst;
|
||||
|
||||
template <typename T>
|
||||
class AudioEncoderIsacT final : public AudioEncoder {
|
||||
public:
|
||||
@ -29,9 +32,6 @@ class AudioEncoderIsacT final : public AudioEncoder {
|
||||
// - 32000 Hz, 30 ms, 10000-56000 bps (if T has super-wideband support)
|
||||
struct Config {
|
||||
bool IsOk() const;
|
||||
|
||||
LockedIsacBandwidthInfo* bwinfo = nullptr;
|
||||
|
||||
int payload_type = 103;
|
||||
int sample_rate_hz = 16000;
|
||||
int frame_size_ms = 30;
|
||||
@ -39,46 +39,48 @@ class AudioEncoderIsacT final : public AudioEncoder {
|
||||
// rate, in bits/s.
|
||||
int max_payload_size_bytes = -1;
|
||||
int max_bit_rate = -1;
|
||||
|
||||
// If true, the encoder will dynamically adjust frame size and bit rate;
|
||||
// the configured values are then merely the starting point.
|
||||
bool adaptive_mode = false;
|
||||
|
||||
// In adaptive mode, prevent adaptive changes to the frame size. (Not used
|
||||
// in nonadaptive mode.)
|
||||
bool enforce_frame_size = false;
|
||||
};
|
||||
|
||||
explicit AudioEncoderIsacT(const Config& config);
|
||||
explicit AudioEncoderIsacT(const CodecInst& codec_inst,
|
||||
LockedIsacBandwidthInfo* bwinfo);
|
||||
~AudioEncoderIsacT() override;
|
||||
|
||||
size_t MaxEncodedBytes() const override;
|
||||
int SampleRateHz() const override;
|
||||
int NumChannels() const override;
|
||||
size_t NumChannels() const override;
|
||||
size_t Num10MsFramesInNextPacket() const override;
|
||||
size_t Max10MsFramesInAPacket() const override;
|
||||
int GetTargetBitrate() const override;
|
||||
EncodedInfo EncodeInternal(uint32_t rtp_timestamp,
|
||||
const int16_t* audio,
|
||||
size_t max_encoded_bytes,
|
||||
uint8_t* encoded) override;
|
||||
void SetTargetBitrate(int target_bps) override;
|
||||
void OnReceivedTargetAudioBitrate(int target_bps) override;
|
||||
void OnReceivedUplinkBandwidth(
|
||||
int target_audio_bitrate_bps,
|
||||
absl::optional<int64_t> bwe_period_ms) override;
|
||||
void OnReceivedUplinkAllocation(BitrateAllocationUpdate update) override;
|
||||
void OnReceivedOverhead(size_t overhead_bytes_per_packet) override;
|
||||
EncodedInfo EncodeImpl(uint32_t rtp_timestamp,
|
||||
rtc::ArrayView<const int16_t> audio,
|
||||
rtc::Buffer* encoded) override;
|
||||
void Reset() override;
|
||||
absl::optional<std::pair<TimeDelta, TimeDelta>> GetFrameLengthRange()
|
||||
const override;
|
||||
|
||||
private:
|
||||
// This value is taken from STREAM_SIZE_MAX_60 for iSAC float (60 ms) and
|
||||
// STREAM_MAXW16_60MS for iSAC fix (60 ms).
|
||||
static const size_t kSufficientEncodeBufferSizeBytes = 400;
|
||||
|
||||
static const int kDefaultBitRate = 32000;
|
||||
static constexpr int kDefaultBitRate = 32000;
|
||||
static constexpr int kMinBitrateBps = 10000;
|
||||
static constexpr int MaxBitrateBps(int sample_rate_hz) {
|
||||
return sample_rate_hz == 32000 ? 56000 : 32000;
|
||||
}
|
||||
|
||||
void SetTargetBitrate(int target_bps, bool subtract_per_packet_overhead);
|
||||
|
||||
// Recreate the iSAC encoder instance with the given settings, and save them.
|
||||
void RecreateEncoderInstance(const Config& config);
|
||||
|
||||
Config config_;
|
||||
typename T::instance_type* isac_state_ = nullptr;
|
||||
LockedIsacBandwidthInfo* bwinfo_ = nullptr;
|
||||
|
||||
// Have we accepted input but not yet emitted it in a packet?
|
||||
bool packet_in_progress_ = false;
|
||||
@ -89,9 +91,18 @@ class AudioEncoderIsacT final : public AudioEncoder {
|
||||
// Timestamp of the previously encoded packet.
|
||||
uint32_t last_encoded_timestamp_;
|
||||
|
||||
// Cache the value of the "WebRTC-SendSideBwe-WithOverhead" field trial.
|
||||
const bool send_side_bwe_with_overhead_ =
|
||||
field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead");
|
||||
|
||||
// When we send a packet, expect this many bytes of headers to be added to it.
|
||||
// Start out with a reasonable default that we can use until we receive a real
|
||||
// value.
|
||||
DataSize overhead_per_packet_ = DataSize::Bytes(28);
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(AudioEncoderIsacT);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_H_
|
||||
|
@ -8,39 +8,21 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
|
||||
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h"
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/numerics/safe_minmax.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
template <typename T>
|
||||
typename AudioEncoderIsacT<T>::Config CreateIsacConfig(
|
||||
const CodecInst& codec_inst,
|
||||
LockedIsacBandwidthInfo* bwinfo) {
|
||||
typename AudioEncoderIsacT<T>::Config config;
|
||||
config.bwinfo = bwinfo;
|
||||
config.payload_type = codec_inst.pltype;
|
||||
config.sample_rate_hz = codec_inst.plfreq;
|
||||
config.frame_size_ms =
|
||||
rtc::CheckedDivExact(1000 * codec_inst.pacsize, config.sample_rate_hz);
|
||||
config.adaptive_mode = (codec_inst.rate == -1);
|
||||
if (codec_inst.rate != -1)
|
||||
config.bit_rate = codec_inst.rate;
|
||||
return config;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool AudioEncoderIsacT<T>::Config::IsOk() const {
|
||||
if (max_bit_rate < 32000 && max_bit_rate != -1)
|
||||
return false;
|
||||
if (max_payload_size_bytes < 120 && max_payload_size_bytes != -1)
|
||||
return false;
|
||||
if (adaptive_mode && !bwinfo)
|
||||
return false;
|
||||
|
||||
switch (sample_rate_hz) {
|
||||
case 16000:
|
||||
if (max_bit_rate > 53400)
|
||||
@ -67,37 +49,26 @@ AudioEncoderIsacT<T>::AudioEncoderIsacT(const Config& config) {
|
||||
RecreateEncoderInstance(config);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
AudioEncoderIsacT<T>::AudioEncoderIsacT(const CodecInst& codec_inst,
|
||||
LockedIsacBandwidthInfo* bwinfo)
|
||||
: AudioEncoderIsacT(CreateIsacConfig<T>(codec_inst, bwinfo)) {}
|
||||
|
||||
template <typename T>
|
||||
AudioEncoderIsacT<T>::~AudioEncoderIsacT() {
|
||||
RTC_CHECK_EQ(0, T::Free(isac_state_));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t AudioEncoderIsacT<T>::MaxEncodedBytes() const {
|
||||
return kSufficientEncodeBufferSizeBytes;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int AudioEncoderIsacT<T>::SampleRateHz() const {
|
||||
return T::EncSampRate(isac_state_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
int AudioEncoderIsacT<T>::NumChannels() const {
|
||||
size_t AudioEncoderIsacT<T>::NumChannels() const {
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t AudioEncoderIsacT<T>::Num10MsFramesInNextPacket() const {
|
||||
const int samples_in_next_packet = T::GetNewFrameLen(isac_state_);
|
||||
return static_cast<size_t>(
|
||||
rtc::CheckedDivExact(samples_in_next_packet,
|
||||
rtc::CheckedDivExact(SampleRateHz(), 100)));
|
||||
return static_cast<size_t>(rtc::CheckedDivExact(
|
||||
samples_in_next_packet, rtc::CheckedDivExact(SampleRateHz(), 100)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -107,44 +78,85 @@ size_t AudioEncoderIsacT<T>::Max10MsFramesInAPacket() const {
|
||||
|
||||
template <typename T>
|
||||
int AudioEncoderIsacT<T>::GetTargetBitrate() const {
|
||||
if (config_.adaptive_mode)
|
||||
return -1;
|
||||
return config_.bit_rate == 0 ? kDefaultBitRate : config_.bit_rate;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
AudioEncoder::EncodedInfo AudioEncoderIsacT<T>::EncodeInternal(
|
||||
void AudioEncoderIsacT<T>::SetTargetBitrate(int target_bps) {
|
||||
// Set target bitrate directly without subtracting per-packet overhead,
|
||||
// because that's what AudioEncoderOpus does.
|
||||
SetTargetBitrate(target_bps,
|
||||
/*subtract_per_packet_overhead=*/false);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void AudioEncoderIsacT<T>::OnReceivedTargetAudioBitrate(int target_bps) {
|
||||
// Set target bitrate directly without subtracting per-packet overhead,
|
||||
// because that's what AudioEncoderOpus does.
|
||||
SetTargetBitrate(target_bps,
|
||||
/*subtract_per_packet_overhead=*/false);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void AudioEncoderIsacT<T>::OnReceivedUplinkBandwidth(
|
||||
int target_audio_bitrate_bps,
|
||||
absl::optional<int64_t> /*bwe_period_ms*/) {
|
||||
// Set target bitrate, subtracting the per-packet overhead if
|
||||
// WebRTC-SendSideBwe-WithOverhead is enabled, because that's what
|
||||
// AudioEncoderOpus does.
|
||||
SetTargetBitrate(
|
||||
target_audio_bitrate_bps,
|
||||
/*subtract_per_packet_overhead=*/send_side_bwe_with_overhead_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void AudioEncoderIsacT<T>::OnReceivedUplinkAllocation(
|
||||
BitrateAllocationUpdate update) {
|
||||
// Set target bitrate, subtracting the per-packet overhead if
|
||||
// WebRTC-SendSideBwe-WithOverhead is enabled, because that's what
|
||||
// AudioEncoderOpus does.
|
||||
SetTargetBitrate(
|
||||
update.target_bitrate.bps<int>(),
|
||||
/*subtract_per_packet_overhead=*/send_side_bwe_with_overhead_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void AudioEncoderIsacT<T>::OnReceivedOverhead(
|
||||
size_t overhead_bytes_per_packet) {
|
||||
overhead_per_packet_ = DataSize::Bytes(overhead_bytes_per_packet);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
AudioEncoder::EncodedInfo AudioEncoderIsacT<T>::EncodeImpl(
|
||||
uint32_t rtp_timestamp,
|
||||
const int16_t* audio,
|
||||
size_t max_encoded_bytes,
|
||||
uint8_t* encoded) {
|
||||
rtc::ArrayView<const int16_t> audio,
|
||||
rtc::Buffer* encoded) {
|
||||
if (!packet_in_progress_) {
|
||||
// Starting a new packet; remember the timestamp for later.
|
||||
packet_in_progress_ = true;
|
||||
packet_timestamp_ = rtp_timestamp;
|
||||
}
|
||||
if (bwinfo_) {
|
||||
IsacBandwidthInfo bwinfo = bwinfo_->Get();
|
||||
T::SetBandwidthInfo(isac_state_, &bwinfo);
|
||||
}
|
||||
int r = T::Encode(isac_state_, audio, encoded);
|
||||
RTC_CHECK_GE(r, 0) << "Encode failed (error code "
|
||||
<< T::GetErrorCode(isac_state_) << ")";
|
||||
size_t encoded_bytes = encoded->AppendData(
|
||||
kSufficientEncodeBufferSizeBytes, [&](rtc::ArrayView<uint8_t> encoded) {
|
||||
int r = T::Encode(isac_state_, audio.data(), encoded.data());
|
||||
|
||||
// T::Encode doesn't allow us to tell it the size of the output
|
||||
// buffer. All we can do is check for an overrun after the fact.
|
||||
RTC_CHECK_LE(static_cast<size_t>(r), max_encoded_bytes);
|
||||
RTC_CHECK_GE(r, 0) << "Encode failed (error code "
|
||||
<< T::GetErrorCode(isac_state_) << ")";
|
||||
|
||||
if (r == 0)
|
||||
return static_cast<size_t>(r);
|
||||
});
|
||||
|
||||
if (encoded_bytes == 0)
|
||||
return EncodedInfo();
|
||||
|
||||
// Got enough input to produce a packet. Return the saved timestamp from
|
||||
// the first chunk of input that went into the packet.
|
||||
packet_in_progress_ = false;
|
||||
EncodedInfo info;
|
||||
info.encoded_bytes = r;
|
||||
info.encoded_bytes = encoded_bytes;
|
||||
info.encoded_timestamp = packet_timestamp_;
|
||||
info.payload_type = config_.payload_type;
|
||||
info.encoder_type = CodecType::kIsac;
|
||||
return info;
|
||||
}
|
||||
|
||||
@ -153,23 +165,40 @@ void AudioEncoderIsacT<T>::Reset() {
|
||||
RecreateEncoderInstance(config_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
absl::optional<std::pair<TimeDelta, TimeDelta>>
|
||||
AudioEncoderIsacT<T>::GetFrameLengthRange() const {
|
||||
return {{TimeDelta::Millis(config_.frame_size_ms),
|
||||
TimeDelta::Millis(config_.frame_size_ms)}};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void AudioEncoderIsacT<T>::SetTargetBitrate(int target_bps,
|
||||
bool subtract_per_packet_overhead) {
|
||||
if (subtract_per_packet_overhead) {
|
||||
const DataRate overhead_rate =
|
||||
overhead_per_packet_ / TimeDelta::Millis(config_.frame_size_ms);
|
||||
target_bps -= overhead_rate.bps();
|
||||
}
|
||||
target_bps = rtc::SafeClamp(target_bps, kMinBitrateBps,
|
||||
MaxBitrateBps(config_.sample_rate_hz));
|
||||
int result = T::Control(isac_state_, target_bps, config_.frame_size_ms);
|
||||
RTC_DCHECK_EQ(result, 0);
|
||||
config_.bit_rate = target_bps;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void AudioEncoderIsacT<T>::RecreateEncoderInstance(const Config& config) {
|
||||
RTC_CHECK(config.IsOk());
|
||||
packet_in_progress_ = false;
|
||||
bwinfo_ = config.bwinfo;
|
||||
if (isac_state_)
|
||||
RTC_CHECK_EQ(0, T::Free(isac_state_));
|
||||
RTC_CHECK_EQ(0, T::Create(&isac_state_));
|
||||
RTC_CHECK_EQ(0, T::EncoderInit(isac_state_, config.adaptive_mode ? 0 : 1));
|
||||
RTC_CHECK_EQ(0, T::EncoderInit(isac_state_, /*coding_mode=*/1));
|
||||
RTC_CHECK_EQ(0, T::SetEncSampRate(isac_state_, config.sample_rate_hz));
|
||||
const int bit_rate = config.bit_rate == 0 ? kDefaultBitRate : config.bit_rate;
|
||||
if (config.adaptive_mode) {
|
||||
RTC_CHECK_EQ(0, T::ControlBwe(isac_state_, bit_rate, config.frame_size_ms,
|
||||
config.enforce_frame_size));
|
||||
} else {
|
||||
RTC_CHECK_EQ(0, T::Control(isac_state_, bit_rate, config.frame_size_ms));
|
||||
}
|
||||
RTC_CHECK_EQ(0, T::Control(isac_state_, bit_rate, config.frame_size_ms));
|
||||
|
||||
if (config.max_payload_size_bytes != -1)
|
||||
RTC_CHECK_EQ(
|
||||
0, T::SetMaxPayloadSize(isac_state_, config.max_payload_size_bytes));
|
||||
@ -187,4 +216,4 @@ void AudioEncoderIsacT<T>::RecreateEncoderInstance(const Config& config) {
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_ISAC_AUDIO_ENCODER_ISAC_T_IMPL_H_
|
||||
|
@ -8,10 +8,10 @@
|
||||
* 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_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_BANDWIDTH_INFO_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_BANDWIDTH_INFO_H_
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
int in_use;
|
||||
@ -21,4 +21,4 @@ typedef struct {
|
||||
int16_t jitter_info;
|
||||
} IsacBandwidthInfo;
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_BANDWIDTH_INFO_H_
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_ISAC_BANDWIDTH_INFO_H_
|
||||
|
@ -8,15 +8,15 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_DECODER_ISAC_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_DECODER_ISAC_H_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_DECODER_ISAC_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_DECODER_ISAC_H_
|
||||
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/source/isac_float_type.h"
|
||||
#include "modules/audio_coding/codecs/isac/audio_decoder_isac_t.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/isac_float_type.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
using AudioDecoderIsac = AudioDecoderIsacT<IsacFloat>;
|
||||
using AudioDecoderIsacFloatImpl = AudioDecoderIsacT<IsacFloat>;
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
|
||||
|
@ -8,15 +8,15 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
|
||||
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/source/isac_float_type.h"
|
||||
#include "modules/audio_coding/codecs/isac/audio_encoder_isac_t.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/isac_float_type.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
using AudioEncoderIsac = AudioEncoderIsacT<IsacFloat>;
|
||||
using AudioEncoderIsacFloatImpl = AudioEncoderIsacT<IsacFloat>;
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INCLUDE_AUDIO_ENCODER_ISAC_H_
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,8 +8,8 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "arith_routines.h"
|
||||
#include "settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/arith_routines.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
|
||||
|
||||
/*
|
||||
|
@ -15,49 +15,53 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#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"
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/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 */
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
Bitstr* streamdata, /* in-/output struct containing bitstream */
|
||||
const int* data, /* input: data vector */
|
||||
const uint16_t* const* 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* data, /* output: data vector */
|
||||
Bitstr* streamdata, /* in-/output struct containing bitstream */
|
||||
const uint16_t* const* 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 */
|
||||
int* data, /* output: data vector */
|
||||
Bitstr* streamdata, /* in-/output struct containing bitstream */
|
||||
const uint16_t* const* 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_ */
|
||||
#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_ */
|
||||
|
@ -8,8 +8,8 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
#include "arith_routines.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/arith_routines.h"
|
||||
|
||||
|
||||
/*
|
||||
@ -17,7 +17,7 @@
|
||||
*/
|
||||
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 uint16_t *const *cdf, /* input: array of cdf arrays */
|
||||
const int N) /* input: data vector length */
|
||||
{
|
||||
uint32_t W_lower, W_upper;
|
||||
@ -84,7 +84,7 @@ void WebRtcIsac_EncHistMulti(Bitstr *streamdata, /* in-/output struct containing
|
||||
*/
|
||||
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 *const *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 */
|
||||
{
|
||||
@ -192,7 +192,7 @@ int WebRtcIsac_DecHistBisectMulti(int *data, /* output: data vector */
|
||||
*/
|
||||
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 *const *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 */
|
||||
{
|
||||
@ -214,10 +214,10 @@ int WebRtcIsac_DecHistOneStepMulti(int *data, /* output: data vector */
|
||||
if (streamdata->stream_index == 0) /* first time decoder is called for this stream */
|
||||
{
|
||||
/* read first word from bytestream */
|
||||
streamval = *stream_ptr << 24;
|
||||
streamval |= *++stream_ptr << 16;
|
||||
streamval |= *++stream_ptr << 8;
|
||||
streamval |= *++stream_ptr;
|
||||
streamval = (uint32_t)(*stream_ptr) << 24;
|
||||
streamval |= (uint32_t)(*++stream_ptr) << 16;
|
||||
streamval |= (uint32_t)(*++stream_ptr) << 8;
|
||||
streamval |= (uint32_t)(*++stream_ptr);
|
||||
} else {
|
||||
streamval = streamdata->streamval;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "arith_routines.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/arith_routines.h"
|
||||
|
||||
|
||||
|
||||
@ -185,11 +185,18 @@ int WebRtcIsac_DecLogisticMulti2(
|
||||
int16_t candQ7;
|
||||
int k;
|
||||
|
||||
// Position just past the end of the stream. STREAM_SIZE_MAX_60 instead of
|
||||
// STREAM_SIZE_MAX (which is the size of the allocated buffer) because that's
|
||||
// the limit to how much data is filled in.
|
||||
const uint8_t* const stream_end = streamdata->stream + STREAM_SIZE_MAX_60;
|
||||
|
||||
stream_ptr = streamdata->stream + streamdata->stream_index;
|
||||
W_upper = streamdata->W_upper;
|
||||
if (streamdata->stream_index == 0) /* first time decoder is called for this stream */
|
||||
{
|
||||
/* read first word from bytestream */
|
||||
if (stream_ptr + 3 >= stream_end)
|
||||
return -1; // Would read out of bounds. Malformed input?
|
||||
streamval = *stream_ptr << 24;
|
||||
streamval |= *++stream_ptr << 16;
|
||||
streamval |= *++stream_ptr << 8;
|
||||
@ -277,6 +284,8 @@ int WebRtcIsac_DecLogisticMulti2(
|
||||
while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */
|
||||
{
|
||||
/* read next byte from stream */
|
||||
if (stream_ptr + 1 >= stream_end)
|
||||
return -1; // Would read out of bounds. Malformed input?
|
||||
streamval = (streamval << 8) | *++stream_ptr;
|
||||
W_upper <<= 8;
|
||||
}
|
||||
|
@ -8,9 +8,9 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/include/audio_decoder_isac.h"
|
||||
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h"
|
||||
#include "modules/audio_coding/codecs/isac/audio_decoder_isac_t_impl.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
|
@ -8,9 +8,9 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/include/audio_encoder_isac.h"
|
||||
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h"
|
||||
#include "modules/audio_coding/codecs/isac/audio_encoder_isac_t_impl.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
|
@ -16,14 +16,14 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bandwidth_estimator.h"
|
||||
#include "settings.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/include/isac.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/include/isac.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
/* array of quantization levels for bottle neck info; Matlab code: */
|
||||
/* sprintf('%4.1ff, ', logspace(log10(5000), log10(40000), 12)) */
|
||||
static const float kQRateTableWb[12] =
|
||||
@ -159,7 +159,7 @@ int16_t WebRtcIsac_UpdateBandwidthEstimator(
|
||||
int immediate_set = 0;
|
||||
int num_pkts_expected;
|
||||
|
||||
assert(!bwest_str->external_bw_info.in_use);
|
||||
RTC_DCHECK(!bwest_str->external_bw_info.in_use);
|
||||
|
||||
// We have to adjust the header-rate if the first packet has a
|
||||
// frame-size different than the initialized value.
|
||||
@ -514,7 +514,7 @@ int16_t WebRtcIsac_UpdateUplinkBwImpl(
|
||||
int16_t index,
|
||||
enum IsacSamplingRate encoderSamplingFreq)
|
||||
{
|
||||
assert(!bwest_str->external_bw_info.in_use);
|
||||
RTC_DCHECK(!bwest_str->external_bw_info.in_use);
|
||||
|
||||
if((index < 0) || (index > 23))
|
||||
{
|
||||
@ -572,7 +572,7 @@ int16_t WebRtcIsac_UpdateUplinkJitter(
|
||||
BwEstimatorstr* bwest_str,
|
||||
int32_t index)
|
||||
{
|
||||
assert(!bwest_str->external_bw_info.in_use);
|
||||
RTC_DCHECK(!bwest_str->external_bw_info.in_use);
|
||||
|
||||
if((index < 0) || (index > 23))
|
||||
{
|
||||
@ -711,7 +711,7 @@ int32_t WebRtcIsac_GetDownlinkBandwidth( const BwEstimatorstr *bwest_str)
|
||||
float jitter_sign;
|
||||
float bw_adjust;
|
||||
|
||||
assert(!bwest_str->external_bw_info.in_use);
|
||||
RTC_DCHECK(!bwest_str->external_bw_info.in_use);
|
||||
|
||||
/* create a value between -1.0 and 1.0 indicating "average sign" of jitter */
|
||||
jitter_sign = bwest_str->rec_jitter_short_term /
|
||||
@ -741,7 +741,7 @@ WebRtcIsac_GetDownlinkMaxDelay(const BwEstimatorstr *bwest_str)
|
||||
{
|
||||
int32_t rec_max_delay;
|
||||
|
||||
assert(!bwest_str->external_bw_info.in_use);
|
||||
RTC_DCHECK(!bwest_str->external_bw_info.in_use);
|
||||
|
||||
rec_max_delay = (int32_t)(bwest_str->rec_max_delay);
|
||||
|
||||
@ -759,7 +759,7 @@ WebRtcIsac_GetDownlinkMaxDelay(const BwEstimatorstr *bwest_str)
|
||||
|
||||
/* Clamp val to the closed interval [min,max]. */
|
||||
static int32_t clamp(int32_t val, int32_t min, int32_t max) {
|
||||
assert(min <= max);
|
||||
RTC_DCHECK_LE(min, max);
|
||||
return val < min ? min : (val > max ? max : val);
|
||||
}
|
||||
|
||||
@ -775,24 +775,6 @@ int32_t WebRtcIsac_GetUplinkMaxDelay(const BwEstimatorstr* bwest_str) {
|
||||
: clamp(bwest_str->send_max_delay_avg, MIN_ISAC_MD, MAX_ISAC_MD);
|
||||
}
|
||||
|
||||
void WebRtcIsacBw_GetBandwidthInfo(BwEstimatorstr* bwest_str,
|
||||
enum IsacSamplingRate decoder_sample_rate_hz,
|
||||
IsacBandwidthInfo* bwinfo) {
|
||||
assert(!bwest_str->external_bw_info.in_use);
|
||||
bwinfo->in_use = 1;
|
||||
bwinfo->send_bw_avg = WebRtcIsac_GetUplinkBandwidth(bwest_str);
|
||||
bwinfo->send_max_delay_avg = WebRtcIsac_GetUplinkMaxDelay(bwest_str);
|
||||
WebRtcIsac_GetDownlinkBwJitIndexImpl(bwest_str, &bwinfo->bottleneck_idx,
|
||||
&bwinfo->jitter_info,
|
||||
decoder_sample_rate_hz);
|
||||
}
|
||||
|
||||
void WebRtcIsacBw_SetBandwidthInfo(BwEstimatorstr* bwest_str,
|
||||
const IsacBandwidthInfo* bwinfo) {
|
||||
memcpy(&bwest_str->external_bw_info, bwinfo,
|
||||
sizeof bwest_str->external_bw_info);
|
||||
}
|
||||
|
||||
/*
|
||||
* update long-term average bitrate and amount of data in buffer
|
||||
* returns minimum payload size (bytes)
|
||||
|
@ -16,169 +16,150 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_
|
||||
|
||||
#include "structs.h"
|
||||
#include "settings.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/structs.h"
|
||||
|
||||
#define MIN_ISAC_BW 10000
|
||||
#define MIN_ISAC_BW_LB 10000
|
||||
#define MIN_ISAC_BW_UB 25000
|
||||
#define MIN_ISAC_BW 10000
|
||||
#define MIN_ISAC_BW_LB 10000
|
||||
#define MIN_ISAC_BW_UB 25000
|
||||
|
||||
#define MAX_ISAC_BW 56000
|
||||
#define MAX_ISAC_BW_UB 32000
|
||||
#define MAX_ISAC_BW_LB 32000
|
||||
#define MAX_ISAC_BW 56000
|
||||
#define MAX_ISAC_BW_UB 32000
|
||||
#define MAX_ISAC_BW_LB 32000
|
||||
|
||||
#define MIN_ISAC_MD 5
|
||||
#define MAX_ISAC_MD 25
|
||||
#define MIN_ISAC_MD 5
|
||||
#define MAX_ISAC_MD 25
|
||||
|
||||
// assumed header size, in bytes; we don't know the exact number
|
||||
// (header compression may be used)
|
||||
#define HEADER_SIZE 35
|
||||
#define HEADER_SIZE 35
|
||||
|
||||
// Initial Frame-Size, in ms, for Wideband & Super-Wideband Mode
|
||||
#define INIT_FRAME_LEN_WB 60
|
||||
#define INIT_FRAME_LEN_WB 60
|
||||
#define INIT_FRAME_LEN_SWB 30
|
||||
|
||||
// Initial Bottleneck Estimate, in bits/sec, for
|
||||
// Wideband & Super-wideband mode
|
||||
#define INIT_BN_EST_WB 20e3f
|
||||
#define INIT_BN_EST_SWB 56e3f
|
||||
#define INIT_BN_EST_WB 20e3f
|
||||
#define INIT_BN_EST_SWB 56e3f
|
||||
|
||||
// Initial Header rate (header rate depends on frame-size),
|
||||
// in bits/sec, for Wideband & Super-Wideband mode.
|
||||
#define INIT_HDR_RATE_WB \
|
||||
#define INIT_HDR_RATE_WB \
|
||||
((float)HEADER_SIZE * 8.0f * 1000.0f / (float)INIT_FRAME_LEN_WB)
|
||||
#define INIT_HDR_RATE_SWB \
|
||||
#define INIT_HDR_RATE_SWB \
|
||||
((float)HEADER_SIZE * 8.0f * 1000.0f / (float)INIT_FRAME_LEN_SWB)
|
||||
|
||||
// number of packets in a row for a high rate burst
|
||||
#define BURST_LEN 3
|
||||
#define BURST_LEN 3
|
||||
|
||||
// ms, max time between two full bursts
|
||||
#define BURST_INTERVAL 500
|
||||
#define BURST_INTERVAL 500
|
||||
|
||||
// number of packets in a row for initial high rate burst
|
||||
#define INIT_BURST_LEN 5
|
||||
#define INIT_BURST_LEN 5
|
||||
|
||||
// bits/s, rate for the first BURST_LEN packets
|
||||
#define INIT_RATE_WB INIT_BN_EST_WB
|
||||
#define INIT_RATE_SWB INIT_BN_EST_SWB
|
||||
|
||||
#define INIT_RATE_WB INIT_BN_EST_WB
|
||||
#define INIT_RATE_SWB INIT_BN_EST_SWB
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This function initializes the struct */
|
||||
/* to be called before using the struct for anything else */
|
||||
/* returns 0 if everything went fine, -1 otherwise */
|
||||
int32_t WebRtcIsac_InitBandwidthEstimator(
|
||||
BwEstimatorstr* bwest_str,
|
||||
enum IsacSamplingRate encoderSampRate,
|
||||
enum IsacSamplingRate decoderSampRate);
|
||||
/* This function initializes the struct */
|
||||
/* to be called before using the struct for anything else */
|
||||
/* returns 0 if everything went fine, -1 otherwise */
|
||||
int32_t WebRtcIsac_InitBandwidthEstimator(
|
||||
BwEstimatorstr* bwest_str,
|
||||
enum IsacSamplingRate encoderSampRate,
|
||||
enum IsacSamplingRate decoderSampRate);
|
||||
|
||||
/* This function updates the receiving estimate */
|
||||
/* Parameters: */
|
||||
/* rtp_number - value from RTP packet, from NetEq */
|
||||
/* frame length - length of signal frame in ms, from iSAC decoder */
|
||||
/* send_ts - value in RTP header giving send time in samples */
|
||||
/* arr_ts - value given by timeGetTime() time of arrival in samples of packet from NetEq */
|
||||
/* pksize - size of packet in bytes, from NetEq */
|
||||
/* Index - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */
|
||||
/* returns 0 if everything went fine, -1 otherwise */
|
||||
int16_t WebRtcIsac_UpdateBandwidthEstimator(
|
||||
BwEstimatorstr* bwest_str,
|
||||
const uint16_t rtp_number,
|
||||
const int32_t frame_length,
|
||||
const uint32_t send_ts,
|
||||
const uint32_t arr_ts,
|
||||
const size_t pksize);
|
||||
/* This function updates the receiving estimate */
|
||||
/* Parameters: */
|
||||
/* rtp_number - value from RTP packet, from NetEq */
|
||||
/* frame length - length of signal frame in ms, from iSAC decoder */
|
||||
/* send_ts - value in RTP header giving send time in samples */
|
||||
/* arr_ts - value given by timeGetTime() time of arrival in samples of
|
||||
* packet from NetEq */
|
||||
/* pksize - size of packet in bytes, from NetEq */
|
||||
/* Index - integer (range 0...23) indicating bottle neck & jitter as
|
||||
* estimated by other side */
|
||||
/* returns 0 if everything went fine, -1 otherwise */
|
||||
int16_t WebRtcIsac_UpdateBandwidthEstimator(BwEstimatorstr* bwest_str,
|
||||
const uint16_t rtp_number,
|
||||
const int32_t frame_length,
|
||||
const uint32_t send_ts,
|
||||
const uint32_t arr_ts,
|
||||
const size_t pksize);
|
||||
|
||||
/* Update receiving estimates. Used when we only receive BWE index, no iSAC data packet. */
|
||||
int16_t WebRtcIsac_UpdateUplinkBwImpl(
|
||||
BwEstimatorstr* bwest_str,
|
||||
int16_t Index,
|
||||
enum IsacSamplingRate encoderSamplingFreq);
|
||||
/* Update receiving estimates. Used when we only receive BWE index, no iSAC data
|
||||
* packet. */
|
||||
int16_t WebRtcIsac_UpdateUplinkBwImpl(
|
||||
BwEstimatorstr* bwest_str,
|
||||
int16_t Index,
|
||||
enum IsacSamplingRate encoderSamplingFreq);
|
||||
|
||||
/* Returns the bandwidth/jitter estimation code (integer 0...23) to put in the sending iSAC payload */
|
||||
void WebRtcIsac_GetDownlinkBwJitIndexImpl(
|
||||
BwEstimatorstr* bwest_str,
|
||||
int16_t* bottleneckIndex,
|
||||
int16_t* jitterInfo,
|
||||
enum IsacSamplingRate decoderSamplingFreq);
|
||||
/* Returns the bandwidth/jitter estimation code (integer 0...23) to put in the
|
||||
* sending iSAC payload */
|
||||
void WebRtcIsac_GetDownlinkBwJitIndexImpl(
|
||||
BwEstimatorstr* bwest_str,
|
||||
int16_t* bottleneckIndex,
|
||||
int16_t* jitterInfo,
|
||||
enum IsacSamplingRate decoderSamplingFreq);
|
||||
|
||||
/* Returns the bandwidth estimation (in bps) */
|
||||
int32_t WebRtcIsac_GetDownlinkBandwidth(
|
||||
const BwEstimatorstr *bwest_str);
|
||||
/* Returns the bandwidth estimation (in bps) */
|
||||
int32_t WebRtcIsac_GetDownlinkBandwidth(const BwEstimatorstr* bwest_str);
|
||||
|
||||
/* Returns the max delay (in ms) */
|
||||
int32_t WebRtcIsac_GetDownlinkMaxDelay(
|
||||
const BwEstimatorstr *bwest_str);
|
||||
/* Returns the max delay (in ms) */
|
||||
int32_t WebRtcIsac_GetDownlinkMaxDelay(const BwEstimatorstr* bwest_str);
|
||||
|
||||
/* Returns the bandwidth that iSAC should send with in bps */
|
||||
int32_t WebRtcIsac_GetUplinkBandwidth(const BwEstimatorstr* bwest_str);
|
||||
/* Returns the bandwidth that iSAC should send with in bps */
|
||||
int32_t WebRtcIsac_GetUplinkBandwidth(const BwEstimatorstr* bwest_str);
|
||||
|
||||
/* Returns the max delay value from the other side in ms */
|
||||
int32_t WebRtcIsac_GetUplinkMaxDelay(
|
||||
const BwEstimatorstr *bwest_str);
|
||||
/* Returns the max delay value from the other side in ms */
|
||||
int32_t WebRtcIsac_GetUplinkMaxDelay(const BwEstimatorstr* bwest_str);
|
||||
|
||||
/* Fills in an IsacExternalBandwidthInfo struct. */
|
||||
void WebRtcIsacBw_GetBandwidthInfo(
|
||||
BwEstimatorstr* bwest_str,
|
||||
enum IsacSamplingRate decoder_sample_rate_hz,
|
||||
IsacBandwidthInfo* bwinfo);
|
||||
/*
|
||||
* update amount of data in bottle neck buffer and burst handling
|
||||
* returns minimum payload size (bytes)
|
||||
*/
|
||||
int WebRtcIsac_GetMinBytes(
|
||||
RateModel* State,
|
||||
int StreamSize, /* bytes in bitstream */
|
||||
const int FrameLen, /* ms per frame */
|
||||
const double BottleNeck, /* bottle neck rate; excl headers (bps) */
|
||||
const double DelayBuildUp, /* max delay from bottleneck buffering (ms) */
|
||||
enum ISACBandwidth bandwidth
|
||||
/*,int16_t frequentLargePackets*/);
|
||||
|
||||
/* Uses the values from an IsacExternalBandwidthInfo struct. */
|
||||
void WebRtcIsacBw_SetBandwidthInfo(BwEstimatorstr* bwest_str,
|
||||
const IsacBandwidthInfo* bwinfo);
|
||||
/*
|
||||
* update long-term average bitrate and amount of data in buffer
|
||||
*/
|
||||
void WebRtcIsac_UpdateRateModel(
|
||||
RateModel* State,
|
||||
int StreamSize, /* bytes in bitstream */
|
||||
const int FrameSamples, /* samples per frame */
|
||||
const double BottleNeck); /* bottle neck rate; excl headers (bps) */
|
||||
|
||||
/*
|
||||
* update amount of data in bottle neck buffer and burst handling
|
||||
* returns minimum payload size (bytes)
|
||||
*/
|
||||
int WebRtcIsac_GetMinBytes(
|
||||
RateModel* State,
|
||||
int StreamSize, /* bytes in bitstream */
|
||||
const int FrameLen, /* ms per frame */
|
||||
const double BottleNeck, /* bottle neck rate; excl headers (bps) */
|
||||
const double DelayBuildUp, /* max delay from bottleneck buffering (ms) */
|
||||
enum ISACBandwidth bandwidth
|
||||
/*,int16_t frequentLargePackets*/);
|
||||
void WebRtcIsac_InitRateModel(RateModel* State);
|
||||
|
||||
/*
|
||||
* update long-term average bitrate and amount of data in buffer
|
||||
*/
|
||||
void WebRtcIsac_UpdateRateModel(
|
||||
RateModel* State,
|
||||
int StreamSize, /* bytes in bitstream */
|
||||
const int FrameSamples, /* samples per frame */
|
||||
const double BottleNeck); /* bottle neck rate; excl headers (bps) */
|
||||
/* Returns the new framelength value (input argument: bottle_neck) */
|
||||
int WebRtcIsac_GetNewFrameLength(double bottle_neck, int current_framelength);
|
||||
|
||||
/* Returns the new SNR value (input argument: bottle_neck) */
|
||||
double WebRtcIsac_GetSnr(double bottle_neck, int new_framelength);
|
||||
|
||||
void WebRtcIsac_InitRateModel(
|
||||
RateModel *State);
|
||||
|
||||
/* Returns the new framelength value (input argument: bottle_neck) */
|
||||
int WebRtcIsac_GetNewFrameLength(
|
||||
double bottle_neck,
|
||||
int current_framelength);
|
||||
|
||||
/* Returns the new SNR value (input argument: bottle_neck) */
|
||||
double WebRtcIsac_GetSnr(
|
||||
double bottle_neck,
|
||||
int new_framelength);
|
||||
|
||||
|
||||
int16_t WebRtcIsac_UpdateUplinkJitter(
|
||||
BwEstimatorstr* bwest_str,
|
||||
int32_t index);
|
||||
int16_t WebRtcIsac_UpdateUplinkJitter(BwEstimatorstr* bwest_str, int32_t index);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ */
|
||||
#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ \
|
||||
*/
|
||||
|
@ -16,18 +16,22 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_
|
||||
|
||||
#include "structs.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/structs.h"
|
||||
#include "modules/third_party/fft/fft.h"
|
||||
|
||||
void WebRtcIsac_ResetBitstream(Bitstr* bit_stream);
|
||||
|
||||
int WebRtcIsac_EstimateBandwidth(BwEstimatorstr* bwest_str, Bitstr* streamdata,
|
||||
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,
|
||||
uint32_t send_ts,
|
||||
uint32_t arr_ts,
|
||||
enum IsacSamplingRate encoderSampRate,
|
||||
enum IsacSamplingRate decoderSampRate);
|
||||
|
||||
@ -37,7 +41,8 @@ int WebRtcIsac_DecodeLb(const TransformTables* transform_tables,
|
||||
int16_t* current_framesamples,
|
||||
int16_t isRCUPayload);
|
||||
|
||||
int WebRtcIsac_DecodeRcuLb(float* signal_out, ISACLBDecStruct* ISACdec_obj,
|
||||
int WebRtcIsac_DecodeRcuLb(float* signal_out,
|
||||
ISACLBDecStruct* ISACdec_obj,
|
||||
int16_t* current_framesamples);
|
||||
|
||||
int WebRtcIsac_EncodeLb(const TransformTables* transform_tables,
|
||||
@ -47,15 +52,20 @@ int WebRtcIsac_EncodeLb(const TransformTables* transform_tables,
|
||||
int16_t bottleneckIndex);
|
||||
|
||||
int WebRtcIsac_EncodeStoredDataLb(const IsacSaveEncoderData* ISACSavedEnc_obj,
|
||||
Bitstr* ISACBitStr_obj, int BWnumber,
|
||||
Bitstr* ISACBitStr_obj,
|
||||
int BWnumber,
|
||||
float scale);
|
||||
|
||||
int WebRtcIsac_EncodeStoredDataUb(
|
||||
const ISACUBSaveEncDataStruct* ISACSavedEnc_obj, Bitstr* bitStream,
|
||||
int32_t jitterInfo, float scale, enum ISACBandwidth bandwidth);
|
||||
const ISACUBSaveEncDataStruct* ISACSavedEnc_obj,
|
||||
Bitstr* bitStream,
|
||||
int32_t jitterInfo,
|
||||
float scale,
|
||||
enum ISACBandwidth bandwidth);
|
||||
|
||||
int16_t WebRtcIsac_GetRedPayloadUb(
|
||||
const ISACUBSaveEncDataStruct* ISACSavedEncObj, Bitstr* bitStreamObj,
|
||||
const ISACUBSaveEncDataStruct* ISACSavedEncObj,
|
||||
Bitstr* bitStreamObj,
|
||||
enum ISACBandwidth bandwidth);
|
||||
|
||||
/******************************************************************************
|
||||
@ -81,7 +91,6 @@ int16_t WebRtcIsac_RateAllocation(int32_t inRateBitPerSec,
|
||||
double* rateUBBitPerSec,
|
||||
enum ISACBandwidth* bandwidthKHz);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeUb16()
|
||||
*
|
||||
@ -166,15 +175,8 @@ int WebRtcIsac_EncodeUb12(const TransformTables* transform_tables,
|
||||
|
||||
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);
|
||||
@ -193,41 +195,29 @@ void WebRtcIsac_Spec2time(const TransformTables* tables,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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_ */
|
||||
#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_ */
|
||||
|
@ -8,9 +8,10 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "crc.h"
|
||||
#include <stdlib.h>
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/crc.h"
|
||||
#include "common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
#define POLYNOMIAL 0x04c11db7L
|
||||
|
||||
|
@ -15,10 +15,10 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcIsac_GetCrc(...)
|
||||
@ -36,11 +36,6 @@
|
||||
* -1 - Error
|
||||
*/
|
||||
|
||||
int WebRtcIsac_GetCrc(
|
||||
const int16_t* encoded,
|
||||
int no_of_word8s,
|
||||
uint32_t* crc);
|
||||
int WebRtcIsac_GetCrc(const int16_t* encoded, int no_of_word8s, uint32_t* crc);
|
||||
|
||||
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_ */
|
||||
#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_ */
|
||||
|
@ -18,18 +18,17 @@
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "codec.h"
|
||||
#include "entropy_coding.h"
|
||||
#include "pitch_estimator.h"
|
||||
#include "bandwidth_estimator.h"
|
||||
#include "structs.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/codec.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/structs.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/pitch_filter.h"
|
||||
|
||||
/*
|
||||
* function to decode the bitstream
|
||||
|
@ -8,10 +8,10 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "structs.h"
|
||||
#include "bandwidth_estimator.h"
|
||||
#include "entropy_coding.h"
|
||||
#include "codec.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/structs.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/codec.h"
|
||||
|
||||
|
||||
int
|
||||
|
@ -21,20 +21,22 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "structs.h"
|
||||
#include "codec.h"
|
||||
#include "pitch_estimator.h"
|
||||
#include "entropy_coding.h"
|
||||
#include "arith_routines.h"
|
||||
#include "pitch_gain_tables.h"
|
||||
#include "pitch_lag_tables.h"
|
||||
#include "spectrum_ar_model_tables.h"
|
||||
#include "lpc_tables.h"
|
||||
#include "lpc_analysis.h"
|
||||
#include "bandwidth_estimator.h"
|
||||
#include "lpc_shape_swb12_tables.h"
|
||||
#include "lpc_shape_swb16_tables.h"
|
||||
#include "lpc_gain_swb_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/structs.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/codec.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/arith_routines.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_analysis.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/pitch_filter.h"
|
||||
|
||||
|
||||
#define UB_LOOKAHEAD 24
|
||||
|
@ -16,17 +16,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#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"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_RemoveLarMean()
|
||||
|
@ -16,12 +16,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#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_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
|
||||
|
||||
#include "settings.h"
|
||||
#include "structs.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/structs.h"
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_RemoveLarMean()
|
||||
@ -39,9 +38,7 @@
|
||||
*
|
||||
*
|
||||
*/
|
||||
int16_t WebRtcIsac_RemoveLarMean(
|
||||
double* lar,
|
||||
int16_t bandwidth);
|
||||
int16_t WebRtcIsac_RemoveLarMean(double* lar, int16_t bandwidth);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecorrelateIntraVec()
|
||||
@ -59,11 +56,9 @@ int16_t WebRtcIsac_RemoveLarMean(
|
||||
* Output:
|
||||
* -out : decorrelated LAR vectors.
|
||||
*/
|
||||
int16_t WebRtcIsac_DecorrelateIntraVec(
|
||||
const double* inLAR,
|
||||
double* out,
|
||||
int16_t bandwidth);
|
||||
|
||||
int16_t WebRtcIsac_DecorrelateIntraVec(const double* inLAR,
|
||||
double* out,
|
||||
int16_t bandwidth);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecorrelateInterVec()
|
||||
@ -82,11 +77,9 @@ int16_t WebRtcIsac_DecorrelateIntraVec(
|
||||
* Output:
|
||||
* -out : decorrelated LAR vectors.
|
||||
*/
|
||||
int16_t WebRtcIsac_DecorrelateInterVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
int16_t bandwidth);
|
||||
|
||||
int16_t WebRtcIsac_DecorrelateInterVec(const double* data,
|
||||
double* out,
|
||||
int16_t bandwidth);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_QuantizeUncorrLar()
|
||||
@ -102,11 +95,7 @@ int16_t WebRtcIsac_DecorrelateInterVec(
|
||||
* -data : quantized version of the input.
|
||||
* -idx : pointer to quantization indices.
|
||||
*/
|
||||
double WebRtcIsac_QuantizeUncorrLar(
|
||||
double* data,
|
||||
int* idx,
|
||||
int16_t bandwidth);
|
||||
|
||||
double WebRtcIsac_QuantizeUncorrLar(double* data, int* idx, int16_t bandwidth);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_CorrelateIntraVec()
|
||||
@ -121,11 +110,9 @@ double WebRtcIsac_QuantizeUncorrLar(
|
||||
* Output:
|
||||
* -out : correlated parametrs.
|
||||
*/
|
||||
int16_t WebRtcIsac_CorrelateIntraVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
int16_t bandwidth);
|
||||
|
||||
int16_t WebRtcIsac_CorrelateIntraVec(const double* data,
|
||||
double* out,
|
||||
int16_t bandwidth);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_CorrelateInterVec()
|
||||
@ -140,17 +127,15 @@ int16_t WebRtcIsac_CorrelateIntraVec(
|
||||
* Output:
|
||||
* -out : correlated parametrs.
|
||||
*/
|
||||
int16_t WebRtcIsac_CorrelateInterVec(
|
||||
const double* data,
|
||||
double* out,
|
||||
int16_t bandwidth);
|
||||
|
||||
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
|
||||
@ -159,10 +144,7 @@ int16_t WebRtcIsac_CorrelateInterVec(
|
||||
* Output:
|
||||
* -data : pointer to LARs.
|
||||
*/
|
||||
int16_t WebRtcIsac_AddLarMean(
|
||||
double* data,
|
||||
int16_t bandwidth);
|
||||
|
||||
int16_t WebRtcIsac_AddLarMean(double* data, int16_t bandwidth);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DequantizeLpcParam()
|
||||
@ -177,11 +159,9 @@ int16_t WebRtcIsac_AddLarMean(
|
||||
* Output:
|
||||
* -out : pointer to quantized values.
|
||||
*/
|
||||
int16_t WebRtcIsac_DequantizeLpcParam(
|
||||
const int* idx,
|
||||
double* out,
|
||||
int16_t bandwidth);
|
||||
|
||||
int16_t WebRtcIsac_DequantizeLpcParam(const int* idx,
|
||||
double* out,
|
||||
int16_t bandwidth);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_ToLogDomainRemoveMean()
|
||||
@ -194,9 +174,7 @@ int16_t WebRtcIsac_DequantizeLpcParam(
|
||||
* Output:
|
||||
* -lpcGain : mean-removed in log domain.
|
||||
*/
|
||||
int16_t WebRtcIsac_ToLogDomainRemoveMean(
|
||||
double* lpGains);
|
||||
|
||||
int16_t WebRtcIsac_ToLogDomainRemoveMean(double* lpGains);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecorrelateLPGain()
|
||||
@ -210,16 +188,13 @@ int16_t WebRtcIsac_ToLogDomainRemoveMean(
|
||||
* Output:
|
||||
* -out : decorrelated parameters.
|
||||
*/
|
||||
int16_t WebRtcIsac_DecorrelateLPGain(
|
||||
const double* data,
|
||||
double* out);
|
||||
|
||||
int16_t WebRtcIsac_DecorrelateLPGain(const double* data, double* out);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_QuantizeLpcGain()
|
||||
*
|
||||
* Quantize the decorrelated log-domain gains.
|
||||
*
|
||||
*
|
||||
* Input:
|
||||
* -lpcGain : uncorrelated LPC gains.
|
||||
*
|
||||
@ -227,10 +202,7 @@ int16_t WebRtcIsac_DecorrelateLPGain(
|
||||
* -idx : quantization indices
|
||||
* -lpcGain : quantized value of the inpt.
|
||||
*/
|
||||
double WebRtcIsac_QuantizeLpcGain(
|
||||
double* lpGains,
|
||||
int* idx);
|
||||
|
||||
double WebRtcIsac_QuantizeLpcGain(double* lpGains, int* idx);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DequantizeLpcGain()
|
||||
@ -243,10 +215,7 @@ double WebRtcIsac_QuantizeLpcGain(
|
||||
* Output:
|
||||
* -lpcGains : quantized values of the given parametes.
|
||||
*/
|
||||
int16_t WebRtcIsac_DequantizeLpcGain(
|
||||
const int* idx,
|
||||
double* lpGains);
|
||||
|
||||
int16_t WebRtcIsac_DequantizeLpcGain(const int* idx, double* lpGains);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_CorrelateLpcGain()
|
||||
@ -259,10 +228,7 @@ int16_t WebRtcIsac_DequantizeLpcGain(
|
||||
* Output:
|
||||
* -out : correlated parameters.
|
||||
*/
|
||||
int16_t WebRtcIsac_CorrelateLpcGain(
|
||||
const double* data,
|
||||
double* out);
|
||||
|
||||
int16_t WebRtcIsac_CorrelateLpcGain(const double* data, double* out);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_AddMeanToLinearDomain()
|
||||
@ -275,8 +241,6 @@ int16_t WebRtcIsac_CorrelateLpcGain(
|
||||
* Output:
|
||||
* -lpcGain : LPC gain in normal domain.
|
||||
*/
|
||||
int16_t WebRtcIsac_AddMeanToLinearDomain(
|
||||
double* lpcGains);
|
||||
int16_t WebRtcIsac_AddMeanToLinearDomain(double* lpcGains);
|
||||
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_
|
||||
|
@ -17,19 +17,19 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "entropy_coding.h"
|
||||
#include "settings.h"
|
||||
#include "arith_routines.h"
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "spectrum_ar_model_tables.h"
|
||||
#include "lpc_tables.h"
|
||||
#include "pitch_gain_tables.h"
|
||||
#include "pitch_lag_tables.h"
|
||||
#include "encode_lpc_swb.h"
|
||||
#include "lpc_shape_swb12_tables.h"
|
||||
#include "lpc_shape_swb16_tables.h"
|
||||
#include "lpc_gain_swb_tables.h"
|
||||
#include "os_specific_inline.h"
|
||||
#include "common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/arith_routines.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/os_specific_inline.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
@ -42,7 +42,7 @@ static const uint16_t kOneBitEqualProbCdf[3] = {
|
||||
0, 32768, 65535 };
|
||||
|
||||
/* Pointer to cdf array for encoder bandwidth (12 vs 16 kHz) indicator. */
|
||||
static const uint16_t* kOneBitEqualProbCdf_ptr[1] = {
|
||||
static const uint16_t* const kOneBitEqualProbCdf_ptr[1] = {
|
||||
kOneBitEqualProbCdf };
|
||||
|
||||
/*
|
||||
@ -96,7 +96,7 @@ static void FindInvArSpec(const int16_t* ARCoefQ12,
|
||||
const int32_t gainQ10,
|
||||
int32_t* CurveQ16) {
|
||||
int32_t CorrQ11[AR_ORDER + 1];
|
||||
int32_t sum, tmpGain;
|
||||
int64_t sum, tmpGain;
|
||||
int32_t diffQ16[FRAMESAMPLES / 8];
|
||||
const int16_t* CS_ptrQ9;
|
||||
int k, n;
|
||||
@ -162,9 +162,9 @@ static void FindInvArSpec(const int16_t* ARCoefQ12,
|
||||
}
|
||||
|
||||
for (k = 0; k < FRAMESAMPLES / 8; k++) {
|
||||
CurveQ16[FRAMESAMPLES_QUARTER - 1 - k] = CurveQ16[k] -
|
||||
(diffQ16[k] << shftVal);
|
||||
CurveQ16[k] += diffQ16[k] << shftVal;
|
||||
int32_t diff_q16_shifted = (int32_t)((uint32_t)(diffQ16[k]) << shftVal);
|
||||
CurveQ16[FRAMESAMPLES_QUARTER - 1 - k] = CurveQ16[k] - diff_q16_shifted;
|
||||
CurveQ16[k] += diff_q16_shifted;
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,13 +182,13 @@ static void GenerateDitherQ7Lb(int16_t* bufQ7, uint32_t seed,
|
||||
|
||||
/* Fixed-point dither sample between -64 and 64 (Q7). */
|
||||
/* dither = seed * 128 / 4294967295 */
|
||||
dither1_Q7 = (int16_t)(((int)seed + 16777216) >> 25);
|
||||
dither1_Q7 = (int16_t)(((int32_t)(seed + 16777216)) >> 25);
|
||||
|
||||
/* New random unsigned int. */
|
||||
seed = (seed * 196314165) + 907633515;
|
||||
|
||||
/* Fixed-point dither sample between -64 and 64. */
|
||||
dither2_Q7 = (int16_t)(((int)seed + 16777216) >> 25);
|
||||
dither2_Q7 = (int16_t)(((int32_t)(seed + 16777216)) >> 25);
|
||||
|
||||
shft = (seed >> 25) & 15;
|
||||
if (shft < 5) {
|
||||
@ -214,7 +214,7 @@ static void GenerateDitherQ7Lb(int16_t* bufQ7, uint32_t seed,
|
||||
seed = (seed * 196314165) + 907633515;
|
||||
|
||||
/* Fixed-point dither sample between -64 and 64. */
|
||||
dither1_Q7 = (int16_t)(((int)seed + 16777216) >> 25);
|
||||
dither1_Q7 = (int16_t)(((int32_t)(seed + 16777216)) >> 25);
|
||||
|
||||
/* Dither sample is placed in either even or odd index. */
|
||||
shft = (seed >> 25) & 1; /* Either 0 or 1 */
|
||||
@ -254,7 +254,7 @@ static void GenerateDitherQ7LbUB(
|
||||
|
||||
/* Fixed-point dither sample between -64 and 64 (Q7). */
|
||||
/* bufQ7 = seed * 128 / 4294967295 */
|
||||
bufQ7[k] = (int16_t)(((int)seed + 16777216) >> 25);
|
||||
bufQ7[k] = (int16_t)(((int32_t)(seed + 16777216)) >> 25);
|
||||
|
||||
/* Scale by 0.35. */
|
||||
bufQ7[k] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(bufQ7[k], 2048, 13);
|
||||
@ -1843,7 +1843,7 @@ static const uint16_t kBwCdf[25] = {
|
||||
62804, 65535 };
|
||||
|
||||
/* pointer to cdf array for estimated bandwidth */
|
||||
static const uint16_t* kBwCdfPtr[1] = { kBwCdf };
|
||||
static const uint16_t* const kBwCdfPtr[1] = { kBwCdf };
|
||||
|
||||
/* initial cdf index for decoder of estimated bandwidth*/
|
||||
static const uint16_t kBwInitIndex[1] = { 7 };
|
||||
|
@ -16,11 +16,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_
|
||||
|
||||
#include "settings.h"
|
||||
#include "structs.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/structs.h"
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeSpec()
|
||||
@ -46,8 +46,11 @@
|
||||
* 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);
|
||||
int WebRtcIsac_DecodeSpec(Bitstr* streamdata,
|
||||
int16_t AvgPitchGain_Q12,
|
||||
enum ISACBand band,
|
||||
double* fr,
|
||||
double* fi);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeSpec()
|
||||
@ -72,24 +75,31 @@ int WebRtcIsac_DecodeSpec(Bitstr* streamdata, int16_t AvgPitchGain_Q12,
|
||||
* 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,
|
||||
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,
|
||||
int WebRtcIsac_DecodeLpcCoefUB(Bitstr* streamdata,
|
||||
double* lpcVecs,
|
||||
double* percepFilterGains,
|
||||
int16_t bandwidth);
|
||||
|
||||
int WebRtcIsac_DecodeLpc(Bitstr* streamdata, double* LPCCoef_lo,
|
||||
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_EncodeLpcLb(double* LPCCoef_lo,
|
||||
double* LPCCoef_hi,
|
||||
Bitstr* streamdata,
|
||||
IsacSaveEncoderData* encData);
|
||||
|
||||
void WebRtcIsac_EncodeLpcGainLb(double* LPCCoef_lo, double* LPCCoef_hi,
|
||||
void WebRtcIsac_EncodeLpcGainLb(double* LPCCoef_lo,
|
||||
double* LPCCoef_hi,
|
||||
Bitstr* streamdata,
|
||||
IsacSaveEncoderData* encData);
|
||||
|
||||
@ -126,7 +136,8 @@ void WebRtcIsac_EncodeLpcGainLb(double* LPCCoef_lo, double* LPCCoef_hi,
|
||||
* Return value : 0 if encoding is successful,
|
||||
* <0 if failed to encode.
|
||||
*/
|
||||
int16_t WebRtcIsac_EncodeLpcUB(double* lpcCoeff, Bitstr* streamdata,
|
||||
int16_t WebRtcIsac_EncodeLpcUB(double* lpcCoeff,
|
||||
Bitstr* streamdata,
|
||||
double* interpolLPCCoeff,
|
||||
int16_t bandwidth,
|
||||
ISACUBSaveEncDataStruct* encData);
|
||||
@ -184,9 +195,9 @@ void WebRtcIsac_EncodePitchLag(double* PitchLags,
|
||||
Bitstr* streamdata,
|
||||
IsacSaveEncoderData* encData);
|
||||
|
||||
int WebRtcIsac_DecodePitchGain(Bitstr* streamdata,
|
||||
int16_t* PitchGain_Q12);
|
||||
int WebRtcIsac_DecodePitchLag(Bitstr* streamdata, int16_t* PitchGain_Q12,
|
||||
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);
|
||||
@ -200,10 +211,10 @@ 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,
|
||||
void WebRtcIsac_TranscodeLPCCoef(double* LPCCoef_lo,
|
||||
double* LPCCoef_hi,
|
||||
int* index_g);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeLpcGainUb()
|
||||
* Encode LPC gains of sub-Frames.
|
||||
@ -220,10 +231,10 @@ void WebRtcIsac_TranscodeLPCCoef(double* LPCCoef_lo, double* LPCCoef_hi,
|
||||
* - lpcGainIndex : quantization indices for lpc gains, these will
|
||||
* be stored to be used for FEC.
|
||||
*/
|
||||
void WebRtcIsac_EncodeLpcGainUb(double* lpGains, Bitstr* streamdata,
|
||||
void WebRtcIsac_EncodeLpcGainUb(double* lpGains,
|
||||
Bitstr* streamdata,
|
||||
int* lpcGainIndex);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeLpcGainUb()
|
||||
* Store LPC gains of sub-Frames in 'streamdata'.
|
||||
@ -239,7 +250,6 @@ void WebRtcIsac_EncodeLpcGainUb(double* lpGains, Bitstr* streamdata,
|
||||
*/
|
||||
void WebRtcIsac_StoreLpcGainUb(double* lpGains, Bitstr* streamdata);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeLpcGainUb()
|
||||
* Decode the LPC gain of sub-frames.
|
||||
@ -257,7 +267,6 @@ void WebRtcIsac_StoreLpcGainUb(double* lpGains, Bitstr* streamdata);
|
||||
*/
|
||||
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.
|
||||
@ -277,7 +286,6 @@ int16_t WebRtcIsac_DecodeLpcGainUb(double* lpGains, Bitstr* streamdata);
|
||||
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
|
||||
@ -298,7 +306,6 @@ int16_t WebRtcIsac_EncodeBandwidth(enum ISACBandwidth bandwidth,
|
||||
int16_t WebRtcIsac_DecodeBandwidth(Bitstr* streamData,
|
||||
enum ISACBandwidth* bandwidth);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_EncodeJitterInfo()
|
||||
* Decode the jitter information.
|
||||
@ -316,9 +323,7 @@ int16_t WebRtcIsac_DecodeBandwidth(Bitstr* streamData,
|
||||
* Return value : 0 if succeeded.
|
||||
* <0 if failed.
|
||||
*/
|
||||
int16_t WebRtcIsac_EncodeJitterInfo(int32_t jitterIndex,
|
||||
Bitstr* streamData);
|
||||
|
||||
int16_t WebRtcIsac_EncodeJitterInfo(int32_t jitterIndex, Bitstr* streamData);
|
||||
|
||||
/******************************************************************************
|
||||
* WebRtcIsac_DecodeJitterInfo()
|
||||
@ -337,7 +342,6 @@ int16_t WebRtcIsac_EncodeJitterInfo(int32_t jitterIndex,
|
||||
* Return value : 0 if succeeded.
|
||||
* <0 if failed.
|
||||
*/
|
||||
int16_t WebRtcIsac_DecodeJitterInfo(Bitstr* streamData,
|
||||
int32_t* jitterInfo);
|
||||
int16_t WebRtcIsac_DecodeJitterInfo(Bitstr* streamData, int32_t* jitterInfo);
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_ */
|
||||
#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_ */
|
||||
|
@ -13,16 +13,14 @@
|
||||
#ifdef WEBRTC_ANDROID
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#include "pitch_estimator.h"
|
||||
#include "lpc_analysis.h"
|
||||
#include "codec.h"
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
|
||||
|
||||
|
||||
void WebRtcIsac_AllPoleFilter(double* InOut,
|
||||
double* Coef,
|
||||
size_t lengthInOut,
|
||||
int orderCoef) {
|
||||
static void WebRtcIsac_AllPoleFilter(double* InOut,
|
||||
double* Coef,
|
||||
size_t lengthInOut,
|
||||
int orderCoef) {
|
||||
/* the state of filter is assumed to be in InOut[-1] to InOut[-orderCoef] */
|
||||
double scal;
|
||||
double sum;
|
||||
@ -55,12 +53,11 @@ void WebRtcIsac_AllPoleFilter(double* InOut,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WebRtcIsac_AllZeroFilter(double* In,
|
||||
double* Coef,
|
||||
size_t lengthInOut,
|
||||
int orderCoef,
|
||||
double* Out) {
|
||||
static void WebRtcIsac_AllZeroFilter(double* In,
|
||||
double* Coef,
|
||||
size_t lengthInOut,
|
||||
int orderCoef,
|
||||
double* Out) {
|
||||
/* the state of filter is assumed to be in In[-1] to In[-orderCoef] */
|
||||
|
||||
size_t n;
|
||||
@ -80,13 +77,12 @@ void WebRtcIsac_AllZeroFilter(double* In,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WebRtcIsac_ZeroPoleFilter(double* In,
|
||||
double* ZeroCoef,
|
||||
double* PoleCoef,
|
||||
size_t lengthInOut,
|
||||
int orderCoef,
|
||||
double* Out) {
|
||||
static void WebRtcIsac_ZeroPoleFilter(double* In,
|
||||
double* ZeroCoef,
|
||||
double* PoleCoef,
|
||||
size_t lengthInOut,
|
||||
int orderCoef,
|
||||
double* Out) {
|
||||
/* the state of the zero section is assumed to be in In[-1] to In[-orderCoef] */
|
||||
/* the state of the pole section is assumed to be in Out[-1] to Out[-orderCoef] */
|
||||
|
||||
@ -115,8 +111,10 @@ void WebRtcIsac_AutoCorr(double* r, const double* x, size_t N, size_t order) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void WebRtcIsac_BwExpand(double* out, double* in, double coef, size_t length) {
|
||||
static void WebRtcIsac_BwExpand(double* out,
|
||||
double* in,
|
||||
double coef,
|
||||
size_t length) {
|
||||
size_t i;
|
||||
double chirp;
|
||||
|
||||
@ -195,69 +193,3 @@ void WebRtcIsac_WeightingFilter(const double* in,
|
||||
memcpy(weiout, weoutbuf+PITCH_WLPCORDER, sizeof(double) * PITCH_FRAME_LEN);
|
||||
memcpy(whiout, whoutbuf+PITCH_WLPCORDER, sizeof(double) * PITCH_FRAME_LEN);
|
||||
}
|
||||
|
||||
|
||||
static const double APupper[ALLPASSSECTIONS] = {0.0347, 0.3826};
|
||||
static const double APlower[ALLPASSSECTIONS] = {0.1544, 0.744};
|
||||
|
||||
|
||||
void WebRtcIsac_AllpassFilterForDec(double* InOut,
|
||||
const double* APSectionFactors,
|
||||
size_t lengthInOut,
|
||||
double* FilterState) {
|
||||
//This performs all-pass filtering--a series of first order all-pass sections are used
|
||||
//to filter the input in a cascade manner.
|
||||
size_t n,j;
|
||||
double temp;
|
||||
for (j=0; j<ALLPASSSECTIONS; j++){
|
||||
for (n=0;n<lengthInOut;n+=2){
|
||||
temp = InOut[n]; //store input
|
||||
InOut[n] = FilterState[j] + APSectionFactors[j]*temp;
|
||||
FilterState[j] = -APSectionFactors[j]*InOut[n] + temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcIsac_DecimateAllpass(const double* in,
|
||||
double* state_in,
|
||||
size_t N,
|
||||
double* out) {
|
||||
size_t n;
|
||||
double data_vec[PITCH_FRAME_LEN];
|
||||
|
||||
/* copy input */
|
||||
memcpy(data_vec+1, in, sizeof(double) * (N-1));
|
||||
|
||||
data_vec[0] = state_in[2*ALLPASSSECTIONS]; //the z^(-1) state
|
||||
state_in[2*ALLPASSSECTIONS] = in[N-1];
|
||||
|
||||
WebRtcIsac_AllpassFilterForDec(data_vec+1, APupper, N, state_in);
|
||||
WebRtcIsac_AllpassFilterForDec(data_vec, APlower, N, state_in+ALLPASSSECTIONS);
|
||||
|
||||
for (n=0;n<N/2;n++)
|
||||
out[n] = data_vec[2*n] + data_vec[2*n+1];
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* create high-pass filter ocefficients
|
||||
* z = 0.998 * exp(j*2*pi*35/8000);
|
||||
* p = 0.94 * exp(j*2*pi*140/8000);
|
||||
* HP_b = [1, -2*real(z), abs(z)^2];
|
||||
* HP_a = [1, -2*real(p), abs(p)^2]; */
|
||||
static const double a_coef[2] = { 1.86864659625574, -0.88360000000000};
|
||||
static const double b_coef[2] = {-1.99524591718270, 0.99600400000000};
|
||||
|
||||
/* second order high-pass filter */
|
||||
void WebRtcIsac_Highpass(const double* in,
|
||||
double* out,
|
||||
double* state,
|
||||
size_t N) {
|
||||
size_t k;
|
||||
|
||||
for (k=0; k<N; k++) {
|
||||
*out = *in + state[1];
|
||||
state[1] = state[0] + b_coef[0] * *in + a_coef[0] * *out;
|
||||
state[0] = b_coef[1] * *in++ + a_coef[1] * *out++;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTER_FUNCTIONS_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTER_FUNCTIONS_H_
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/structs.h"
|
||||
|
||||
void WebRtcIsac_AutoCorr(double* r, const double* x, size_t N, size_t order);
|
||||
|
||||
void WebRtcIsac_WeightingFilter(const double* in,
|
||||
double* weiout,
|
||||
double* whiout,
|
||||
WeightFiltstr* wfdata);
|
||||
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTER_FUNCTIONS_H_
|
@ -1,37 +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.
|
||||
*/
|
||||
|
||||
/* filterbank_tables.c*/
|
||||
/* This file contains variables that are used in filterbanks.c*/
|
||||
|
||||
#include "filterbank_tables.h"
|
||||
#include "settings.h"
|
||||
|
||||
/* The composite all-pass filter factors */
|
||||
const float WebRtcIsac_kCompositeApFactorsFloat[4] = {
|
||||
0.03470000000000f, 0.15440000000000f, 0.38260000000000f, 0.74400000000000f};
|
||||
|
||||
/* The upper channel all-pass filter factors */
|
||||
const float WebRtcIsac_kUpperApFactorsFloat[2] = {
|
||||
0.03470000000000f, 0.38260000000000f};
|
||||
|
||||
/* The lower channel all-pass filter factors */
|
||||
const float WebRtcIsac_kLowerApFactorsFloat[2] = {
|
||||
0.15440000000000f, 0.74400000000000f};
|
||||
|
||||
/* The matrix for transforming the backward composite state to upper channel state */
|
||||
const float WebRtcIsac_kTransform1Float[8] = {
|
||||
-0.00158678506084f, 0.00127157815343f, -0.00104805672709f, 0.00084837248079f,
|
||||
0.00134467983258f, -0.00107756549387f, 0.00088814793277f, -0.00071893072525f};
|
||||
|
||||
/* The matrix for transforming the backward composite state to lower channel state */
|
||||
const float WebRtcIsac_kTransform2Float[8] = {
|
||||
-0.00170686041697f, 0.00136780109829f, -0.00112736532350f, 0.00091257055385f,
|
||||
0.00103094281812f, -0.00082615076557f, 0.00068092756088f, -0.00055119165484f};
|
@ -1,46 +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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* filterbank_tables.h
|
||||
*
|
||||
* Header file for variables that are defined in
|
||||
* filterbank_tables.c.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTERBANK_TABLES_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTERBANK_TABLES_H_
|
||||
|
||||
#include "structs.h"
|
||||
|
||||
/********************* Coefficient Tables ************************/
|
||||
/* The number of composite all-pass filter factors */
|
||||
#define NUMBEROFCOMPOSITEAPSECTIONS 4
|
||||
|
||||
/* The number of all-pass filter factors in an upper or lower channel*/
|
||||
#define NUMBEROFCHANNELAPSECTIONS 2
|
||||
|
||||
/* The composite all-pass filter factors */
|
||||
extern const float WebRtcIsac_kCompositeApFactorsFloat[4];
|
||||
|
||||
/* The upper channel all-pass filter factors */
|
||||
extern const float WebRtcIsac_kUpperApFactorsFloat[2];
|
||||
|
||||
/* The lower channel all-pass filter factors */
|
||||
extern const float WebRtcIsac_kLowerApFactorsFloat[2];
|
||||
|
||||
/* The matrix for transforming the backward composite state to upper channel state */
|
||||
extern const float WebRtcIsac_kTransform1Float[8];
|
||||
|
||||
/* The matrix for transforming the backward composite state to lower channel state */
|
||||
extern const float WebRtcIsac_kTransform2Float[8];
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FILTERBANK_TABLES_H_ */
|
@ -18,241 +18,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
#include "filterbank_tables.h"
|
||||
#include "codec.h"
|
||||
|
||||
/* This function performs all-pass filtering--a series of first order all-pass
|
||||
* sections are used to filter the input in a cascade manner.
|
||||
* The input is overwritten!!
|
||||
*/
|
||||
static void WebRtcIsac_AllPassFilter2Float(float *InOut, const float *APSectionFactors,
|
||||
int lengthInOut, int NumberOfSections,
|
||||
float *FilterState)
|
||||
{
|
||||
int n, j;
|
||||
float temp;
|
||||
for (j=0; j<NumberOfSections; j++){
|
||||
for (n=0;n<lengthInOut;n++){
|
||||
temp = FilterState[j] + APSectionFactors[j] * InOut[n];
|
||||
FilterState[j] = -APSectionFactors[j] * temp + InOut[n];
|
||||
InOut[n] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* HPstcoeff_in = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */
|
||||
static const float kHpStCoefInFloat[4] =
|
||||
{-1.94895953203325f, 0.94984516000000f, -0.05101826139794f, 0.05015484000000f};
|
||||
|
||||
/* Function WebRtcIsac_SplitAndFilter
|
||||
* This function creates low-pass and high-pass decimated versions of part of
|
||||
the input signal, and part of the signal in the input 'lookahead buffer'.
|
||||
|
||||
INPUTS:
|
||||
in: a length FRAMESAMPLES array of input samples
|
||||
prefiltdata: input data structure containing the filterbank states
|
||||
and lookahead samples from the previous encoding
|
||||
iteration.
|
||||
OUTPUTS:
|
||||
LP: a FRAMESAMPLES_HALF array of low-pass filtered samples that
|
||||
have been phase equalized. The first QLOOKAHEAD samples are
|
||||
based on the samples in the two prefiltdata->INLABUFx arrays
|
||||
each of length QLOOKAHEAD.
|
||||
The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based
|
||||
on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input
|
||||
array in[].
|
||||
HP: a FRAMESAMPLES_HALF array of high-pass filtered samples that
|
||||
have been phase equalized. The first QLOOKAHEAD samples are
|
||||
based on the samples in the two prefiltdata->INLABUFx arrays
|
||||
each of length QLOOKAHEAD.
|
||||
The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based
|
||||
on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input
|
||||
array in[].
|
||||
|
||||
LP_la: a FRAMESAMPLES_HALF array of low-pass filtered samples.
|
||||
These samples are not phase equalized. They are computed
|
||||
from the samples in the in[] array.
|
||||
HP_la: a FRAMESAMPLES_HALF array of high-pass filtered samples
|
||||
that are not phase equalized. They are computed from
|
||||
the in[] vector.
|
||||
prefiltdata: this input data structure's filterbank state and
|
||||
lookahead sample buffers are updated for the next
|
||||
encoding iteration.
|
||||
*/
|
||||
void WebRtcIsac_SplitAndFilterFloat(float *pin, float *LP, float *HP,
|
||||
double *LP_la, double *HP_la,
|
||||
PreFiltBankstr *prefiltdata)
|
||||
{
|
||||
int k,n;
|
||||
float CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS];
|
||||
float ForTransform_CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS];
|
||||
float ForTransform_CompositeAPFilterState2[NUMBEROFCOMPOSITEAPSECTIONS];
|
||||
float tempinoutvec[FRAMESAMPLES+MAX_AR_MODEL_ORDER];
|
||||
float tempin_ch1[FRAMESAMPLES+MAX_AR_MODEL_ORDER];
|
||||
float tempin_ch2[FRAMESAMPLES+MAX_AR_MODEL_ORDER];
|
||||
float in[FRAMESAMPLES];
|
||||
float ftmp;
|
||||
|
||||
|
||||
/* High pass filter */
|
||||
|
||||
for (k=0;k<FRAMESAMPLES;k++) {
|
||||
in[k] = pin[k] + kHpStCoefInFloat[2] * prefiltdata->HPstates_float[0] +
|
||||
kHpStCoefInFloat[3] * prefiltdata->HPstates_float[1];
|
||||
ftmp = pin[k] - kHpStCoefInFloat[0] * prefiltdata->HPstates_float[0] -
|
||||
kHpStCoefInFloat[1] * prefiltdata->HPstates_float[1];
|
||||
prefiltdata->HPstates_float[1] = prefiltdata->HPstates_float[0];
|
||||
prefiltdata->HPstates_float[0] = ftmp;
|
||||
}
|
||||
|
||||
/*
|
||||
% backwards all-pass filtering to obtain zero-phase
|
||||
[tmp1(N2+LA:-1:LA+1, 1), state1] = filter(Q.coef, Q.coef(end:-1:1), in(N:-2:2));
|
||||
tmp1(LA:-1:1) = filter(Q.coef, Q.coef(end:-1:1), Q.LookAheadBuf1, state1);
|
||||
Q.LookAheadBuf1 = in(N:-2:N-2*LA+2);
|
||||
*/
|
||||
/*Backwards all-pass filter the odd samples of the input (upper channel)
|
||||
to eventually obtain zero phase. The composite all-pass filter (comprised of both
|
||||
the upper and lower channel all-pass filsters in series) is used for the
|
||||
filtering. */
|
||||
|
||||
/* First Channel */
|
||||
|
||||
/*initial state of composite filter is zero */
|
||||
for (k=0;k<NUMBEROFCOMPOSITEAPSECTIONS;k++){
|
||||
CompositeAPFilterState[k] = 0.0;
|
||||
}
|
||||
/* put every other sample of input into a temporary vector in reverse (backward) order*/
|
||||
for (k=0;k<FRAMESAMPLES_HALF;k++) {
|
||||
tempinoutvec[k] = in[FRAMESAMPLES-1-2*k];
|
||||
}
|
||||
|
||||
/* now all-pass filter the backwards vector. Output values overwrite the input vector. */
|
||||
WebRtcIsac_AllPassFilter2Float(tempinoutvec, WebRtcIsac_kCompositeApFactorsFloat,
|
||||
FRAMESAMPLES_HALF, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
|
||||
|
||||
/* save the backwards filtered output for later forward filtering,
|
||||
but write it in forward order*/
|
||||
for (k=0;k<FRAMESAMPLES_HALF;k++) {
|
||||
tempin_ch1[FRAMESAMPLES_HALF+QLOOKAHEAD-1-k] = tempinoutvec[k];
|
||||
}
|
||||
|
||||
/* save the backwards filter state becaue it will be transformed
|
||||
later into a forward state */
|
||||
for (k=0; k<NUMBEROFCOMPOSITEAPSECTIONS; k++) {
|
||||
ForTransform_CompositeAPFilterState[k] = CompositeAPFilterState[k];
|
||||
}
|
||||
|
||||
/* now backwards filter the samples in the lookahead buffer. The samples were
|
||||
placed there in the encoding of the previous frame. The output samples
|
||||
overwrite the input samples */
|
||||
WebRtcIsac_AllPassFilter2Float(prefiltdata->INLABUF1_float,
|
||||
WebRtcIsac_kCompositeApFactorsFloat, QLOOKAHEAD,
|
||||
NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
|
||||
|
||||
/* save the output, but write it in forward order */
|
||||
/* write the lookahead samples for the next encoding iteration. Every other
|
||||
sample at the end of the input frame is written in reverse order for the
|
||||
lookahead length. Exported in the prefiltdata structure. */
|
||||
for (k=0;k<QLOOKAHEAD;k++) {
|
||||
tempin_ch1[QLOOKAHEAD-1-k]=prefiltdata->INLABUF1_float[k];
|
||||
prefiltdata->INLABUF1_float[k]=in[FRAMESAMPLES-1-2*k];
|
||||
}
|
||||
|
||||
/* Second Channel. This is exactly like the first channel, except that the
|
||||
even samples are now filtered instead (lower channel). */
|
||||
for (k=0;k<NUMBEROFCOMPOSITEAPSECTIONS;k++){
|
||||
CompositeAPFilterState[k] = 0.0;
|
||||
}
|
||||
|
||||
for (k=0;k<FRAMESAMPLES_HALF;k++) {
|
||||
tempinoutvec[k] = in[FRAMESAMPLES-2-2*k];
|
||||
}
|
||||
|
||||
WebRtcIsac_AllPassFilter2Float(tempinoutvec, WebRtcIsac_kCompositeApFactorsFloat,
|
||||
FRAMESAMPLES_HALF, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
|
||||
|
||||
for (k=0;k<FRAMESAMPLES_HALF;k++) {
|
||||
tempin_ch2[FRAMESAMPLES_HALF+QLOOKAHEAD-1-k] = tempinoutvec[k];
|
||||
}
|
||||
|
||||
for (k=0; k<NUMBEROFCOMPOSITEAPSECTIONS; k++) {
|
||||
ForTransform_CompositeAPFilterState2[k] = CompositeAPFilterState[k];
|
||||
}
|
||||
|
||||
|
||||
WebRtcIsac_AllPassFilter2Float(prefiltdata->INLABUF2_float,
|
||||
WebRtcIsac_kCompositeApFactorsFloat, QLOOKAHEAD,NUMBEROFCOMPOSITEAPSECTIONS,
|
||||
CompositeAPFilterState);
|
||||
|
||||
for (k=0;k<QLOOKAHEAD;k++) {
|
||||
tempin_ch2[QLOOKAHEAD-1-k]=prefiltdata->INLABUF2_float[k];
|
||||
prefiltdata->INLABUF2_float[k]=in[FRAMESAMPLES-2-2*k];
|
||||
}
|
||||
|
||||
/* Transform filter states from backward to forward */
|
||||
/*At this point, each of the states of the backwards composite filters for the
|
||||
two channels are transformed into forward filtering states for the corresponding
|
||||
forward channel filters. Each channel's forward filtering state from the previous
|
||||
encoding iteration is added to the transformed state to get a proper forward state */
|
||||
|
||||
/* So the existing NUMBEROFCOMPOSITEAPSECTIONS x 1 (4x1) state vector is multiplied by a
|
||||
NUMBEROFCHANNELAPSECTIONSxNUMBEROFCOMPOSITEAPSECTIONS (2x4) transform matrix to get the
|
||||
new state that is added to the previous 2x1 input state */
|
||||
|
||||
for (k=0;k<NUMBEROFCHANNELAPSECTIONS;k++){ /* k is row variable */
|
||||
for (n=0; n<NUMBEROFCOMPOSITEAPSECTIONS;n++){/* n is column variable */
|
||||
prefiltdata->INSTAT1_float[k] += ForTransform_CompositeAPFilterState[n]*
|
||||
WebRtcIsac_kTransform1Float[k*NUMBEROFCHANNELAPSECTIONS+n];
|
||||
prefiltdata->INSTAT2_float[k] += ForTransform_CompositeAPFilterState2[n]*
|
||||
WebRtcIsac_kTransform2Float[k*NUMBEROFCHANNELAPSECTIONS+n];
|
||||
}
|
||||
}
|
||||
|
||||
/*obtain polyphase components by forward all-pass filtering through each channel */
|
||||
/* the backward filtered samples are now forward filtered with the corresponding channel filters */
|
||||
/* The all pass filtering automatically updates the filter states which are exported in the
|
||||
prefiltdata structure */
|
||||
WebRtcIsac_AllPassFilter2Float(tempin_ch1,WebRtcIsac_kUpperApFactorsFloat,
|
||||
FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT1_float);
|
||||
WebRtcIsac_AllPassFilter2Float(tempin_ch2,WebRtcIsac_kLowerApFactorsFloat,
|
||||
FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT2_float);
|
||||
|
||||
/* Now Construct low-pass and high-pass signals as combinations of polyphase components */
|
||||
for (k=0; k<FRAMESAMPLES_HALF; k++) {
|
||||
LP[k] = 0.5f*(tempin_ch1[k] + tempin_ch2[k]);/* low pass signal*/
|
||||
HP[k] = 0.5f*(tempin_ch1[k] - tempin_ch2[k]);/* high pass signal*/
|
||||
}
|
||||
|
||||
/* Lookahead LP and HP signals */
|
||||
/* now create low pass and high pass signals of the input vector. However, no
|
||||
backwards filtering is performed, and hence no phase equalization is involved.
|
||||
Also, the input contains some samples that are lookahead samples. The high pass
|
||||
and low pass signals that are created are used outside this function for analysis
|
||||
(not encoding) purposes */
|
||||
|
||||
/* set up input */
|
||||
for (k=0; k<FRAMESAMPLES_HALF; k++) {
|
||||
tempin_ch1[k]=in[2*k+1];
|
||||
tempin_ch2[k]=in[2*k];
|
||||
}
|
||||
|
||||
/* the input filter states are passed in and updated by the all-pass filtering routine and
|
||||
exported in the prefiltdata structure*/
|
||||
WebRtcIsac_AllPassFilter2Float(tempin_ch1,WebRtcIsac_kUpperApFactorsFloat,
|
||||
FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTATLA1_float);
|
||||
WebRtcIsac_AllPassFilter2Float(tempin_ch2,WebRtcIsac_kLowerApFactorsFloat,
|
||||
FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTATLA2_float);
|
||||
|
||||
for (k=0; k<FRAMESAMPLES_HALF; k++) {
|
||||
LP_la[k] = (float)(0.5f*(tempin_ch1[k] + tempin_ch2[k])); /*low pass */
|
||||
HP_la[k] = (double)(0.5f*(tempin_ch1[k] - tempin_ch2[k])); /* high pass */
|
||||
}
|
||||
|
||||
|
||||
}/*end of WebRtcIsac_SplitAndFilter */
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/codec.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
|
||||
|
||||
/* Combining */
|
||||
|
||||
|
@ -10,12 +10,12 @@
|
||||
|
||||
/* encode.c - Encoding function for the iSAC coder */
|
||||
|
||||
#include "structs.h"
|
||||
#include "codec.h"
|
||||
#include "pitch_estimator.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/structs.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/codec.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
|
||||
|
||||
void WebRtcIsac_InitMasking(MaskFiltstr *maskdata) {
|
||||
|
||||
int k;
|
||||
@ -43,39 +43,6 @@ void WebRtcIsac_InitMasking(MaskFiltstr *maskdata) {
|
||||
return;
|
||||
}
|
||||
|
||||
void WebRtcIsac_InitPreFilterbank(PreFiltBankstr *prefiltdata)
|
||||
{
|
||||
int k;
|
||||
|
||||
for (k = 0; k < QLOOKAHEAD; k++) {
|
||||
prefiltdata->INLABUF1[k] = 0;
|
||||
prefiltdata->INLABUF2[k] = 0;
|
||||
|
||||
prefiltdata->INLABUF1_float[k] = 0;
|
||||
prefiltdata->INLABUF2_float[k] = 0;
|
||||
}
|
||||
for (k = 0; k < 2*(QORDER-1); k++) {
|
||||
prefiltdata->INSTAT1[k] = 0;
|
||||
prefiltdata->INSTAT2[k] = 0;
|
||||
prefiltdata->INSTATLA1[k] = 0;
|
||||
prefiltdata->INSTATLA2[k] = 0;
|
||||
|
||||
prefiltdata->INSTAT1_float[k] = 0;
|
||||
prefiltdata->INSTAT2_float[k] = 0;
|
||||
prefiltdata->INSTATLA1_float[k] = 0;
|
||||
prefiltdata->INSTATLA2_float[k] = 0;
|
||||
}
|
||||
|
||||
/* High pass filter states */
|
||||
prefiltdata->HPstates[0] = 0.0;
|
||||
prefiltdata->HPstates[1] = 0.0;
|
||||
|
||||
prefiltdata->HPstates_float[0] = 0.0f;
|
||||
prefiltdata->HPstates_float[1] = 0.0f;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void WebRtcIsac_InitPostFilterbank(PostFiltBankstr *postfiltdata)
|
||||
{
|
||||
int k;
|
||||
@ -103,69 +70,3 @@ void WebRtcIsac_InitPostFilterbank(PostFiltBankstr *postfiltdata)
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void WebRtcIsac_InitPitchFilter(PitchFiltstr *pitchfiltdata)
|
||||
{
|
||||
int k;
|
||||
|
||||
for (k = 0; k < PITCH_BUFFSIZE; k++) {
|
||||
pitchfiltdata->ubuf[k] = 0.0;
|
||||
}
|
||||
pitchfiltdata->ystate[0] = 0.0;
|
||||
for (k = 1; k < (PITCH_DAMPORDER); k++) {
|
||||
pitchfiltdata->ystate[k] = 0.0;
|
||||
}
|
||||
pitchfiltdata->oldlagp[0] = 50.0;
|
||||
pitchfiltdata->oldgainp[0] = 0.0;
|
||||
}
|
||||
|
||||
void WebRtcIsac_InitWeightingFilter(WeightFiltstr *wfdata)
|
||||
{
|
||||
int k;
|
||||
double t, dtmp, dtmp2, denum, denum2;
|
||||
|
||||
for (k=0;k<PITCH_WLPCBUFLEN;k++)
|
||||
wfdata->buffer[k]=0.0;
|
||||
|
||||
for (k=0;k<PITCH_WLPCORDER;k++) {
|
||||
wfdata->istate[k]=0.0;
|
||||
wfdata->weostate[k]=0.0;
|
||||
wfdata->whostate[k]=0.0;
|
||||
}
|
||||
|
||||
/* next part should be in Matlab, writing to a global table */
|
||||
t = 0.5;
|
||||
denum = 1.0 / ((double) PITCH_WLPCWINLEN);
|
||||
denum2 = denum * denum;
|
||||
for (k=0;k<PITCH_WLPCWINLEN;k++) {
|
||||
dtmp = PITCH_WLPCASYM * t * denum + (1-PITCH_WLPCASYM) * t * t * denum2;
|
||||
dtmp *= 3.14159265;
|
||||
dtmp2 = sin(dtmp);
|
||||
wfdata->window[k] = dtmp2 * dtmp2;
|
||||
t++;
|
||||
}
|
||||
}
|
||||
|
||||
/* clear all buffers */
|
||||
void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct *State)
|
||||
{
|
||||
int k;
|
||||
|
||||
for (k = 0; k < PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2; k++)
|
||||
State->dec_buffer[k] = 0.0;
|
||||
for (k = 0; k < 2*ALLPASSSECTIONS+1; k++)
|
||||
State->decimator_state[k] = 0.0;
|
||||
for (k = 0; k < 2; k++)
|
||||
State->hp_state[k] = 0.0;
|
||||
for (k = 0; k < QLOOKAHEAD; k++)
|
||||
State->whitened_buf[k] = 0.0;
|
||||
for (k = 0; k < QLOOKAHEAD; k++)
|
||||
State->inbuf[k] = 0.0;
|
||||
|
||||
WebRtcIsac_InitPitchFilter(&(State->PFstr_wght));
|
||||
|
||||
WebRtcIsac_InitPitchFilter(&(State->PFstr));
|
||||
|
||||
WebRtcIsac_InitWeightingFilter(&(State->Wghtstr));
|
||||
}
|
||||
|
@ -15,22 +15,24 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/include/isac.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/include/isac.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/source/codec.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/source/crc.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/source/structs.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/codec.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/crc.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/os_specific_inline.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/structs.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
|
||||
#include "rtc_base/system/arch.h"
|
||||
|
||||
#define BIT_MASK_DEC_INIT 0x0001
|
||||
#define BIT_MASK_ENC_INIT 0x0002
|
||||
@ -204,62 +206,6 @@ static void GetSendBandwidthInfo(ISACMainStruct* instISAC,
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcIsac_AssignSize(...)
|
||||
*
|
||||
* This function returns the size of the ISAC instance, so that the instance
|
||||
* can be created out side iSAC.
|
||||
*
|
||||
* Output:
|
||||
* - sizeinbytes : number of bytes needed to allocate for the
|
||||
* instance.
|
||||
*
|
||||
* Return value : 0 - Ok
|
||||
* -1 - Error
|
||||
*/
|
||||
int16_t WebRtcIsac_AssignSize(int* sizeInBytes) {
|
||||
*sizeInBytes = sizeof(ISACMainStruct) * 2 / sizeof(int16_t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcIsac_Assign(...)
|
||||
*
|
||||
* This function assigns the memory already created to the ISAC instance.
|
||||
*
|
||||
* Input:
|
||||
* - ISAC_main_inst : address of the pointer to the coder instance.
|
||||
* - instISAC_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* instISAC_Addr) {
|
||||
if (instISAC_Addr != NULL) {
|
||||
ISACMainStruct* instISAC = (ISACMainStruct*)instISAC_Addr;
|
||||
instISAC->errorCode = 0;
|
||||
instISAC->initFlag = 0;
|
||||
|
||||
/* Assign the address. */
|
||||
*ISAC_main_inst = (ISACStruct*)instISAC_Addr;
|
||||
|
||||
/* Default is wideband. */
|
||||
instISAC->encoderSamplingRateKHz = kIsacWideband;
|
||||
instISAC->decoderSamplingRateKHz = kIsacWideband;
|
||||
instISAC->bandwidthKHz = isac8kHz;
|
||||
instISAC->in_sample_rate_hz = 16000;
|
||||
|
||||
WebRtcIsac_InitTransform(&instISAC->transform_tables);
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* WebRtcIsac_Create(...)
|
||||
*
|
||||
@ -1253,10 +1199,23 @@ static int Decode(ISACStruct* ISAC_main_inst,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (numDecodedBytesUB < 0) {
|
||||
instISAC->errorCode = numDecodedBytesUB;
|
||||
return -1;
|
||||
}
|
||||
if (numDecodedBytesLB + numDecodedBytesUB > lenEncodedBytes) {
|
||||
// We have supposedly decoded more bytes than we were given. Likely
|
||||
// caused by bad input data.
|
||||
instISAC->errorCode = ISAC_LENGTH_MISMATCH;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* It might be less due to garbage. */
|
||||
if ((numDecodedBytesUB != lenNextStream) &&
|
||||
(numDecodedBytesUB != (lenNextStream -
|
||||
encoded[numDecodedBytesLB + 1 + numDecodedBytesUB]))) {
|
||||
(numDecodedBytesLB + 1 + numDecodedBytesUB >= lenEncodedBytes ||
|
||||
numDecodedBytesUB !=
|
||||
(lenNextStream -
|
||||
encoded[numDecodedBytesLB + 1 + numDecodedBytesUB]))) {
|
||||
instISAC->errorCode = ISAC_LENGTH_MISMATCH;
|
||||
return -1;
|
||||
}
|
||||
@ -1539,8 +1498,8 @@ int16_t WebRtcIsac_Control(ISACStruct* ISAC_main_inst,
|
||||
void WebRtcIsac_SetInitialBweBottleneck(ISACStruct* ISAC_main_inst,
|
||||
int bottleneck_bits_per_second) {
|
||||
ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst;
|
||||
assert(bottleneck_bits_per_second >= 10000 &&
|
||||
bottleneck_bits_per_second <= 32000);
|
||||
RTC_DCHECK_GE(bottleneck_bits_per_second, 10000);
|
||||
RTC_DCHECK_LE(bottleneck_bits_per_second, 32000);
|
||||
instISAC->bwestimator_obj.send_bw_avg = (float)bottleneck_bits_per_second;
|
||||
}
|
||||
|
||||
@ -1760,7 +1719,7 @@ int16_t WebRtcIsac_ReadBwIndex(const uint8_t* encoded,
|
||||
* - frameLength : Length of frame in packet (in samples)
|
||||
*
|
||||
*/
|
||||
int16_t WebRtcIsac_ReadFrameLen(ISACStruct* ISAC_main_inst,
|
||||
int16_t WebRtcIsac_ReadFrameLen(const ISACStruct* ISAC_main_inst,
|
||||
const uint8_t* encoded,
|
||||
int16_t* frameLength) {
|
||||
Bitstr streamdata;
|
||||
@ -2338,26 +2297,11 @@ uint16_t WebRtcIsac_DecSampRate(ISACStruct* ISAC_main_inst) {
|
||||
return instISAC->decoderSamplingRateKHz == kIsacWideband ? 16000 : 32000;
|
||||
}
|
||||
|
||||
void WebRtcIsac_GetBandwidthInfo(ISACStruct* inst,
|
||||
IsacBandwidthInfo* bwinfo) {
|
||||
ISACMainStruct* instISAC = (ISACMainStruct*)inst;
|
||||
assert(instISAC->initFlag & BIT_MASK_DEC_INIT);
|
||||
WebRtcIsacBw_GetBandwidthInfo(&instISAC->bwestimator_obj,
|
||||
instISAC->decoderSamplingRateKHz, bwinfo);
|
||||
}
|
||||
|
||||
void WebRtcIsac_SetBandwidthInfo(ISACStruct* inst,
|
||||
const IsacBandwidthInfo* bwinfo) {
|
||||
ISACMainStruct* instISAC = (ISACMainStruct*)inst;
|
||||
assert(instISAC->initFlag & BIT_MASK_ENC_INIT);
|
||||
WebRtcIsacBw_SetBandwidthInfo(&instISAC->bwestimator_obj, bwinfo);
|
||||
}
|
||||
|
||||
void WebRtcIsac_SetEncSampRateInDecoder(ISACStruct* inst,
|
||||
int sample_rate_hz) {
|
||||
ISACMainStruct* instISAC = (ISACMainStruct*)inst;
|
||||
assert(instISAC->initFlag & BIT_MASK_DEC_INIT);
|
||||
assert(!(instISAC->initFlag & BIT_MASK_ENC_INIT));
|
||||
assert(sample_rate_hz == 16000 || sample_rate_hz == 32000);
|
||||
RTC_DCHECK_NE(0, instISAC->initFlag & BIT_MASK_DEC_INIT);
|
||||
RTC_DCHECK(!(instISAC->initFlag & BIT_MASK_ENC_INIT));
|
||||
RTC_DCHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000);
|
||||
instISAC->encoderSamplingRateKHz = sample_rate_hz / 1000;
|
||||
}
|
||||
|
@ -8,10 +8,10 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_
|
||||
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/include/isac.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/include/isac.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -64,10 +64,6 @@ struct IsacFloat {
|
||||
static inline int16_t Free(instance_type* inst) {
|
||||
return WebRtcIsac_Free(inst);
|
||||
}
|
||||
static inline void GetBandwidthInfo(instance_type* inst,
|
||||
IsacBandwidthInfo* bwinfo) {
|
||||
WebRtcIsac_GetBandwidthInfo(inst, bwinfo);
|
||||
}
|
||||
static inline int16_t GetErrorCode(instance_type* inst) {
|
||||
return WebRtcIsac_GetErrorCode(inst);
|
||||
}
|
||||
@ -75,10 +71,6 @@ struct IsacFloat {
|
||||
static inline int16_t GetNewFrameLen(instance_type* inst) {
|
||||
return WebRtcIsac_GetNewFrameLen(inst);
|
||||
}
|
||||
static inline void SetBandwidthInfo(instance_type* inst,
|
||||
const IsacBandwidthInfo* bwinfo) {
|
||||
WebRtcIsac_SetBandwidthInfo(inst, bwinfo);
|
||||
}
|
||||
static inline int16_t SetDecSampRate(instance_type* inst,
|
||||
uint16_t sample_rate_hz) {
|
||||
return WebRtcIsac_SetDecSampRate(inst, sample_rate_hz);
|
||||
@ -95,15 +87,6 @@ struct IsacFloat {
|
||||
int bottleneck_bits_per_second) {
|
||||
WebRtcIsac_SetInitialBweBottleneck(inst, bottleneck_bits_per_second);
|
||||
}
|
||||
static inline int16_t UpdateBwEstimate(instance_type* inst,
|
||||
const uint8_t* encoded,
|
||||
size_t packet_size,
|
||||
uint16_t rtp_seq_number,
|
||||
uint32_t send_ts,
|
||||
uint32_t arr_ts) {
|
||||
return WebRtcIsac_UpdateBwEstimate(inst, encoded, packet_size,
|
||||
rtp_seq_number, send_ts, arr_ts);
|
||||
}
|
||||
static inline int16_t SetMaxPayloadSize(instance_type* inst,
|
||||
int16_t max_payload_size_bytes) {
|
||||
return WebRtcIsac_SetMaxPayloadSize(inst, max_payload_size_bytes);
|
||||
@ -114,4 +97,4 @@ struct IsacFloat {
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_FLOAT_TYPE_H_
|
||||
|
409
webrtc/modules/audio_coding/codecs/isac/main/source/isac_vad.c
Normal file
409
webrtc/modules/audio_coding/codecs/isac/main/source/isac_vad.c
Normal file
@ -0,0 +1,409 @@
|
||||
/*
|
||||
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
void WebRtcIsac_InitPitchFilter(PitchFiltstr* pitchfiltdata) {
|
||||
int k;
|
||||
|
||||
for (k = 0; k < PITCH_BUFFSIZE; k++) {
|
||||
pitchfiltdata->ubuf[k] = 0.0;
|
||||
}
|
||||
pitchfiltdata->ystate[0] = 0.0;
|
||||
for (k = 1; k < (PITCH_DAMPORDER); k++) {
|
||||
pitchfiltdata->ystate[k] = 0.0;
|
||||
}
|
||||
pitchfiltdata->oldlagp[0] = 50.0;
|
||||
pitchfiltdata->oldgainp[0] = 0.0;
|
||||
}
|
||||
|
||||
static void WebRtcIsac_InitWeightingFilter(WeightFiltstr* wfdata) {
|
||||
int k;
|
||||
double t, dtmp, dtmp2, denum, denum2;
|
||||
|
||||
for (k = 0; k < PITCH_WLPCBUFLEN; k++)
|
||||
wfdata->buffer[k] = 0.0;
|
||||
|
||||
for (k = 0; k < PITCH_WLPCORDER; k++) {
|
||||
wfdata->istate[k] = 0.0;
|
||||
wfdata->weostate[k] = 0.0;
|
||||
wfdata->whostate[k] = 0.0;
|
||||
}
|
||||
|
||||
/* next part should be in Matlab, writing to a global table */
|
||||
t = 0.5;
|
||||
denum = 1.0 / ((double)PITCH_WLPCWINLEN);
|
||||
denum2 = denum * denum;
|
||||
for (k = 0; k < PITCH_WLPCWINLEN; k++) {
|
||||
dtmp = PITCH_WLPCASYM * t * denum + (1 - PITCH_WLPCASYM) * t * t * denum2;
|
||||
dtmp *= 3.14159265;
|
||||
dtmp2 = sin(dtmp);
|
||||
wfdata->window[k] = dtmp2 * dtmp2;
|
||||
t++;
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct* State) {
|
||||
int k;
|
||||
|
||||
for (k = 0; k < PITCH_CORR_LEN2 + PITCH_CORR_STEP2 + PITCH_MAX_LAG / 2 -
|
||||
PITCH_FRAME_LEN / 2 + 2;
|
||||
k++)
|
||||
State->dec_buffer[k] = 0.0;
|
||||
for (k = 0; k < 2 * ALLPASSSECTIONS + 1; k++)
|
||||
State->decimator_state[k] = 0.0;
|
||||
for (k = 0; k < 2; k++)
|
||||
State->hp_state[k] = 0.0;
|
||||
for (k = 0; k < QLOOKAHEAD; k++)
|
||||
State->whitened_buf[k] = 0.0;
|
||||
for (k = 0; k < QLOOKAHEAD; k++)
|
||||
State->inbuf[k] = 0.0;
|
||||
|
||||
WebRtcIsac_InitPitchFilter(&(State->PFstr_wght));
|
||||
|
||||
WebRtcIsac_InitPitchFilter(&(State->PFstr));
|
||||
|
||||
WebRtcIsac_InitWeightingFilter(&(State->Wghtstr));
|
||||
}
|
||||
|
||||
void WebRtcIsac_InitPreFilterbank(PreFiltBankstr* prefiltdata) {
|
||||
int k;
|
||||
|
||||
for (k = 0; k < QLOOKAHEAD; k++) {
|
||||
prefiltdata->INLABUF1[k] = 0;
|
||||
prefiltdata->INLABUF2[k] = 0;
|
||||
|
||||
prefiltdata->INLABUF1_float[k] = 0;
|
||||
prefiltdata->INLABUF2_float[k] = 0;
|
||||
}
|
||||
for (k = 0; k < 2 * (QORDER - 1); k++) {
|
||||
prefiltdata->INSTAT1[k] = 0;
|
||||
prefiltdata->INSTAT2[k] = 0;
|
||||
prefiltdata->INSTATLA1[k] = 0;
|
||||
prefiltdata->INSTATLA2[k] = 0;
|
||||
|
||||
prefiltdata->INSTAT1_float[k] = 0;
|
||||
prefiltdata->INSTAT2_float[k] = 0;
|
||||
prefiltdata->INSTATLA1_float[k] = 0;
|
||||
prefiltdata->INSTATLA2_float[k] = 0;
|
||||
}
|
||||
|
||||
/* High pass filter states */
|
||||
prefiltdata->HPstates[0] = 0.0;
|
||||
prefiltdata->HPstates[1] = 0.0;
|
||||
|
||||
prefiltdata->HPstates_float[0] = 0.0f;
|
||||
prefiltdata->HPstates_float[1] = 0.0f;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
double WebRtcIsac_LevDurb(double* a, double* k, double* r, size_t order) {
|
||||
const double LEVINSON_EPS = 1.0e-10;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* The upper channel all-pass filter factors */
|
||||
const float WebRtcIsac_kUpperApFactorsFloat[2] = {0.03470000000000f,
|
||||
0.38260000000000f};
|
||||
|
||||
/* The lower channel all-pass filter factors */
|
||||
const float WebRtcIsac_kLowerApFactorsFloat[2] = {0.15440000000000f,
|
||||
0.74400000000000f};
|
||||
|
||||
/* This function performs all-pass filtering--a series of first order all-pass
|
||||
* sections are used to filter the input in a cascade manner.
|
||||
* The input is overwritten!!
|
||||
*/
|
||||
void WebRtcIsac_AllPassFilter2Float(float* InOut,
|
||||
const float* APSectionFactors,
|
||||
int lengthInOut,
|
||||
int NumberOfSections,
|
||||
float* FilterState) {
|
||||
int n, j;
|
||||
float temp;
|
||||
for (j = 0; j < NumberOfSections; j++) {
|
||||
for (n = 0; n < lengthInOut; n++) {
|
||||
temp = FilterState[j] + APSectionFactors[j] * InOut[n];
|
||||
FilterState[j] = -APSectionFactors[j] * temp + InOut[n];
|
||||
InOut[n] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The number of composite all-pass filter factors */
|
||||
#define NUMBEROFCOMPOSITEAPSECTIONS 4
|
||||
|
||||
/* Function WebRtcIsac_SplitAndFilter
|
||||
* This function creates low-pass and high-pass decimated versions of part of
|
||||
the input signal, and part of the signal in the input 'lookahead buffer'.
|
||||
|
||||
INPUTS:
|
||||
in: a length FRAMESAMPLES array of input samples
|
||||
prefiltdata: input data structure containing the filterbank states
|
||||
and lookahead samples from the previous encoding
|
||||
iteration.
|
||||
OUTPUTS:
|
||||
LP: a FRAMESAMPLES_HALF array of low-pass filtered samples that
|
||||
have been phase equalized. The first QLOOKAHEAD samples are
|
||||
based on the samples in the two prefiltdata->INLABUFx arrays
|
||||
each of length QLOOKAHEAD.
|
||||
The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based
|
||||
on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input
|
||||
array in[].
|
||||
HP: a FRAMESAMPLES_HALF array of high-pass filtered samples that
|
||||
have been phase equalized. The first QLOOKAHEAD samples are
|
||||
based on the samples in the two prefiltdata->INLABUFx arrays
|
||||
each of length QLOOKAHEAD.
|
||||
The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based
|
||||
on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input
|
||||
array in[].
|
||||
|
||||
LP_la: a FRAMESAMPLES_HALF array of low-pass filtered samples.
|
||||
These samples are not phase equalized. They are computed
|
||||
from the samples in the in[] array.
|
||||
HP_la: a FRAMESAMPLES_HALF array of high-pass filtered samples
|
||||
that are not phase equalized. They are computed from
|
||||
the in[] vector.
|
||||
prefiltdata: this input data structure's filterbank state and
|
||||
lookahead sample buffers are updated for the next
|
||||
encoding iteration.
|
||||
*/
|
||||
void WebRtcIsac_SplitAndFilterFloat(float* pin,
|
||||
float* LP,
|
||||
float* HP,
|
||||
double* LP_la,
|
||||
double* HP_la,
|
||||
PreFiltBankstr* prefiltdata) {
|
||||
int k, n;
|
||||
float CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS];
|
||||
float ForTransform_CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS];
|
||||
float ForTransform_CompositeAPFilterState2[NUMBEROFCOMPOSITEAPSECTIONS];
|
||||
float tempinoutvec[FRAMESAMPLES + MAX_AR_MODEL_ORDER];
|
||||
float tempin_ch1[FRAMESAMPLES + MAX_AR_MODEL_ORDER];
|
||||
float tempin_ch2[FRAMESAMPLES + MAX_AR_MODEL_ORDER];
|
||||
float in[FRAMESAMPLES];
|
||||
float ftmp;
|
||||
|
||||
/* HPstcoeff_in = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */
|
||||
static const float kHpStCoefInFloat[4] = {
|
||||
-1.94895953203325f, 0.94984516000000f, -0.05101826139794f,
|
||||
0.05015484000000f};
|
||||
|
||||
/* The composite all-pass filter factors */
|
||||
static const float WebRtcIsac_kCompositeApFactorsFloat[4] = {
|
||||
0.03470000000000f, 0.15440000000000f, 0.38260000000000f,
|
||||
0.74400000000000f};
|
||||
|
||||
// The matrix for transforming the backward composite state to upper channel
|
||||
// state.
|
||||
static const float WebRtcIsac_kTransform1Float[8] = {
|
||||
-0.00158678506084f, 0.00127157815343f, -0.00104805672709f,
|
||||
0.00084837248079f, 0.00134467983258f, -0.00107756549387f,
|
||||
0.00088814793277f, -0.00071893072525f};
|
||||
|
||||
// The matrix for transforming the backward composite state to lower channel
|
||||
// state.
|
||||
static const float WebRtcIsac_kTransform2Float[8] = {
|
||||
-0.00170686041697f, 0.00136780109829f, -0.00112736532350f,
|
||||
0.00091257055385f, 0.00103094281812f, -0.00082615076557f,
|
||||
0.00068092756088f, -0.00055119165484f};
|
||||
|
||||
/* High pass filter */
|
||||
|
||||
for (k = 0; k < FRAMESAMPLES; k++) {
|
||||
in[k] = pin[k] + kHpStCoefInFloat[2] * prefiltdata->HPstates_float[0] +
|
||||
kHpStCoefInFloat[3] * prefiltdata->HPstates_float[1];
|
||||
ftmp = pin[k] - kHpStCoefInFloat[0] * prefiltdata->HPstates_float[0] -
|
||||
kHpStCoefInFloat[1] * prefiltdata->HPstates_float[1];
|
||||
prefiltdata->HPstates_float[1] = prefiltdata->HPstates_float[0];
|
||||
prefiltdata->HPstates_float[0] = ftmp;
|
||||
}
|
||||
|
||||
/* First Channel */
|
||||
|
||||
/*initial state of composite filter is zero */
|
||||
for (k = 0; k < NUMBEROFCOMPOSITEAPSECTIONS; k++) {
|
||||
CompositeAPFilterState[k] = 0.0;
|
||||
}
|
||||
/* put every other sample of input into a temporary vector in reverse
|
||||
* (backward) order*/
|
||||
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
|
||||
tempinoutvec[k] = in[FRAMESAMPLES - 1 - 2 * k];
|
||||
}
|
||||
|
||||
/* now all-pass filter the backwards vector. Output values overwrite the
|
||||
* input vector. */
|
||||
WebRtcIsac_AllPassFilter2Float(
|
||||
tempinoutvec, WebRtcIsac_kCompositeApFactorsFloat, FRAMESAMPLES_HALF,
|
||||
NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
|
||||
|
||||
/* save the backwards filtered output for later forward filtering,
|
||||
but write it in forward order*/
|
||||
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
|
||||
tempin_ch1[FRAMESAMPLES_HALF + QLOOKAHEAD - 1 - k] = tempinoutvec[k];
|
||||
}
|
||||
|
||||
/* save the backwards filter state becaue it will be transformed
|
||||
later into a forward state */
|
||||
for (k = 0; k < NUMBEROFCOMPOSITEAPSECTIONS; k++) {
|
||||
ForTransform_CompositeAPFilterState[k] = CompositeAPFilterState[k];
|
||||
}
|
||||
|
||||
/* now backwards filter the samples in the lookahead buffer. The samples were
|
||||
placed there in the encoding of the previous frame. The output samples
|
||||
overwrite the input samples */
|
||||
WebRtcIsac_AllPassFilter2Float(
|
||||
prefiltdata->INLABUF1_float, WebRtcIsac_kCompositeApFactorsFloat,
|
||||
QLOOKAHEAD, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
|
||||
|
||||
/* save the output, but write it in forward order */
|
||||
/* write the lookahead samples for the next encoding iteration. Every other
|
||||
sample at the end of the input frame is written in reverse order for the
|
||||
lookahead length. Exported in the prefiltdata structure. */
|
||||
for (k = 0; k < QLOOKAHEAD; k++) {
|
||||
tempin_ch1[QLOOKAHEAD - 1 - k] = prefiltdata->INLABUF1_float[k];
|
||||
prefiltdata->INLABUF1_float[k] = in[FRAMESAMPLES - 1 - 2 * k];
|
||||
}
|
||||
|
||||
/* Second Channel. This is exactly like the first channel, except that the
|
||||
even samples are now filtered instead (lower channel). */
|
||||
for (k = 0; k < NUMBEROFCOMPOSITEAPSECTIONS; k++) {
|
||||
CompositeAPFilterState[k] = 0.0;
|
||||
}
|
||||
|
||||
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
|
||||
tempinoutvec[k] = in[FRAMESAMPLES - 2 - 2 * k];
|
||||
}
|
||||
|
||||
WebRtcIsac_AllPassFilter2Float(
|
||||
tempinoutvec, WebRtcIsac_kCompositeApFactorsFloat, FRAMESAMPLES_HALF,
|
||||
NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
|
||||
|
||||
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
|
||||
tempin_ch2[FRAMESAMPLES_HALF + QLOOKAHEAD - 1 - k] = tempinoutvec[k];
|
||||
}
|
||||
|
||||
for (k = 0; k < NUMBEROFCOMPOSITEAPSECTIONS; k++) {
|
||||
ForTransform_CompositeAPFilterState2[k] = CompositeAPFilterState[k];
|
||||
}
|
||||
|
||||
WebRtcIsac_AllPassFilter2Float(
|
||||
prefiltdata->INLABUF2_float, WebRtcIsac_kCompositeApFactorsFloat,
|
||||
QLOOKAHEAD, NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState);
|
||||
|
||||
for (k = 0; k < QLOOKAHEAD; k++) {
|
||||
tempin_ch2[QLOOKAHEAD - 1 - k] = prefiltdata->INLABUF2_float[k];
|
||||
prefiltdata->INLABUF2_float[k] = in[FRAMESAMPLES - 2 - 2 * k];
|
||||
}
|
||||
|
||||
/* Transform filter states from backward to forward */
|
||||
/*At this point, each of the states of the backwards composite filters for the
|
||||
two channels are transformed into forward filtering states for the
|
||||
corresponding forward channel filters. Each channel's forward filtering
|
||||
state from the previous
|
||||
encoding iteration is added to the transformed state to get a proper forward
|
||||
state */
|
||||
|
||||
/* So the existing NUMBEROFCOMPOSITEAPSECTIONS x 1 (4x1) state vector is
|
||||
multiplied by a NUMBEROFCHANNELAPSECTIONSxNUMBEROFCOMPOSITEAPSECTIONS (2x4)
|
||||
transform matrix to get the new state that is added to the previous 2x1
|
||||
input state */
|
||||
|
||||
for (k = 0; k < NUMBEROFCHANNELAPSECTIONS; k++) { /* k is row variable */
|
||||
for (n = 0; n < NUMBEROFCOMPOSITEAPSECTIONS;
|
||||
n++) { /* n is column variable */
|
||||
prefiltdata->INSTAT1_float[k] +=
|
||||
ForTransform_CompositeAPFilterState[n] *
|
||||
WebRtcIsac_kTransform1Float[k * NUMBEROFCHANNELAPSECTIONS + n];
|
||||
prefiltdata->INSTAT2_float[k] +=
|
||||
ForTransform_CompositeAPFilterState2[n] *
|
||||
WebRtcIsac_kTransform2Float[k * NUMBEROFCHANNELAPSECTIONS + n];
|
||||
}
|
||||
}
|
||||
|
||||
/*obtain polyphase components by forward all-pass filtering through each
|
||||
* channel */
|
||||
/* the backward filtered samples are now forward filtered with the
|
||||
* corresponding channel filters */
|
||||
/* The all pass filtering automatically updates the filter states which are
|
||||
exported in the prefiltdata structure */
|
||||
WebRtcIsac_AllPassFilter2Float(tempin_ch1, WebRtcIsac_kUpperApFactorsFloat,
|
||||
FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,
|
||||
prefiltdata->INSTAT1_float);
|
||||
WebRtcIsac_AllPassFilter2Float(tempin_ch2, WebRtcIsac_kLowerApFactorsFloat,
|
||||
FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,
|
||||
prefiltdata->INSTAT2_float);
|
||||
|
||||
/* Now Construct low-pass and high-pass signals as combinations of polyphase
|
||||
* components */
|
||||
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
|
||||
LP[k] = 0.5f * (tempin_ch1[k] + tempin_ch2[k]); /* low pass signal*/
|
||||
HP[k] = 0.5f * (tempin_ch1[k] - tempin_ch2[k]); /* high pass signal*/
|
||||
}
|
||||
|
||||
/* Lookahead LP and HP signals */
|
||||
/* now create low pass and high pass signals of the input vector. However, no
|
||||
backwards filtering is performed, and hence no phase equalization is
|
||||
involved. Also, the input contains some samples that are lookahead samples.
|
||||
The high pass and low pass signals that are created are used outside this
|
||||
function for analysis (not encoding) purposes */
|
||||
|
||||
/* set up input */
|
||||
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
|
||||
tempin_ch1[k] = in[2 * k + 1];
|
||||
tempin_ch2[k] = in[2 * k];
|
||||
}
|
||||
|
||||
/* the input filter states are passed in and updated by the all-pass filtering
|
||||
routine and exported in the prefiltdata structure*/
|
||||
WebRtcIsac_AllPassFilter2Float(tempin_ch1, WebRtcIsac_kUpperApFactorsFloat,
|
||||
FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,
|
||||
prefiltdata->INSTATLA1_float);
|
||||
WebRtcIsac_AllPassFilter2Float(tempin_ch2, WebRtcIsac_kLowerApFactorsFloat,
|
||||
FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,
|
||||
prefiltdata->INSTATLA2_float);
|
||||
|
||||
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
|
||||
LP_la[k] = (float)(0.5f * (tempin_ch1[k] + tempin_ch2[k])); /*low pass */
|
||||
HP_la[k] = (double)(0.5f * (tempin_ch1[k] - tempin_ch2[k])); /* high pass */
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_VAD_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_VAD_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/structs.h"
|
||||
|
||||
void WebRtcIsac_InitPitchFilter(PitchFiltstr* pitchfiltdata);
|
||||
void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct* state);
|
||||
void WebRtcIsac_InitPreFilterbank(PreFiltBankstr* prefiltdata);
|
||||
|
||||
double WebRtcIsac_LevDurb(double* a, double* k, double* r, size_t order);
|
||||
|
||||
/* The number of all-pass filter factors in an upper or lower channel*/
|
||||
#define NUMBEROFCHANNELAPSECTIONS 2
|
||||
|
||||
/* The upper channel all-pass filter factors */
|
||||
extern const float WebRtcIsac_kUpperApFactorsFloat[2];
|
||||
|
||||
/* The lower channel all-pass filter factors */
|
||||
extern const float WebRtcIsac_kLowerApFactorsFloat[2];
|
||||
|
||||
void WebRtcIsac_AllPassFilter2Float(float* InOut,
|
||||
const float* APSectionFactors,
|
||||
int lengthInOut,
|
||||
int NumberOfSections,
|
||||
float* FilterState);
|
||||
void WebRtcIsac_SplitAndFilterFloat(float* in,
|
||||
float* LP,
|
||||
float* HP,
|
||||
double* LP_la,
|
||||
double* HP_la,
|
||||
PreFiltBankstr* prefiltdata);
|
||||
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ISAC_VAD_H_
|
@ -14,8 +14,6 @@
|
||||
* contains the normalized lattice filter routines (MA and AR) for iSAC codec
|
||||
*
|
||||
*/
|
||||
#include "settings.h"
|
||||
#include "codec.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
@ -24,6 +22,9 @@
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/codec.h"
|
||||
|
||||
/* filter the signal using normalized lattice filter */
|
||||
/* MA filter */
|
||||
void WebRtcIsac_NormLatticeFilterMa(int orderCoef,
|
||||
|
@ -8,16 +8,15 @@
|
||||
* 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
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_analysis.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/codec.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/filter_functions.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/isac_vad.h"
|
||||
|
||||
/* window */
|
||||
/* Matlab generation code:
|
||||
@ -75,45 +74,10 @@ static const double kLpcCorrWindow[WINLEN] = {
|
||||
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)
|
||||
{
|
||||
static void WebRtcIsac_GetVars(const double* input,
|
||||
const int16_t* pitchGains_Q12,
|
||||
double* oldEnergy,
|
||||
double* varscale) {
|
||||
double nrg[4], chng, pg;
|
||||
int k;
|
||||
|
||||
@ -162,12 +126,9 @@ void WebRtcIsac_GetVars(const double *input, const int16_t *pitchGains_Q12,
|
||||
*oldEnergy = nrg[3];
|
||||
}
|
||||
|
||||
void
|
||||
WebRtcIsac_GetVarsUB(
|
||||
const double* input,
|
||||
double* oldEnergy,
|
||||
double* varscale)
|
||||
{
|
||||
static void WebRtcIsac_GetVarsUB(const double* input,
|
||||
double* oldEnergy,
|
||||
double* varscale) {
|
||||
double nrg[4], chng;
|
||||
int k;
|
||||
|
||||
|
@ -15,36 +15,32 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYSIS_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYSIS_H_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYSIS_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYSIS_H_
|
||||
|
||||
#include "settings.h"
|
||||
#include "structs.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/structs.h"
|
||||
|
||||
double WebRtcIsac_LevDurb(double *a, double *k, double *r, size_t order);
|
||||
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_GetVars(const double *input, const int16_t *pitchGains_Q12,
|
||||
double *oldEnergy, double *varscale);
|
||||
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_GetLpcCoefLb(double *inLo, double *inHi, MaskFiltstr *maskdata,
|
||||
double signal_noise_ratio, const int16_t *pitchGains_Q12,
|
||||
double *lo_coeff, double *hi_coeff);
|
||||
void WebRtcIsac_GetLpcCoefUb(double* inSignal,
|
||||
MaskFiltstr* maskdata,
|
||||
double* lpCoeff,
|
||||
double corr[][UB_LPC_ORDER + 1],
|
||||
double* varscale,
|
||||
int16_t bandwidth);
|
||||
|
||||
|
||||
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_ */
|
||||
#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYIS_H_ */
|
||||
|
@ -16,9 +16,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lpc_gain_swb_tables.h"
|
||||
#include "settings.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
|
||||
const double WebRtcIsac_kQSizeLpcGain = 0.100000;
|
||||
|
||||
|
@ -16,11 +16,12 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#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_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_
|
||||
|
||||
#include "settings.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
|
||||
extern const double WebRtcIsac_kQSizeLpcGain;
|
||||
|
||||
@ -46,4 +47,4 @@ 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_
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_
|
||||
|
@ -16,9 +16,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lpc_shape_swb12_tables.h"
|
||||
#include "settings.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
|
||||
/*
|
||||
* Mean value of LAR
|
||||
|
@ -16,32 +16,33 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#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_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_
|
||||
|
||||
#include "settings.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.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_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_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 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 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_kLpcShapeEntropySearchUb12[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec0Ub12[14];
|
||||
|
||||
@ -59,7 +60,7 @@ 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];
|
||||
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_
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_
|
||||
|
@ -16,9 +16,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lpc_shape_swb16_tables.h"
|
||||
#include "settings.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
|
||||
/*
|
||||
* Mean value of LAR
|
||||
|
@ -16,18 +16,20 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#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_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_
|
||||
|
||||
#include "settings.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
|
||||
extern const double WebRtcIsac_kMeanLarUb16[UB_LPC_ORDER];
|
||||
|
||||
extern const double WebRtcIsac_kIintraVecDecorrMatUb16[UB_LPC_ORDER][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 double WebRtcIsac_kInterVecDecorrMatUb16[UB16_LPC_VEC_PER_FRAME]
|
||||
[UB16_LPC_VEC_PER_FRAME];
|
||||
|
||||
extern const uint16_t WebRtcIsac_kLpcShapeCdfVec01Ub16[14];
|
||||
|
||||
@ -61,18 +63,19 @@ 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 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 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 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 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_
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_
|
||||
|
@ -10,8 +10,8 @@
|
||||
|
||||
/* coding tables for the KLT coefficients */
|
||||
|
||||
#include "lpc_tables.h"
|
||||
#include "settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/lpc_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
|
||||
/* cdf array for model indicator */
|
||||
const uint16_t WebRtcIsac_kQKltModelCdf[4] = {
|
||||
|
@ -15,34 +15,33 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_
|
||||
|
||||
#include "structs.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/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 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 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)
|
||||
#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];
|
||||
extern const uint16_t WebRtcIsac_kQKltModelCdf[KLT_NUM_MODELS + 1];
|
||||
|
||||
/* pointer to cdf array for model indicator */
|
||||
extern const uint16_t *WebRtcIsac_kQKltModelCdfPtr[1];
|
||||
extern const uint16_t* WebRtcIsac_kQKltModelCdfPtr[1];
|
||||
|
||||
/* initial cdf index for decoder of model indicator */
|
||||
extern const uint16_t WebRtcIsac_kQKltModelInitIndex[1];
|
||||
@ -78,9 +77,9 @@ 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_kQKltCdfPtrGain[12];
|
||||
|
||||
extern const uint16_t *WebRtcIsac_kQKltCdfPtrShape[108];
|
||||
extern const uint16_t* WebRtcIsac_kQKltCdfPtrShape[108];
|
||||
|
||||
/* left KLT transforms */
|
||||
extern const double WebRtcIsac_kKltT1Gain[4];
|
||||
@ -97,4 +96,4 @@ extern const double WebRtcIsac_kLpcMeansGain[12];
|
||||
|
||||
extern const double WebRtcIsac_kLpcMeansShape[108];
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_ */
|
||||
#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_ */
|
||||
|
@ -8,12 +8,12 @@
|
||||
* 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_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_
|
||||
|
||||
#include <math.h>
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
#include "rtc_base/system/arch.h"
|
||||
|
||||
#if defined(WEBRTC_POSIX)
|
||||
#define WebRtcIsac_lrint lrint
|
||||
@ -24,11 +24,12 @@ static __inline long int WebRtcIsac_lrint(double x_dbl) {
|
||||
__asm {
|
||||
fld x_dbl
|
||||
fistp x_int
|
||||
};
|
||||
}
|
||||
;
|
||||
|
||||
return x_int;
|
||||
}
|
||||
#else // Do a slow but correct implementation of lrint
|
||||
#else // Do a slow but correct implementation of lrint
|
||||
|
||||
static __inline long int WebRtcIsac_lrint(double x_dbl) {
|
||||
long int x_int;
|
||||
@ -38,4 +39,4 @@ static __inline long int WebRtcIsac_lrint(double x_dbl) {
|
||||
|
||||
#endif
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_
|
||||
|
@ -8,7 +8,7 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "pitch_estimator.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
@ -17,6 +17,10 @@
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/filter_functions.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/pitch_filter.h"
|
||||
#include "rtc_base/system/ignore_warnings.h"
|
||||
|
||||
static const double kInterpolWin[8] = {-0.00067556028640, 0.02184247643159, -0.12203175715679, 0.60086484101160,
|
||||
0.60086484101160, -0.12203175715679, 0.02184247643159, -0.00067556028640};
|
||||
|
||||
@ -122,13 +126,56 @@ static void PCorr(const double *in, double *outcorr)
|
||||
}
|
||||
}
|
||||
|
||||
static void WebRtcIsac_AllpassFilterForDec(double* InOut,
|
||||
const double* APSectionFactors,
|
||||
size_t lengthInOut,
|
||||
double* FilterState) {
|
||||
// This performs all-pass filtering--a series of first order all-pass
|
||||
// sections are used to filter the input in a cascade manner.
|
||||
size_t n, j;
|
||||
double temp;
|
||||
for (j = 0; j < ALLPASSSECTIONS; j++) {
|
||||
for (n = 0; n < lengthInOut; n += 2) {
|
||||
temp = InOut[n]; // store input
|
||||
InOut[n] = FilterState[j] + APSectionFactors[j] * temp;
|
||||
FilterState[j] = -APSectionFactors[j] * InOut[n] + temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WebRtcIsac_InitializePitch(const double *in,
|
||||
const double old_lag,
|
||||
const double old_gain,
|
||||
PitchAnalysisStruct *State,
|
||||
double *lags)
|
||||
{
|
||||
static 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
|
||||
|
||||
static const double APupper[ALLPASSSECTIONS] = {0.0347, 0.3826};
|
||||
static const double APlower[ALLPASSSECTIONS] = {0.1544, 0.744};
|
||||
|
||||
size_t n;
|
||||
double data_vec[PITCH_FRAME_LEN];
|
||||
|
||||
/* copy input */
|
||||
memcpy(data_vec + 1, in, sizeof(double) * (N - 1));
|
||||
|
||||
data_vec[0] = state_in[2 * ALLPASSSECTIONS]; // the z^(-1) state
|
||||
state_in[2 * ALLPASSSECTIONS] = in[N - 1];
|
||||
|
||||
WebRtcIsac_AllpassFilterForDec(data_vec + 1, APupper, N, state_in);
|
||||
WebRtcIsac_AllpassFilterForDec(data_vec, APlower, N,
|
||||
state_in + ALLPASSSECTIONS);
|
||||
|
||||
for (n = 0; n < N / 2; n++)
|
||||
out[n] = data_vec[2 * n] + data_vec[2 * n + 1];
|
||||
}
|
||||
|
||||
RTC_PUSH_IGNORING_WFRAME_LARGER_THAN()
|
||||
|
||||
static 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;
|
||||
@ -449,7 +496,7 @@ void WebRtcIsac_InitializePitch(const double *in,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RTC_POP_IGNORING_WFRAME_LARGER_THAN()
|
||||
|
||||
/* create weighting matrix by orthogonalizing a basis of polynomials of increasing order
|
||||
* t = (0:4)';
|
||||
@ -464,6 +511,29 @@ static const double kWeight[5][5] = {
|
||||
{ 0.01714285714286, 0.05142857142857, -0.05714285714286, -0.30857142857143, 0.29714285714286}
|
||||
};
|
||||
|
||||
/* second order high-pass filter */
|
||||
static void WebRtcIsac_Highpass(const double* in,
|
||||
double* out,
|
||||
double* state,
|
||||
size_t N) {
|
||||
/* create high-pass filter ocefficients
|
||||
* z = 0.998 * exp(j*2*pi*35/8000);
|
||||
* p = 0.94 * exp(j*2*pi*140/8000);
|
||||
* HP_b = [1, -2*real(z), abs(z)^2];
|
||||
* HP_a = [1, -2*real(p), abs(p)^2]; */
|
||||
static const double a_coef[2] = { 1.86864659625574, -0.88360000000000};
|
||||
static const double b_coef[2] = {-1.99524591718270, 0.99600400000000};
|
||||
|
||||
size_t k;
|
||||
|
||||
for (k=0; k<N; k++) {
|
||||
*out = *in + state[1];
|
||||
state[1] = state[0] + b_coef[0] * *in + a_coef[0] * *out;
|
||||
state[0] = b_coef[1] * *in++ + a_coef[1] * *out++;
|
||||
}
|
||||
}
|
||||
|
||||
RTC_PUSH_IGNORING_WFRAME_LARGER_THAN()
|
||||
|
||||
void WebRtcIsac_PitchAnalysis(const double *in, /* PITCH_FRAME_LEN samples */
|
||||
double *out, /* PITCH_FRAME_LEN+QLOOKAHEAD samples */
|
||||
@ -621,3 +691,5 @@ void WebRtcIsac_PitchAnalysis(const double *in, /* PITCH_FRAME_LEN
|
||||
for (k = 0; k < QLOOKAHEAD; k++)
|
||||
State->inbuf[k] = inbuf[k + PITCH_FRAME_LEN];
|
||||
}
|
||||
|
||||
RTC_POP_IGNORING_WFRAME_LARGER_THAN()
|
||||
|
@ -15,61 +15,18 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_
|
||||
|
||||
#include "structs.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/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_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_ */
|
||||
#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_ */
|
||||
|
@ -8,13 +8,13 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "pitch_estimator.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "os_specific_inline.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/pitch_estimator.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/os_specific_inline.h"
|
||||
#include "rtc_base/compile_assert_c.h"
|
||||
|
||||
/*
|
||||
* We are implementing the following filters;
|
||||
@ -275,6 +275,11 @@ static void FilterFrame(const double* in_data, PitchFiltstr* filter_state,
|
||||
/* Copy states to local variables. */
|
||||
memcpy(filter_parameters.buffer, filter_state->ubuf,
|
||||
sizeof(filter_state->ubuf));
|
||||
RTC_COMPILE_ASSERT(sizeof(filter_parameters.buffer) >=
|
||||
sizeof(filter_state->ubuf));
|
||||
memset(filter_parameters.buffer +
|
||||
sizeof(filter_state->ubuf) / sizeof(filter_state->ubuf[0]),
|
||||
0, sizeof(filter_parameters.buffer) - sizeof(filter_state->ubuf));
|
||||
memcpy(filter_parameters.damper_state, filter_state->ystate,
|
||||
sizeof(filter_state->ystate));
|
||||
|
||||
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_FILTER_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_FILTER_H_
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/structs.h"
|
||||
|
||||
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);
|
||||
|
||||
#endif // MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_FILTER_H_
|
@ -8,9 +8,8 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "pitch_gain_tables.h"
|
||||
|
||||
#include "settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
|
||||
/* header file for coding tables for the pitch filter side-info in the entropy coder */
|
||||
/********************* Pitch Filter Gain Coefficient Tables ************************/
|
||||
|
@ -11,17 +11,20 @@
|
||||
/*
|
||||
* pitch_gain_tables.h
|
||||
*
|
||||
* This file contains tables for the pitch filter side-info in the entropy coder.
|
||||
* 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_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_
|
||||
|
||||
#include "webrtc/typedefs.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/* header file for coding tables for the pitch filter side-info in the entropy coder */
|
||||
/********************* Pitch Filter Gain Coefficient Tables ************************/
|
||||
/* 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];
|
||||
|
||||
@ -42,4 +45,4 @@ extern const int16_t WebRtcIsac_kQMeanGain4Q12[144];
|
||||
/* size of cdf table */
|
||||
extern const uint16_t WebRtcIsac_kQCdfTableSizeGain[1];
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_ */
|
||||
#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_ */
|
||||
|
@ -8,8 +8,8 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "pitch_lag_tables.h"
|
||||
#include "settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
|
||||
/* header file for coding tables for the pitch filter side-info in the entropy coder */
|
||||
/********************* Pitch Filter Gain Coefficient Tables ************************/
|
||||
|
@ -11,16 +11,20 @@
|
||||
/*
|
||||
* pitch_lag_tables.h
|
||||
*
|
||||
* This file contains tables for the pitch filter side-info in the entropy coder.
|
||||
* 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_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_
|
||||
#define 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 ************************/
|
||||
#include <stdint.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 */
|
||||
|
||||
@ -30,7 +34,7 @@ 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];
|
||||
extern const uint16_t* WebRtcIsac_kQPitchLagCdfPtrLo[4];
|
||||
|
||||
/* size of first cdf table */
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdfSizeLo[1];
|
||||
@ -49,7 +53,6 @@ extern const double WebRtcIsac_kQMeanLag4Lo[9];
|
||||
|
||||
extern const double WebRtcIsac_kQPitchLagStepsizeLo;
|
||||
|
||||
|
||||
/* tables for use with medium pitch gain */
|
||||
|
||||
/* cdfs for quantized pitch lags */
|
||||
@ -58,7 +61,7 @@ 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];
|
||||
extern const uint16_t* WebRtcIsac_kQPitchLagCdfPtrMid[4];
|
||||
|
||||
/* size of first cdf table */
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdfSizeMid[1];
|
||||
@ -77,7 +80,6 @@ extern const double WebRtcIsac_kQMeanLag4Mid[19];
|
||||
|
||||
extern const double WebRtcIsac_kQPitchLagStepsizeMid;
|
||||
|
||||
|
||||
/* tables for use with large pitch gain */
|
||||
|
||||
/* cdfs for quantized pitch lags */
|
||||
@ -86,7 +88,7 @@ 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];
|
||||
extern const uint16_t* WebRtcIsac_kQPitchLagCdfPtrHi[4];
|
||||
|
||||
/* size of first cdf table */
|
||||
extern const uint16_t WebRtcIsac_kQPitchLagCdfSizeHi[1];
|
||||
@ -111,4 +113,4 @@ 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_ */
|
||||
#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_ */
|
||||
|
@ -15,191 +15,182 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_
|
||||
|
||||
/* sampling frequency (Hz) */
|
||||
#define FS 16000
|
||||
#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
|
||||
|
||||
|
||||
#define INITIAL_FRAMESAMPLES 960
|
||||
|
||||
/* do not modify the following; this will have to be modified if we
|
||||
* have a 20ms framesize option */
|
||||
/**********************************************************************/
|
||||
/* miliseconds */
|
||||
#define FRAMESIZE 30
|
||||
#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
|
||||
#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)
|
||||
#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)
|
||||
#define FRAMESAMPLES_10ms ((10 * FS) / 1000)
|
||||
#define SWBFRAMESAMPLES_10ms (FRAMESAMPLES_10ms * 2)
|
||||
/* number of samples in 30 ms frame */
|
||||
#define FRAMESAMPLES_30ms 480
|
||||
#define FRAMESAMPLES_30ms 480
|
||||
/* number of subframes */
|
||||
#define SUBFRAMES 6
|
||||
#define SUBFRAMES 6
|
||||
/* length of a subframe */
|
||||
#define UPDATE 80
|
||||
#define UPDATE 80
|
||||
/* length of half a subframe (low/high band) */
|
||||
#define HALF_SUBFRAMELEN (UPDATE/2)
|
||||
#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 */
|
||||
#define QLOOKAHEAD 24 /* 3 ms */
|
||||
/* order of AR model in spectral entropy coder */
|
||||
#define AR_ORDER 6
|
||||
#define AR_ORDER 6
|
||||
/* order of LP model in spectral entropy coder */
|
||||
#define LP_ORDER 0
|
||||
#define LP_ORDER 0
|
||||
|
||||
/* window length (masking analysis) */
|
||||
#define WINLEN 256
|
||||
#define WINLEN 256
|
||||
/* order of low-band pole filter used to approximate masking curve */
|
||||
#define ORDERLO 12
|
||||
#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
|
||||
#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
|
||||
#define POSTQORDER 3
|
||||
/* order for pre-filterbank */
|
||||
#define QORDER 3
|
||||
#define QORDER 3
|
||||
/* another order */
|
||||
#define QORDER_ALL (POSTQORDER+QORDER-1)
|
||||
#define QORDER_ALL (POSTQORDER + QORDER - 1)
|
||||
/* for decimator */
|
||||
#define ALLPASSSECTIONS 2
|
||||
|
||||
#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 */
|
||||
#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
|
||||
#define BIT_COUNTER_SIZE 30
|
||||
/* maximum order of any AR model or filter */
|
||||
#define MAX_AR_MODEL_ORDER 12//50
|
||||
|
||||
#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)
|
||||
#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
|
||||
#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
|
||||
#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)
|
||||
#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
|
||||
#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
|
||||
#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
|
||||
|
||||
|
||||
#define PITCH_GAIN_STEPSIZE 0.125
|
||||
|
||||
/* Order of high pass filter */
|
||||
#define HPORDER 2
|
||||
#define HPORDER 2
|
||||
|
||||
/* some mathematical constants */
|
||||
/* log2(exp) */
|
||||
#define LOG2EXP 1.44269504088896
|
||||
#define PI 3.14159265358979
|
||||
#define LOG2EXP 1.44269504088896
|
||||
#define PI 3.14159265358979
|
||||
|
||||
/* Maximum number of iterations allowed to limit payload size */
|
||||
#define MAX_PAYLOAD_LIMIT_ITERATION 5
|
||||
#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_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 RCU_TRANSCODING_SCALE_UB 0.50f
|
||||
#define RCU_TRANSCODING_SCALE_UB_INVERSE 2.0f
|
||||
|
||||
/* 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
|
||||
#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
|
||||
#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
|
||||
#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
|
||||
#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
|
||||
#define ISAC_INCOMPATIBLE_FORMATS 6810
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_ */
|
||||
#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_ */
|
||||
|
@ -8,8 +8,8 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "spectrum_ar_model_tables.h"
|
||||
#include "settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
|
||||
/********************* AR Coefficient Tables ************************/
|
||||
/* cdf for quantized reflection coefficient 1 */
|
||||
|
@ -11,15 +11,15 @@
|
||||
/*
|
||||
* spectrum_ar_model_tables.h
|
||||
*
|
||||
* This file contains definitions of tables with AR coefficients,
|
||||
* 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_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_
|
||||
#define MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_
|
||||
|
||||
#include "structs.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/structs.h"
|
||||
|
||||
#define NUM_AR_RC_QUANT_BAUNDARY 12
|
||||
|
||||
@ -45,15 +45,15 @@ 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 */
|
||||
/* 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];
|
||||
extern const uint16_t* WebRtcIsac_kQArRcCdfPtr[AR_ORDER];
|
||||
|
||||
/* pointers to AR representation levels tables */
|
||||
extern const int16_t *WebRtcIsac_kQArRcLevelsPtr[AR_ORDER];
|
||||
|
||||
extern const int16_t* WebRtcIsac_kQArRcLevelsPtr[AR_ORDER];
|
||||
|
||||
/******************** GAIN Coefficient Tables ***********************/
|
||||
/* cdf for Gain coefficient */
|
||||
@ -66,7 +66,7 @@ extern const int32_t WebRtcIsac_kQGain2Levels[18];
|
||||
extern const int32_t WebRtcIsac_kQGain2BoundaryLevels[19];
|
||||
|
||||
/* pointer to Gain cdf table */
|
||||
extern const uint16_t *WebRtcIsac_kQGainCdf_ptr[1];
|
||||
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];
|
||||
@ -75,4 +75,5 @@ extern const uint16_t WebRtcIsac_kQGainInitIndex[1];
|
||||
/* Cosine table */
|
||||
extern const int16_t WebRtcIsac_kCos[6][60];
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ */
|
||||
#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ \
|
||||
*/
|
||||
|
@ -15,187 +15,174 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_
|
||||
#ifndef MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_
|
||||
#define 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/include/isac.h"
|
||||
#include "webrtc/modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
#include "modules/audio_coding/codecs/isac/bandwidth_info.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
#include "modules/third_party/fft/fft.h"
|
||||
|
||||
typedef struct Bitstreamstruct {
|
||||
|
||||
uint8_t stream[STREAM_SIZE_MAX];
|
||||
uint32_t W_upper;
|
||||
uint32_t streamval;
|
||||
uint32_t stream_index;
|
||||
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 DataBufferLo[WINLEN];
|
||||
double DataBufferHi[WINLEN];
|
||||
double CorrBufLo[ORDERLO + 1];
|
||||
double CorrBufHi[ORDERHI + 1];
|
||||
|
||||
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];
|
||||
|
||||
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;
|
||||
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];
|
||||
|
||||
//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];
|
||||
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];
|
||||
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];
|
||||
// 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];
|
||||
double HPstates1[HPORDER];
|
||||
double HPstates2[HPORDER];
|
||||
|
||||
float STATE_0_LOWER_float[2*POSTQORDER];
|
||||
float STATE_0_UPPER_float[2*POSTQORDER];
|
||||
float STATE_0_LOWER_float[2 * POSTQORDER];
|
||||
float STATE_0_UPPER_float[2 * POSTQORDER];
|
||||
|
||||
float HPstates1_float[HPORDER];
|
||||
float HPstates2_float[HPORDER];
|
||||
float HPstates1_float[HPORDER];
|
||||
float HPstates2_float[HPORDER];
|
||||
|
||||
} PostFiltBankstr;
|
||||
|
||||
typedef struct {
|
||||
// data buffer for pitch filter
|
||||
double ubuf[PITCH_BUFFSIZE];
|
||||
|
||||
//data buffer for pitch filter
|
||||
double ubuf[PITCH_BUFFSIZE];
|
||||
// low pass state vector
|
||||
double ystate[PITCH_DAMPORDER];
|
||||
|
||||
//low pass state vector
|
||||
double ystate[PITCH_DAMPORDER];
|
||||
|
||||
//old lag and gain
|
||||
double oldlagp[1];
|
||||
double oldgainp[1];
|
||||
// old lag and gain
|
||||
double oldlagp[1];
|
||||
double oldgainp[1];
|
||||
|
||||
} PitchFiltstr;
|
||||
|
||||
typedef struct {
|
||||
// data buffer
|
||||
double buffer[PITCH_WLPCBUFLEN];
|
||||
|
||||
//data buffer
|
||||
double buffer[PITCH_WLPCBUFLEN];
|
||||
// state vectors
|
||||
double istate[PITCH_WLPCORDER];
|
||||
double weostate[PITCH_WLPCORDER];
|
||||
double whostate[PITCH_WLPCORDER];
|
||||
|
||||
//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];
|
||||
// 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];
|
||||
|
||||
//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 whitened_buf[QLOOKAHEAD];
|
||||
double inbuf[QLOOKAHEAD];
|
||||
|
||||
double inbuf[QLOOKAHEAD];
|
||||
|
||||
PitchFiltstr PFstr_wght;
|
||||
PitchFiltstr PFstr;
|
||||
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;
|
||||
int32_t prev_frame_length;
|
||||
|
||||
/* Previous RTP timestamp from received
|
||||
packet (in samples relative beginning) */
|
||||
int32_t prev_rec_rtp_number;
|
||||
int32_t prev_rec_rtp_number;
|
||||
|
||||
/* Send timestamp for previous packet (in ms using timeGetTime()) */
|
||||
uint32_t prev_rec_send_ts;
|
||||
uint32_t prev_rec_send_ts;
|
||||
|
||||
/* Arrival time for previous packet (in ms using timeGetTime()) */
|
||||
uint32_t prev_rec_arr_ts;
|
||||
uint32_t prev_rec_arr_ts;
|
||||
|
||||
/* rate of previous packet, derived from RTP timestamps (in bits/s) */
|
||||
float prev_rec_rtp_rate;
|
||||
float prev_rec_rtp_rate;
|
||||
|
||||
/* Time sinse the last update of the BN estimate (in ms) */
|
||||
uint32_t last_update_ts;
|
||||
uint32_t last_update_ts;
|
||||
|
||||
/* Time sinse the last reduction (in ms) */
|
||||
uint32_t last_reduction_ts;
|
||||
uint32_t last_reduction_ts;
|
||||
|
||||
/* How many times the estimate was update in the beginning */
|
||||
int32_t count_tot_updates_rec;
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
float rec_header_rate;
|
||||
|
||||
/* The estimated bottle neck rate from here to there (in bits/s) */
|
||||
float send_bw_avg;
|
||||
float send_bw_avg;
|
||||
|
||||
/* The estimated mean absolute jitter value, as seen on
|
||||
the other siee (in ms) */
|
||||
float send_max_delay_avg;
|
||||
float send_max_delay_avg;
|
||||
|
||||
// number of packets received since last update
|
||||
int num_pkts_rec;
|
||||
@ -218,72 +205,54 @@ typedef struct {
|
||||
|
||||
int change_to_WB;
|
||||
|
||||
uint32_t senderTimestamp;
|
||||
uint32_t receiverTimestamp;
|
||||
//enum IsacSamplingRate incomingStreamSampFreq;
|
||||
uint16_t numConsecLatePkts;
|
||||
float consecLatency;
|
||||
int16_t inWaitLatePkts;
|
||||
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;
|
||||
int PrevExceed;
|
||||
/* ms */
|
||||
int ExceedAgo;
|
||||
int ExceedAgo;
|
||||
/* packets left to send in current burst */
|
||||
int BurstCounter;
|
||||
int BurstCounter;
|
||||
/* packets */
|
||||
int InitCounter;
|
||||
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;
|
||||
int startIdx;
|
||||
|
||||
/* Frame length in samples */
|
||||
int16_t framelength;
|
||||
|
||||
/* Pitch Gain */
|
||||
int pitchGain_index[2];
|
||||
int pitchGain_index[2];
|
||||
|
||||
/* Pitch Lag */
|
||||
double meanGain[2];
|
||||
int pitchIndex[PITCH_SUBFRAMES*2];
|
||||
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];
|
||||
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];
|
||||
@ -291,125 +260,109 @@ typedef struct {
|
||||
int16_t AvgPitchGain[2];
|
||||
|
||||
/* Used in adaptive mode only */
|
||||
int minBytes;
|
||||
int minBytes;
|
||||
|
||||
} IsacSaveEncoderData;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int indexLPCShape[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
|
||||
double lpcGain[SUBFRAMES << 1];
|
||||
int lpcGainIndex[SUBFRAMES << 1];
|
||||
|
||||
int indexLPCShape[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
|
||||
double lpcGain[SUBFRAMES<<1];
|
||||
int lpcGainIndex[SUBFRAMES<<1];
|
||||
|
||||
Bitstr bitStreamObj;
|
||||
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;
|
||||
Bitstr bitstr_obj;
|
||||
MaskFiltstr maskfiltstr_obj;
|
||||
PreFiltBankstr prefiltbankstr_obj;
|
||||
PitchFiltstr pitchfiltstr_obj;
|
||||
PitchAnalysisStruct pitchanalysisstr_obj;
|
||||
FFTstr fftstr_obj;
|
||||
FFTstr fftstr_obj;
|
||||
IsacSaveEncoderData SaveEnc_obj;
|
||||
|
||||
int buffer_index;
|
||||
int16_t current_framesamples;
|
||||
int buffer_index;
|
||||
int16_t current_framesamples;
|
||||
|
||||
float data_buffer_float[FRAMESAMPLES_30ms];
|
||||
float data_buffer_float[FRAMESAMPLES_30ms];
|
||||
|
||||
int frame_nb;
|
||||
double bottleneck;
|
||||
int16_t new_framelength;
|
||||
double s2nr;
|
||||
int frame_nb;
|
||||
double bottleneck;
|
||||
int16_t new_framelength;
|
||||
double s2nr;
|
||||
|
||||
/* Maximum allowed number of bits for a 30 msec packet */
|
||||
int16_t payloadLimitBytes30;
|
||||
int16_t payloadLimitBytes30;
|
||||
/* Maximum allowed number of bits for a 30 msec packet */
|
||||
int16_t payloadLimitBytes60;
|
||||
int16_t payloadLimitBytes60;
|
||||
/* Maximum allowed number of bits for both 30 and 60 msec packet */
|
||||
int16_t maxPayloadBytes;
|
||||
int16_t maxPayloadBytes;
|
||||
/* Maximum allowed rate in bytes per 30 msec packet */
|
||||
int16_t maxRateInBytes;
|
||||
int16_t maxRateInBytes;
|
||||
|
||||
/*---
|
||||
If set to 1 iSAC will not addapt the frame-size, if used in
|
||||
If set to 1 iSAC will not adapt the frame-size, if used in
|
||||
channel-adaptive mode. The initial value will be used for all rates.
|
||||
---*/
|
||||
int16_t enforceFrameSize;
|
||||
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
|
||||
the redundant payload. We can not retrieve it from BWE because it is
|
||||
a recursive procedure (WebRtcIsac_GetDownlinkBwJitIndexImpl) and has to be
|
||||
called only once per each encode.
|
||||
-----*/
|
||||
int16_t lastBWIdx;
|
||||
int16_t lastBWIdx;
|
||||
} ISACLBEncStruct;
|
||||
|
||||
typedef struct {
|
||||
|
||||
Bitstr bitstr_obj;
|
||||
MaskFiltstr maskfiltstr_obj;
|
||||
PreFiltBankstr prefiltbankstr_obj;
|
||||
FFTstr fftstr_obj;
|
||||
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;
|
||||
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;
|
||||
// int16_t payloadLimitBytes30;
|
||||
/* Maximum allowed number of bits for both 30 and 60 msec packet */
|
||||
//int16_t maxPayloadBytes;
|
||||
int16_t maxPayloadSizeBytes;
|
||||
// int16_t maxPayloadBytes;
|
||||
int16_t maxPayloadSizeBytes;
|
||||
|
||||
double lastLPCVec[UB_LPC_ORDER];
|
||||
int16_t numBytesUsed;
|
||||
int16_t lastJitterInfo;
|
||||
double lastLPCVec[UB_LPC_ORDER];
|
||||
int16_t numBytesUsed;
|
||||
int16_t lastJitterInfo;
|
||||
} ISACUBEncStruct;
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
Bitstr bitstr_obj;
|
||||
MaskFiltstr maskfiltstr_obj;
|
||||
Bitstr bitstr_obj;
|
||||
MaskFiltstr maskfiltstr_obj;
|
||||
PostFiltBankstr postfiltbankstr_obj;
|
||||
PitchFiltstr pitchfiltstr_obj;
|
||||
FFTstr fftstr_obj;
|
||||
PitchFiltstr pitchfiltstr_obj;
|
||||
FFTstr fftstr_obj;
|
||||
|
||||
} ISACLBDecStruct;
|
||||
|
||||
typedef struct {
|
||||
|
||||
Bitstr bitstr_obj;
|
||||
MaskFiltstr maskfiltstr_obj;
|
||||
Bitstr bitstr_obj;
|
||||
MaskFiltstr maskfiltstr_obj;
|
||||
PostFiltBankstr postfiltbankstr_obj;
|
||||
FFTstr fftstr_obj;
|
||||
FFTstr fftstr_obj;
|
||||
|
||||
} ISACUBDecStruct;
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
ISACLBEncStruct ISACencLB_obj;
|
||||
ISACLBDecStruct ISACdecLB_obj;
|
||||
} ISACLBStruct;
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
ISACUBEncStruct ISACencUB_obj;
|
||||
ISACUBDecStruct ISACdecUB_obj;
|
||||
} ISACUBStruct;
|
||||
@ -421,14 +374,14 @@ typedef struct {
|
||||
*/
|
||||
typedef struct {
|
||||
/* 6 lower-band & 6 upper-band */
|
||||
double loFiltGain[SUBFRAMES];
|
||||
double hiFiltGain[SUBFRAMES];
|
||||
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];
|
||||
uint8_t stream[3];
|
||||
} transcode_obj;
|
||||
|
||||
typedef struct {
|
||||
@ -444,46 +397,46 @@ typedef struct {
|
||||
|
||||
typedef struct {
|
||||
// lower-band codec instance
|
||||
ISACLBStruct instLB;
|
||||
ISACLBStruct instLB;
|
||||
// upper-band codec instance
|
||||
ISACUBStruct instUB;
|
||||
ISACUBStruct instUB;
|
||||
|
||||
// Bandwidth Estimator and model for the rate.
|
||||
BwEstimatorstr bwestimator_obj;
|
||||
RateModel rate_data_obj;
|
||||
double MaxDelay;
|
||||
BwEstimatorstr bwestimator_obj;
|
||||
RateModel rate_data_obj;
|
||||
double MaxDelay;
|
||||
|
||||
/* 0 = adaptive; 1 = instantaneous */
|
||||
int16_t codingMode;
|
||||
int16_t codingMode;
|
||||
|
||||
// overall bottleneck of the codec
|
||||
int32_t bottleneck;
|
||||
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];
|
||||
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;
|
||||
int16_t errorCode;
|
||||
|
||||
// bandwidth of the encoded audio 8, 12 or 16 kHz
|
||||
enum ISACBandwidth bandwidthKHz;
|
||||
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;
|
||||
int16_t initFlag;
|
||||
|
||||
// Flag to to indicate signal bandwidth switch
|
||||
int16_t resetFlag_8kHz;
|
||||
int16_t resetFlag_8kHz;
|
||||
|
||||
// Maximum allowed rate, measured in Bytes per 30 ms.
|
||||
int16_t maxRateBytesPer30Ms;
|
||||
int16_t maxRateBytesPer30Ms;
|
||||
// Maximum allowed payload-size, measured in Bytes.
|
||||
int16_t maxPayloadSizeBytes;
|
||||
int16_t maxPayloadSizeBytes;
|
||||
/* The expected sampling rate of the input signal. Valid values are 16000
|
||||
* and 32000. This is not the operation sampling rate of the codec. */
|
||||
uint16_t in_sample_rate_hz;
|
||||
@ -492,4 +445,4 @@ typedef struct {
|
||||
TransformTables transform_tables;
|
||||
} ISACMainStruct;
|
||||
|
||||
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_ */
|
||||
#endif /* MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_ */
|
||||
|
@ -8,12 +8,13 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
#include "fft.h"
|
||||
#include "codec.h"
|
||||
#include "os_specific_inline.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/codec.h"
|
||||
#include "modules/audio_coding/codecs/isac/main/source/os_specific_inline.h"
|
||||
#include "modules/third_party/fft/fft.h"
|
||||
|
||||
void WebRtcIsac_InitTransform(TransformTables* tables) {
|
||||
int k;
|
||||
double fact, phase;
|
||||
|
@ -2,12 +2,21 @@ webrtc_audio_coding_sources = [
|
||||
'codecs/isac/main/source/arith_routines.c',
|
||||
'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/crc.c',
|
||||
'codecs/isac/main/source/decode_bwe.c',
|
||||
'codecs/isac/main/source/decode.c',
|
||||
'codecs/isac/main/source/encode.c',
|
||||
'codecs/isac/main/source/encode_lpc_swb.c',
|
||||
'codecs/isac/main/source/entropy_coding.c',
|
||||
'codecs/isac/main/source/filter_functions.c',
|
||||
'codecs/isac/main/source/filterbanks.c',
|
||||
'codecs/isac/main/source/filterbank_tables.c',
|
||||
'codecs/isac/main/source/filter_functions.c',
|
||||
'codecs/isac/main/source/intialize.c',
|
||||
'codecs/isac/main/source/isac.c',
|
||||
'codecs/isac/main/source/isac_vad.c',
|
||||
'codecs/isac/main/source/lattice.c',
|
||||
'codecs/isac/main/source/lpc_analysis.c',
|
||||
'codecs/isac/main/source/lpc_gain_swb_tables.c',
|
||||
'codecs/isac/main/source/lpc_shape_swb12_tables.c',
|
||||
@ -18,24 +27,12 @@ webrtc_audio_coding_sources = [
|
||||
'codecs/isac/main/source/pitch_gain_tables.c',
|
||||
'codecs/isac/main/source/pitch_lag_tables.c',
|
||||
'codecs/isac/main/source/spectrum_ar_model_tables.c',
|
||||
'codecs/audio_decoder.cc',
|
||||
'codecs/audio_encoder.cc',
|
||||
'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/crc.c',
|
||||
'codecs/isac/main/source/decode.c',
|
||||
'codecs/isac/main/source/decode_bwe.c',
|
||||
'codecs/isac/main/source/encode.c',
|
||||
'codecs/isac/main/source/fft.c',
|
||||
'codecs/isac/main/source/isac.c',
|
||||
'codecs/isac/main/source/lattice.c',
|
||||
'codecs/isac/main/source/transform.c',
|
||||
]
|
||||
|
||||
libwebrtc_audio_coding = library('webrtc_audio_coding',
|
||||
webrtc_audio_coding_sources,
|
||||
dependencies: [base_dep, common_audio_dep] + common_deps,
|
||||
dependencies: [base_dep, api_dep, common_audio_dep, system_wrappers_dep, fft_dep] + common_deps,
|
||||
include_directories: webrtc_inc,
|
||||
c_args: common_cflags,
|
||||
cpp_args: common_cxxflags,
|
||||
@ -50,13 +47,13 @@ webrtc_audio_coding_dep = declare_dependency(
|
||||
)
|
||||
|
||||
install_headers(['codecs/isac/bandwidth_info.h'],
|
||||
subdir: 'webrtc_audio_processing/webrtc/modules/audio_coding/codecs/isac'
|
||||
subdir: 'webrtc_audio_processing/modules/audio_coding/codecs/isac'
|
||||
)
|
||||
|
||||
install_headers(['codecs/isac/main/source/settings.h'],
|
||||
subdir: 'webrtc_audio_processing/webrtc/modules/audio_coding/codecs/isac/main/source'
|
||||
subdir: 'webrtc_audio_processing/modules/audio_coding/codecs/isac/main/source'
|
||||
)
|
||||
|
||||
install_headers(['codecs/isac/main/include/isac.h'],
|
||||
subdir: 'webrtc_audio_processing/webrtc/modules/audio_coding/codecs/isac/main/include'
|
||||
subdir: 'webrtc_audio_processing/modules/audio_coding/codecs/isac/main/include'
|
||||
)
|
||||
|
@ -6,281 +6,606 @@
|
||||
# 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
|
||||
import("../../webrtc.gni")
|
||||
if (rtc_enable_protobuf) {
|
||||
import("//third_party/protobuf/proto_library.gni")
|
||||
}
|
||||
|
||||
source_set("audio_processing") {
|
||||
config("apm_debug_dump") {
|
||||
if (apm_debug_dump) {
|
||||
defines = [ "WEBRTC_APM_DEBUG_DUMP=1" ]
|
||||
} else {
|
||||
defines = [ "WEBRTC_APM_DEBUG_DUMP=0" ]
|
||||
}
|
||||
}
|
||||
|
||||
rtc_library("config") {
|
||||
visibility = [ ":*" ]
|
||||
sources = [
|
||||
"include/config.cc",
|
||||
"include/config.h",
|
||||
]
|
||||
deps = [ "../../rtc_base/system:rtc_export" ]
|
||||
}
|
||||
|
||||
rtc_library("api") {
|
||||
visibility = [ "*" ]
|
||||
sources = [
|
||||
"include/audio_processing.cc",
|
||||
"include/audio_processing.h",
|
||||
]
|
||||
deps = [
|
||||
":audio_frame_view",
|
||||
":audio_processing_statistics",
|
||||
":config",
|
||||
"../../api:array_view",
|
||||
"../../api:scoped_refptr",
|
||||
"../../api/audio:aec3_config",
|
||||
"../../api/audio:audio_frame_api",
|
||||
"../../api/audio:echo_control",
|
||||
"../../rtc_base:deprecation",
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
"../../rtc_base/system:arch",
|
||||
"../../rtc_base/system:file_wrapper",
|
||||
"../../rtc_base/system:rtc_export",
|
||||
"agc:gain_control_interface",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||
}
|
||||
|
||||
rtc_library("audio_frame_proxies") {
|
||||
visibility = [ "*" ]
|
||||
sources = [
|
||||
"include/audio_frame_proxies.cc",
|
||||
"include/audio_frame_proxies.h",
|
||||
]
|
||||
deps = [
|
||||
":api",
|
||||
":audio_frame_view",
|
||||
"../../api/audio:audio_frame_api",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_library("audio_buffer") {
|
||||
visibility = [ "*" ]
|
||||
|
||||
configs += [ ":apm_debug_dump" ]
|
||||
|
||||
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/array_util.cc",
|
||||
"beamformer/array_util.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 = [
|
||||
":api",
|
||||
"../../api:array_view",
|
||||
"../../common_audio",
|
||||
"../../common_audio:common_audio_c",
|
||||
"../../rtc_base:checks",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_library("high_pass_filter") {
|
||||
visibility = [ "*" ]
|
||||
|
||||
sources = [
|
||||
"high_pass_filter.cc",
|
||||
"high_pass_filter.h",
|
||||
]
|
||||
|
||||
defines = []
|
||||
|
||||
deps = [
|
||||
":audio_buffer",
|
||||
"../../api:array_view",
|
||||
"../../rtc_base:checks",
|
||||
"utility:cascaded_biquad_filter",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_source_set("aec_dump_interface") {
|
||||
visibility = [ "*" ]
|
||||
sources = [
|
||||
"include/aec_dump.cc",
|
||||
"include/aec_dump.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":api",
|
||||
":audio_frame_view",
|
||||
"../../rtc_base:deprecation",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_library("audio_processing") {
|
||||
visibility = [ "*" ]
|
||||
configs += [ ":apm_debug_dump" ]
|
||||
sources = [
|
||||
"audio_processing_builder_impl.cc",
|
||||
"audio_processing_impl.cc",
|
||||
"audio_processing_impl.h",
|
||||
"common.h",
|
||||
"echo_control_mobile_impl.cc",
|
||||
"echo_control_mobile_impl.h",
|
||||
"echo_detector/circular_buffer.cc",
|
||||
"echo_detector/circular_buffer.h",
|
||||
"echo_detector/mean_variance_estimator.cc",
|
||||
"echo_detector/mean_variance_estimator.h",
|
||||
"echo_detector/moving_max.cc",
|
||||
"echo_detector/moving_max.h",
|
||||
"echo_detector/normalized_covariance_estimator.cc",
|
||||
"echo_detector/normalized_covariance_estimator.h",
|
||||
"gain_control_impl.cc",
|
||||
"gain_control_impl.h",
|
||||
"gain_controller2.cc",
|
||||
"gain_controller2.h",
|
||||
"level_estimator.cc",
|
||||
"level_estimator.h",
|
||||
"render_queue_item_verifier.h",
|
||||
"residual_echo_detector.cc",
|
||||
"residual_echo_detector.h",
|
||||
"typing_detection.cc",
|
||||
"typing_detection.h",
|
||||
]
|
||||
|
||||
defines = []
|
||||
deps = [
|
||||
"../..:webrtc_common",
|
||||
"../audio_coding:isac",
|
||||
":aec_dump_interface",
|
||||
":api",
|
||||
":apm_logging",
|
||||
":audio_buffer",
|
||||
":audio_frame_proxies",
|
||||
":audio_frame_view",
|
||||
":audio_processing_statistics",
|
||||
":config",
|
||||
":high_pass_filter",
|
||||
":optionally_built_submodule_creators",
|
||||
":rms_level",
|
||||
":voice_detection",
|
||||
"../../api:array_view",
|
||||
"../../api:function_view",
|
||||
"../../api/audio:aec3_config",
|
||||
"../../api/audio:audio_frame_api",
|
||||
"../../api/audio:echo_control",
|
||||
"../../audio/utility:audio_frame_operations",
|
||||
"../../common_audio:common_audio_c",
|
||||
"../../common_audio/third_party/ooura:fft_size_256",
|
||||
"../../rtc_base:checks",
|
||||
"../../rtc_base:deprecation",
|
||||
"../../rtc_base:gtest_prod",
|
||||
"../../rtc_base:ignore_wundef",
|
||||
"../../rtc_base:refcount",
|
||||
"../../rtc_base:safe_minmax",
|
||||
"../../rtc_base:sanitizer",
|
||||
"../../rtc_base/synchronization:mutex",
|
||||
"../../rtc_base/system:rtc_export",
|
||||
"../../system_wrappers",
|
||||
"../../system_wrappers:field_trial",
|
||||
"../../system_wrappers:metrics",
|
||||
"aec3",
|
||||
"aec_dump:aec_dump",
|
||||
"aecm:aecm_core",
|
||||
"agc",
|
||||
"agc:gain_control_interface",
|
||||
"agc:legacy_agc",
|
||||
"agc2:adaptive_digital",
|
||||
"agc2:fixed_digital",
|
||||
"agc2:gain_applier",
|
||||
"ns",
|
||||
"transient:transient_suppressor_api",
|
||||
"vad",
|
||||
]
|
||||
|
||||
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" ]
|
||||
}
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||
|
||||
deps += [
|
||||
"../../base:rtc_base_approved",
|
||||
"../../common_audio",
|
||||
"../../common_audio:fir_filter",
|
||||
"../../common_audio:fir_filter_factory",
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
"../../system_wrappers",
|
||||
]
|
||||
|
||||
if (rtc_enable_protobuf) {
|
||||
deps += [ "aec_dump:aec_dump_impl" ]
|
||||
} else {
|
||||
deps += [ "aec_dump:null_aec_dump_factory" ]
|
||||
}
|
||||
}
|
||||
|
||||
rtc_library("voice_detection") {
|
||||
sources = [
|
||||
"voice_detection.cc",
|
||||
"voice_detection.h",
|
||||
]
|
||||
deps = [
|
||||
":api",
|
||||
":audio_buffer",
|
||||
"../../api/audio:audio_frame_api",
|
||||
"../../common_audio:common_audio_c",
|
||||
"../../rtc_base:checks",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_library("optionally_built_submodule_creators") {
|
||||
sources = [
|
||||
"optionally_built_submodule_creators.cc",
|
||||
"optionally_built_submodule_creators.h",
|
||||
]
|
||||
deps = [
|
||||
"transient:transient_suppressor_api",
|
||||
"transient:transient_suppressor_impl",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_source_set("rms_level") {
|
||||
visibility = [ "*" ]
|
||||
sources = [
|
||||
"rms_level.cc",
|
||||
"rms_level.h",
|
||||
]
|
||||
deps = [
|
||||
"../../api:array_view",
|
||||
"../../rtc_base:checks",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||
}
|
||||
|
||||
rtc_library("audio_processing_statistics") {
|
||||
visibility = [ "*" ]
|
||||
sources = [
|
||||
"include/audio_processing_statistics.cc",
|
||||
"include/audio_processing_statistics.h",
|
||||
]
|
||||
deps = [ "../../rtc_base/system:rtc_export" ]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||
}
|
||||
|
||||
rtc_source_set("audio_frame_view") {
|
||||
sources = [ "include/audio_frame_view.h" ]
|
||||
deps = [ "../../api:array_view" ]
|
||||
}
|
||||
|
||||
if (rtc_enable_protobuf) {
|
||||
proto_library("audioproc_debug_proto") {
|
||||
sources = [
|
||||
"debug.proto",
|
||||
]
|
||||
sources = [ "debug.proto" ]
|
||||
|
||||
proto_out_dir = "webrtc/audio_processing"
|
||||
proto_out_dir = "modules/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" ]
|
||||
}
|
||||
rtc_library("apm_logging") {
|
||||
configs += [ ":apm_debug_dump" ]
|
||||
sources = [
|
||||
"logging/apm_data_dumper.cc",
|
||||
"logging/apm_data_dumper.h",
|
||||
]
|
||||
deps = [
|
||||
"../../api:array_view",
|
||||
"../../common_audio",
|
||||
"../../rtc_base:checks",
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
]
|
||||
defines = []
|
||||
}
|
||||
|
||||
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 (rtc_include_tests) {
|
||||
rtc_source_set("mocks") {
|
||||
testonly = true
|
||||
sources = [ "include/mock_audio_processing.h" ]
|
||||
deps = [
|
||||
":aec_dump_interface",
|
||||
":api",
|
||||
":audio_buffer",
|
||||
":audio_processing",
|
||||
":audio_processing_statistics",
|
||||
"../../test:test_support",
|
||||
]
|
||||
}
|
||||
|
||||
group("audio_processing_tests") {
|
||||
testonly = true
|
||||
deps = [
|
||||
":audioproc_test_utils",
|
||||
"transient:click_annotate",
|
||||
"transient:transient_suppression_test",
|
||||
]
|
||||
|
||||
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" ]
|
||||
if (rtc_enable_protobuf) {
|
||||
deps += [
|
||||
":audioproc_unittest_proto",
|
||||
"aec_dump:aec_dump_unittests",
|
||||
"test/conversational_speech",
|
||||
"test/py_quality_assessment",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
rtc_library("audio_processing_unittests") {
|
||||
testonly = true
|
||||
|
||||
configs += [ ":apm_debug_dump" ]
|
||||
sources = [
|
||||
"audio_buffer_unittest.cc",
|
||||
"audio_frame_view_unittest.cc",
|
||||
"config_unittest.cc",
|
||||
"echo_control_mobile_unittest.cc",
|
||||
"gain_controller2_unittest.cc",
|
||||
"splitting_filter_unittest.cc",
|
||||
"test/fake_recording_device_unittest.cc",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":analog_mic_simulation",
|
||||
":api",
|
||||
":apm_logging",
|
||||
":audio_buffer",
|
||||
":audio_frame_view",
|
||||
":audio_processing",
|
||||
":audioproc_test_utils",
|
||||
":config",
|
||||
":high_pass_filter",
|
||||
":mocks",
|
||||
":voice_detection",
|
||||
"../../api:array_view",
|
||||
"../../api:scoped_refptr",
|
||||
"../../api/audio:aec3_config",
|
||||
"../../api/audio:aec3_factory",
|
||||
"../../common_audio",
|
||||
"../../common_audio:common_audio_c",
|
||||
"../../rtc_base",
|
||||
"../../rtc_base:checks",
|
||||
"../../rtc_base:gtest_prod",
|
||||
"../../rtc_base:ignore_wundef",
|
||||
"../../rtc_base:protobuf_utils",
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
"../../rtc_base:rtc_base_tests_utils",
|
||||
"../../rtc_base:safe_minmax",
|
||||
"../../rtc_base:task_queue_for_test",
|
||||
"../../rtc_base/synchronization:mutex",
|
||||
"../../rtc_base/system:arch",
|
||||
"../../rtc_base/system:file_wrapper",
|
||||
"../../system_wrappers",
|
||||
"../../test:fileutils",
|
||||
"../../test:rtc_expect_death",
|
||||
"../../test:test_support",
|
||||
"../audio_coding:neteq_input_audio_tools",
|
||||
"aec_dump:mock_aec_dump_unittests",
|
||||
"agc:agc_unittests",
|
||||
"agc2:adaptive_digital_unittests",
|
||||
"agc2:biquad_filter_unittests",
|
||||
"agc2:fixed_digital_unittests",
|
||||
"agc2:noise_estimator_unittests",
|
||||
"agc2:rnn_vad_with_level_unittests",
|
||||
"agc2:test_utils",
|
||||
"agc2/rnn_vad:unittests",
|
||||
"test/conversational_speech:unittest",
|
||||
"transient:transient_suppression_unittests",
|
||||
"utility:legacy_delay_estimator_unittest",
|
||||
"utility:pffft_wrapper_unittest",
|
||||
"vad:vad_unittests",
|
||||
"//testing/gtest",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||
|
||||
defines = []
|
||||
|
||||
if (rtc_prefer_fixed_point) {
|
||||
defines += [ "WEBRTC_AUDIOPROC_FIXED_PROFILE" ]
|
||||
} else {
|
||||
defines += [ "WEBRTC_AUDIOPROC_FLOAT_PROFILE" ]
|
||||
}
|
||||
|
||||
# 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",
|
||||
if (rtc_enable_protobuf) {
|
||||
defines += [ "WEBRTC_AUDIOPROC_DEBUG_DUMP" ]
|
||||
deps += [
|
||||
":audioproc_debug_proto",
|
||||
":audioproc_protobuf_utils",
|
||||
":audioproc_test_utils",
|
||||
":audioproc_unittest_proto",
|
||||
":optionally_built_submodule_creators",
|
||||
":rms_level",
|
||||
":runtime_settings_protobuf_utils",
|
||||
"../../api/audio:audio_frame_api",
|
||||
"../../api/audio:echo_control",
|
||||
"../../rtc_base:rtc_base_tests_utils",
|
||||
"../../rtc_base:rtc_task_queue",
|
||||
"aec_dump",
|
||||
"aec_dump:aec_dump_unittests",
|
||||
]
|
||||
absl_deps += [ "//third_party/abseil-cpp/absl/flags:flag" ]
|
||||
sources += [
|
||||
"audio_processing_impl_locking_unittest.cc",
|
||||
"audio_processing_impl_unittest.cc",
|
||||
"audio_processing_unittest.cc",
|
||||
"echo_control_mobile_bit_exact_unittest.cc",
|
||||
"echo_detector/circular_buffer_unittest.cc",
|
||||
"echo_detector/mean_variance_estimator_unittest.cc",
|
||||
"echo_detector/moving_max_unittest.cc",
|
||||
"echo_detector/normalized_covariance_estimator_unittest.cc",
|
||||
"gain_control_unittest.cc",
|
||||
"high_pass_filter_unittest.cc",
|
||||
"level_estimator_unittest.cc",
|
||||
"residual_echo_detector_unittest.cc",
|
||||
"rms_level_unittest.cc",
|
||||
"test/debug_dump_replayer.cc",
|
||||
"test/debug_dump_replayer.h",
|
||||
"test/debug_dump_test.cc",
|
||||
"test/echo_canceller_test_tools.cc",
|
||||
"test/echo_canceller_test_tools.h",
|
||||
"test/echo_canceller_test_tools_unittest.cc",
|
||||
"test/echo_control_mock.h",
|
||||
"test/test_utils.h",
|
||||
"voice_detection_unittest.cc",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
rtc_library("audio_processing_perf_tests") {
|
||||
testonly = true
|
||||
configs += [ ":apm_debug_dump" ]
|
||||
|
||||
sources = [ "audio_processing_performance_unittest.cc" ]
|
||||
deps = [
|
||||
":audio_processing",
|
||||
":audioproc_test_utils",
|
||||
"../../api:array_view",
|
||||
"../../rtc_base:protobuf_utils",
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
"../../system_wrappers",
|
||||
"../../test:perf_test",
|
||||
"../../test:test_support",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_library("analog_mic_simulation") {
|
||||
sources = [
|
||||
"test/fake_recording_device.cc",
|
||||
"test/fake_recording_device.h",
|
||||
]
|
||||
deps = [
|
||||
"../../api:array_view",
|
||||
"../../api/audio:audio_frame_api",
|
||||
"../../common_audio",
|
||||
"../../rtc_base:checks",
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
"../../rtc_base:safe_minmax",
|
||||
"agc:gain_map",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||
}
|
||||
|
||||
if (rtc_enable_protobuf) {
|
||||
rtc_library("audioproc_f_impl") {
|
||||
testonly = true
|
||||
configs += [ ":apm_debug_dump" ]
|
||||
sources = [
|
||||
"test/aec_dump_based_simulator.cc",
|
||||
"test/aec_dump_based_simulator.h",
|
||||
"test/api_call_statistics.cc",
|
||||
"test/api_call_statistics.h",
|
||||
"test/audio_processing_simulator.cc",
|
||||
"test/audio_processing_simulator.h",
|
||||
"test/audioproc_float_impl.cc",
|
||||
"test/audioproc_float_impl.h",
|
||||
"test/wav_based_simulator.cc",
|
||||
"test/wav_based_simulator.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":analog_mic_simulation",
|
||||
":api",
|
||||
":apm_logging",
|
||||
":audio_processing",
|
||||
":audioproc_debug_proto",
|
||||
":audioproc_protobuf_utils",
|
||||
":audioproc_test_utils",
|
||||
":runtime_settings_protobuf_utils",
|
||||
"../../api/audio:aec3_config_json",
|
||||
"../../api/audio:aec3_factory",
|
||||
"../../common_audio",
|
||||
"../../rtc_base:checks",
|
||||
"../../rtc_base:ignore_wundef",
|
||||
"../../rtc_base:protobuf_utils",
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
"../../rtc_base:rtc_json",
|
||||
"../../rtc_base:task_queue_for_test",
|
||||
"../../rtc_base/system:file_wrapper",
|
||||
"../../system_wrappers",
|
||||
"../../system_wrappers:field_trial",
|
||||
"../../test:test_support",
|
||||
"aec_dump",
|
||||
"aec_dump:aec_dump_impl",
|
||||
"//testing/gtest",
|
||||
]
|
||||
absl_deps = [
|
||||
"//third_party/abseil-cpp/absl/flags:flag",
|
||||
"//third_party/abseil-cpp/absl/flags:parse",
|
||||
"//third_party/abseil-cpp/absl/strings",
|
||||
"//third_party/abseil-cpp/absl/types:optional",
|
||||
]
|
||||
} # audioproc_f_impl
|
||||
}
|
||||
|
||||
if (rtc_enable_protobuf) {
|
||||
proto_library("audioproc_unittest_proto") {
|
||||
sources = [ "test/unittest.proto" ]
|
||||
proto_out_dir = "modules/audio_processing/test"
|
||||
}
|
||||
|
||||
rtc_library("audioproc_protobuf_utils") {
|
||||
sources = [
|
||||
"test/protobuf_utils.cc",
|
||||
"test/protobuf_utils.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":audioproc_debug_proto",
|
||||
"../../rtc_base:checks",
|
||||
"../../rtc_base:ignore_wundef",
|
||||
"../../rtc_base:protobuf_utils",
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
"../../rtc_base/system:arch",
|
||||
]
|
||||
}
|
||||
|
||||
configs += [ "../..:common_config" ]
|
||||
public_configs = [ "../..:common_inherited_config" ]
|
||||
rtc_library("runtime_settings_protobuf_utils") {
|
||||
testonly = true
|
||||
sources = [
|
||||
"test/runtime_setting_util.cc",
|
||||
"test/runtime_setting_util.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
"../../common_audio",
|
||||
]
|
||||
deps = [
|
||||
":api",
|
||||
":audioproc_debug_proto",
|
||||
":audioproc_protobuf_utils",
|
||||
"../../rtc_base:checks",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rtc_library("audioproc_test_utils") {
|
||||
visibility = [ "*" ]
|
||||
testonly = true
|
||||
sources = [
|
||||
"test/audio_buffer_tools.cc",
|
||||
"test/audio_buffer_tools.h",
|
||||
"test/audio_processing_builder_for_testing.cc",
|
||||
"test/audio_processing_builder_for_testing.h",
|
||||
"test/bitexactness_tools.cc",
|
||||
"test/bitexactness_tools.h",
|
||||
"test/performance_timer.cc",
|
||||
"test/performance_timer.h",
|
||||
"test/simulator_buffers.cc",
|
||||
"test/simulator_buffers.h",
|
||||
"test/test_utils.cc",
|
||||
"test/test_utils.h",
|
||||
]
|
||||
|
||||
configs += [ ":apm_debug_dump" ]
|
||||
|
||||
deps = [
|
||||
":api",
|
||||
":audio_buffer",
|
||||
":audio_processing",
|
||||
"../../api:array_view",
|
||||
"../../api/audio:audio_frame_api",
|
||||
"../../common_audio",
|
||||
"../../rtc_base:checks",
|
||||
"../../rtc_base:rtc_base_approved",
|
||||
"../../rtc_base/system:arch",
|
||||
"../../system_wrappers",
|
||||
"../../test:fileutils",
|
||||
"../../test:test_support",
|
||||
"../audio_coding:neteq_input_audio_tools",
|
||||
"//testing/gtest",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||
}
|
||||
|
@ -1,32 +0,0 @@
|
||||
/*
|
||||
* 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,129 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Specifies the interface for the AEC core.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_H_
|
||||
#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_CORE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#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 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
|
||||
// as long arrays of float, all the real parts followed by all the imaginary
|
||||
// ones (complex_t[SIZE] -> float[2][SIZE]). This allows SIMD optimizations and
|
||||
// is better than two arrays (one for the real parts and one for the imaginary
|
||||
// parts) as this other way would require two pointers instead of one and cause
|
||||
// extra register spilling. This also allows the offsets to be calculated at
|
||||
// compile time.
|
||||
|
||||
// Metrics
|
||||
enum {
|
||||
kOffsetLevel = -100
|
||||
};
|
||||
|
||||
typedef struct Stats {
|
||||
float instant;
|
||||
float average;
|
||||
float min;
|
||||
float max;
|
||||
float sum;
|
||||
float hisum;
|
||||
float himean;
|
||||
int counter;
|
||||
int hicounter;
|
||||
} Stats;
|
||||
|
||||
typedef struct AecCore AecCore;
|
||||
|
||||
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_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);
|
||||
|
||||
// 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_
|
@ -1,202 +0,0 @@
|
||||
/*
|
||||
* 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_
|
@ -1,774 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
@ -1,736 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
@ -1,731 +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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The core AEC algorithm, SSE2 version of speed-critical functions.
|
||||
*/
|
||||
|
||||
#include <emmintrin.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"
|
||||
|
||||
__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 FilterFarSSE2(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 __m128 xfBuf_re = _mm_loadu_ps(&aec->xfBuf[0][xPos + j]);
|
||||
const __m128 xfBuf_im = _mm_loadu_ps(&aec->xfBuf[1][xPos + j]);
|
||||
const __m128 wfBuf_re = _mm_loadu_ps(&aec->wfBuf[0][pos + j]);
|
||||
const __m128 wfBuf_im = _mm_loadu_ps(&aec->wfBuf[1][pos + j]);
|
||||
const __m128 yf_re = _mm_loadu_ps(&yf[0][j]);
|
||||
const __m128 yf_im = _mm_loadu_ps(&yf[1][j]);
|
||||
const __m128 a = _mm_mul_ps(xfBuf_re, wfBuf_re);
|
||||
const __m128 b = _mm_mul_ps(xfBuf_im, wfBuf_im);
|
||||
const __m128 c = _mm_mul_ps(xfBuf_re, wfBuf_im);
|
||||
const __m128 d = _mm_mul_ps(xfBuf_im, wfBuf_re);
|
||||
const __m128 e = _mm_sub_ps(a, b);
|
||||
const __m128 f = _mm_add_ps(c, d);
|
||||
const __m128 g = _mm_add_ps(yf_re, e);
|
||||
const __m128 h = _mm_add_ps(yf_im, f);
|
||||
_mm_storeu_ps(&yf[0][j], g);
|
||||
_mm_storeu_ps(&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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ScaleErrorSignalSSE2(AecCore* aec, float ef[2][PART_LEN1]) {
|
||||
const __m128 k1e_10f = _mm_set1_ps(1e-10f);
|
||||
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)
|
||||
for (i = 0; i + 3 < PART_LEN1; i += 4) {
|
||||
const __m128 xPow = _mm_loadu_ps(&aec->xPow[i]);
|
||||
const __m128 ef_re_base = _mm_loadu_ps(&ef[0][i]);
|
||||
const __m128 ef_im_base = _mm_loadu_ps(&ef[1][i]);
|
||||
|
||||
const __m128 xPowPlus = _mm_add_ps(xPow, k1e_10f);
|
||||
__m128 ef_re = _mm_div_ps(ef_re_base, xPowPlus);
|
||||
__m128 ef_im = _mm_div_ps(ef_im_base, xPowPlus);
|
||||
const __m128 ef_re2 = _mm_mul_ps(ef_re, ef_re);
|
||||
const __m128 ef_im2 = _mm_mul_ps(ef_im, ef_im);
|
||||
const __m128 ef_sum2 = _mm_add_ps(ef_re2, ef_im2);
|
||||
const __m128 absEf = _mm_sqrt_ps(ef_sum2);
|
||||
const __m128 bigger = _mm_cmpgt_ps(absEf, kThresh);
|
||||
__m128 absEfPlus = _mm_add_ps(absEf, k1e_10f);
|
||||
const __m128 absEfInv = _mm_div_ps(kThresh, absEfPlus);
|
||||
__m128 ef_re_if = _mm_mul_ps(ef_re, absEfInv);
|
||||
__m128 ef_im_if = _mm_mul_ps(ef_im, absEfInv);
|
||||
ef_re_if = _mm_and_ps(bigger, ef_re_if);
|
||||
ef_im_if = _mm_and_ps(bigger, ef_im_if);
|
||||
ef_re = _mm_andnot_ps(bigger, ef_re);
|
||||
ef_im = _mm_andnot_ps(bigger, ef_im);
|
||||
ef_re = _mm_or_ps(ef_re, ef_re_if);
|
||||
ef_im = _mm_or_ps(ef_im, ef_im_if);
|
||||
ef_re = _mm_mul_ps(ef_re, kMu);
|
||||
ef_im = _mm_mul_ps(ef_im, kMu);
|
||||
|
||||
_mm_storeu_ps(&ef[0][i], ef_re);
|
||||
_mm_storeu_ps(&ef[1][i], ef_im);
|
||||
}
|
||||
// scalar code for the remaining items.
|
||||
{
|
||||
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 (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 FilterAdaptationSSE2(AecCore* aec,
|
||||
float* fft,
|
||||
float ef[2][PART_LEN1]) {
|
||||
int i, j;
|
||||
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 >= num_partitions) {
|
||||
xPos -= num_partitions * PART_LEN1;
|
||||
}
|
||||
|
||||
// Process the whole array...
|
||||
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]);
|
||||
const __m128 ef_re = _mm_loadu_ps(&ef[0][j]);
|
||||
const __m128 ef_im = _mm_loadu_ps(&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 __m128 a = _mm_mul_ps(xfBuf_re, ef_re);
|
||||
const __m128 b = _mm_mul_ps(xfBuf_im, ef_im);
|
||||
const __m128 c = _mm_mul_ps(xfBuf_re, ef_im);
|
||||
const __m128 d = _mm_mul_ps(xfBuf_im, ef_re);
|
||||
const __m128 e = _mm_add_ps(a, b);
|
||||
const __m128 f = _mm_sub_ps(c, d);
|
||||
// Interleave real and imaginary parts.
|
||||
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);
|
||||
}
|
||||
// ... 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
|
||||
{
|
||||
float scale = 2.0f / PART_LEN2;
|
||||
const __m128 scale_ps = _mm_load_ps1(&scale);
|
||||
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);
|
||||
}
|
||||
}
|
||||
aec_rdft_forward_128(fft);
|
||||
|
||||
{
|
||||
float wt1 = aec->wfBuf[1][pos];
|
||||
aec->wfBuf[0][pos + PART_LEN] += fft[1];
|
||||
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));
|
||||
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);
|
||||
_mm_storeu_ps(&aec->wfBuf[1][pos + j], wtBuf_im);
|
||||
}
|
||||
aec->wfBuf[1][pos] = wt1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// 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.
|
||||
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));
|
||||
|
||||
// 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));
|
||||
|
||||
// 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));
|
||||
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_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_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_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);
|
||||
|
||||
// Combine parts.
|
||||
log2_a = _mm_add_ps(n, log2_y);
|
||||
}
|
||||
|
||||
// b * log2(a)
|
||||
b_log2_a = _mm_mul_ps(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].
|
||||
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));
|
||||
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 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));
|
||||
// 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));
|
||||
const __m128 exp2_y_2 = _mm_mul_ps(exp2_y_1, y);
|
||||
const __m128 exp2_y = _mm_add_ps(exp2_y_2, *((__m128*)C0));
|
||||
|
||||
// Combine parts.
|
||||
a_exp_b = _mm_mul_ps(exp2_y, two_n);
|
||||
}
|
||||
return a_exp_b;
|
||||
}
|
||||
|
||||
static void OverdriveAndSuppressSSE2(AecCore* aec,
|
||||
float hNl[PART_LEN1],
|
||||
const float hNlFb,
|
||||
float efw[2][PART_LEN1]) {
|
||||
int i;
|
||||
const __m128 vec_hNlFb = _mm_set1_ps(hNlFb);
|
||||
const __m128 vec_one = _mm_set1_ps(1.0f);
|
||||
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) {
|
||||
// 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_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_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);
|
||||
vec_hNl = mm_pow_ps(vec_hNl, vec_overDriveSm_overDriveCurve);
|
||||
_mm_storeu_ps(&hNl[i], vec_hNl);
|
||||
}
|
||||
|
||||
// Suppress error signal
|
||||
{
|
||||
__m128 vec_efw_re = _mm_loadu_ps(&efw[0][i]);
|
||||
__m128 vec_efw_im = _mm_loadu_ps(&efw[1][i]);
|
||||
vec_efw_re = _mm_mul_ps(vec_efw_re, vec_hNl);
|
||||
vec_efw_im = _mm_mul_ps(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 = _mm_mul_ps(vec_efw_im, vec_minus_one);
|
||||
_mm_storeu_ps(&efw[0][i], vec_efw_re);
|
||||
_mm_storeu_ps(&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;
|
||||
}
|
||||
}
|
||||
|
||||
__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;
|
||||
}
|
@ -1,589 +0,0 @@
|
||||
/*
|
||||
* http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html
|
||||
* Copyright Takuya OOURA, 1996-2001
|
||||
*
|
||||
* You may use, copy, modify and distribute this code for any purpose (include
|
||||
* commercial use) and without fee. Please refer to this package when you modify
|
||||
* this code.
|
||||
*
|
||||
* Changes by the WebRTC authors:
|
||||
* - Trivial type modifications.
|
||||
* - Minimal code subset to do rdft of length 128.
|
||||
* - Optimizations because of known length.
|
||||
*
|
||||
* All changes are covered by the WebRTC license and IP grant:
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/audio_processing/aec/aec_rdft.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// 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 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.
|
||||
*/
|
||||
|
||||
unsigned int j, j1, k, k1;
|
||||
float xr, xi, yr, yi;
|
||||
|
||||
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 + 0];
|
||||
xi = a[j1 + 1];
|
||||
yr = a[k1 + 0];
|
||||
yi = a[k1 + 1];
|
||||
a[j1 + 0] = yr;
|
||||
a[j1 + 1] = yi;
|
||||
a[k1 + 0] = xr;
|
||||
a[k1 + 1] = xi;
|
||||
j1 += 8;
|
||||
k1 += 16;
|
||||
xr = a[j1 + 0];
|
||||
xi = a[j1 + 1];
|
||||
yr = a[k1 + 0];
|
||||
yi = a[k1 + 1];
|
||||
a[j1 + 0] = yr;
|
||||
a[j1 + 1] = yi;
|
||||
a[k1 + 0] = xr;
|
||||
a[k1 + 1] = xi;
|
||||
j1 += 8;
|
||||
k1 -= 8;
|
||||
xr = a[j1 + 0];
|
||||
xi = a[j1 + 1];
|
||||
yr = a[k1 + 0];
|
||||
yi = a[k1 + 1];
|
||||
a[j1 + 0] = yr;
|
||||
a[j1 + 1] = yi;
|
||||
a[k1 + 0] = xr;
|
||||
a[k1 + 1] = xi;
|
||||
j1 += 8;
|
||||
k1 += 16;
|
||||
xr = a[j1 + 0];
|
||||
xi = a[j1 + 1];
|
||||
yr = a[k1 + 0];
|
||||
yi = a[k1 + 1];
|
||||
a[j1 + 0] = yr;
|
||||
a[j1 + 1] = yi;
|
||||
a[k1 + 0] = xr;
|
||||
a[k1 + 1] = xi;
|
||||
}
|
||||
j1 = 2 * k + 8 + ip[k];
|
||||
k1 = j1 + 8;
|
||||
xr = a[j1 + 0];
|
||||
xi = a[j1 + 1];
|
||||
yr = a[k1 + 0];
|
||||
yi = a[k1 + 1];
|
||||
a[j1 + 0] = yr;
|
||||
a[j1 + 1] = yi;
|
||||
a[k1 + 0] = xr;
|
||||
a[k1 + 1] = xi;
|
||||
}
|
||||
}
|
||||
|
||||
static void cft1st_128_C(float* a) {
|
||||
const int n = 128;
|
||||
int j, k1, k2;
|
||||
float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i;
|
||||
float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
|
||||
|
||||
// The processing of the first set of elements was simplified in C to avoid
|
||||
// some operations (multiplication by zero or one, addition of two elements
|
||||
// multiplied by the same weight, ...).
|
||||
x0r = a[0] + a[2];
|
||||
x0i = a[1] + a[3];
|
||||
x1r = a[0] - a[2];
|
||||
x1i = a[1] - a[3];
|
||||
x2r = a[4] + a[6];
|
||||
x2i = a[5] + a[7];
|
||||
x3r = a[4] - a[6];
|
||||
x3i = a[5] - a[7];
|
||||
a[0] = x0r + x2r;
|
||||
a[1] = x0i + x2i;
|
||||
a[4] = x0r - x2r;
|
||||
a[5] = x0i - x2i;
|
||||
a[2] = x1r - x3i;
|
||||
a[3] = x1i + x3r;
|
||||
a[6] = x1r + x3i;
|
||||
a[7] = x1i - x3r;
|
||||
wk1r = rdft_w[2];
|
||||
x0r = a[8] + a[10];
|
||||
x0i = a[9] + a[11];
|
||||
x1r = a[8] - a[10];
|
||||
x1i = a[9] - a[11];
|
||||
x2r = a[12] + a[14];
|
||||
x2i = a[13] + a[15];
|
||||
x3r = a[12] - a[14];
|
||||
x3i = a[13] - a[15];
|
||||
a[8] = x0r + x2r;
|
||||
a[9] = x0i + x2i;
|
||||
a[12] = x2i - x0i;
|
||||
a[13] = x0r - x2r;
|
||||
x0r = x1r - x3i;
|
||||
x0i = x1i + x3r;
|
||||
a[10] = wk1r * (x0r - x0i);
|
||||
a[11] = wk1r * (x0r + x0i);
|
||||
x0r = x3i + x1r;
|
||||
x0i = x3r - x1i;
|
||||
a[14] = wk1r * (x0i - x0r);
|
||||
a[15] = wk1r * (x0i + x0r);
|
||||
k1 = 0;
|
||||
for (j = 16; j < n; j += 16) {
|
||||
k1 += 2;
|
||||
k2 = 2 * k1;
|
||||
wk2r = rdft_w[k1 + 0];
|
||||
wk2i = rdft_w[k1 + 1];
|
||||
wk1r = rdft_w[k2 + 0];
|
||||
wk1i = rdft_w[k2 + 1];
|
||||
wk3r = rdft_wk3ri_first[k1 + 0];
|
||||
wk3i = rdft_wk3ri_first[k1 + 1];
|
||||
x0r = a[j + 0] + a[j + 2];
|
||||
x0i = a[j + 1] + a[j + 3];
|
||||
x1r = a[j + 0] - a[j + 2];
|
||||
x1i = a[j + 1] - a[j + 3];
|
||||
x2r = a[j + 4] + a[j + 6];
|
||||
x2i = a[j + 5] + a[j + 7];
|
||||
x3r = a[j + 4] - a[j + 6];
|
||||
x3i = a[j + 5] - a[j + 7];
|
||||
a[j + 0] = x0r + x2r;
|
||||
a[j + 1] = x0i + x2i;
|
||||
x0r -= x2r;
|
||||
x0i -= x2i;
|
||||
a[j + 4] = wk2r * x0r - wk2i * x0i;
|
||||
a[j + 5] = wk2r * x0i + wk2i * x0r;
|
||||
x0r = x1r - x3i;
|
||||
x0i = x1i + x3r;
|
||||
a[j + 2] = wk1r * x0r - wk1i * x0i;
|
||||
a[j + 3] = wk1r * x0i + wk1i * x0r;
|
||||
x0r = x1r + x3i;
|
||||
x0i = x1i - x3r;
|
||||
a[j + 6] = wk3r * x0r - wk3i * x0i;
|
||||
a[j + 7] = wk3r * x0i + wk3i * x0r;
|
||||
wk1r = rdft_w[k2 + 2];
|
||||
wk1i = rdft_w[k2 + 3];
|
||||
wk3r = rdft_wk3ri_second[k1 + 0];
|
||||
wk3i = rdft_wk3ri_second[k1 + 1];
|
||||
x0r = a[j + 8] + a[j + 10];
|
||||
x0i = a[j + 9] + a[j + 11];
|
||||
x1r = a[j + 8] - a[j + 10];
|
||||
x1i = a[j + 9] - a[j + 11];
|
||||
x2r = a[j + 12] + a[j + 14];
|
||||
x2i = a[j + 13] + a[j + 15];
|
||||
x3r = a[j + 12] - a[j + 14];
|
||||
x3i = a[j + 13] - a[j + 15];
|
||||
a[j + 8] = x0r + x2r;
|
||||
a[j + 9] = x0i + x2i;
|
||||
x0r -= x2r;
|
||||
x0i -= x2i;
|
||||
a[j + 12] = -wk2i * x0r - wk2r * x0i;
|
||||
a[j + 13] = -wk2i * x0i + wk2r * x0r;
|
||||
x0r = x1r - x3i;
|
||||
x0i = x1i + x3r;
|
||||
a[j + 10] = wk1r * x0r - wk1i * x0i;
|
||||
a[j + 11] = wk1r * x0i + wk1i * x0r;
|
||||
x0r = x1r + x3i;
|
||||
x0i = x1i - x3r;
|
||||
a[j + 14] = wk3r * x0r - wk3i * x0i;
|
||||
a[j + 15] = wk3r * x0i + wk3i * x0r;
|
||||
}
|
||||
}
|
||||
|
||||
static void cftmdl_128_C(float* a) {
|
||||
const int l = 8;
|
||||
const int n = 128;
|
||||
const int m = 32;
|
||||
int j0, j1, j2, j3, k, k1, k2, m2;
|
||||
float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i;
|
||||
float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
|
||||
|
||||
for (j0 = 0; j0 < l; j0 += 2) {
|
||||
j1 = j0 + 8;
|
||||
j2 = j0 + 16;
|
||||
j3 = j0 + 24;
|
||||
x0r = a[j0 + 0] + a[j1 + 0];
|
||||
x0i = a[j0 + 1] + a[j1 + 1];
|
||||
x1r = a[j0 + 0] - a[j1 + 0];
|
||||
x1i = a[j0 + 1] - a[j1 + 1];
|
||||
x2r = a[j2 + 0] + a[j3 + 0];
|
||||
x2i = a[j2 + 1] + a[j3 + 1];
|
||||
x3r = a[j2 + 0] - a[j3 + 0];
|
||||
x3i = a[j2 + 1] - a[j3 + 1];
|
||||
a[j0 + 0] = x0r + x2r;
|
||||
a[j0 + 1] = x0i + x2i;
|
||||
a[j2 + 0] = x0r - x2r;
|
||||
a[j2 + 1] = x0i - x2i;
|
||||
a[j1 + 0] = x1r - x3i;
|
||||
a[j1 + 1] = x1i + x3r;
|
||||
a[j3 + 0] = x1r + x3i;
|
||||
a[j3 + 1] = x1i - x3r;
|
||||
}
|
||||
wk1r = rdft_w[2];
|
||||
for (j0 = m; j0 < l + m; j0 += 2) {
|
||||
j1 = j0 + 8;
|
||||
j2 = j0 + 16;
|
||||
j3 = j0 + 24;
|
||||
x0r = a[j0 + 0] + a[j1 + 0];
|
||||
x0i = a[j0 + 1] + a[j1 + 1];
|
||||
x1r = a[j0 + 0] - a[j1 + 0];
|
||||
x1i = a[j0 + 1] - a[j1 + 1];
|
||||
x2r = a[j2 + 0] + a[j3 + 0];
|
||||
x2i = a[j2 + 1] + a[j3 + 1];
|
||||
x3r = a[j2 + 0] - a[j3 + 0];
|
||||
x3i = a[j2 + 1] - a[j3 + 1];
|
||||
a[j0 + 0] = x0r + x2r;
|
||||
a[j0 + 1] = x0i + x2i;
|
||||
a[j2 + 0] = x2i - x0i;
|
||||
a[j2 + 1] = x0r - x2r;
|
||||
x0r = x1r - x3i;
|
||||
x0i = x1i + x3r;
|
||||
a[j1 + 0] = wk1r * (x0r - x0i);
|
||||
a[j1 + 1] = wk1r * (x0r + x0i);
|
||||
x0r = x3i + x1r;
|
||||
x0i = x3r - x1i;
|
||||
a[j3 + 0] = wk1r * (x0i - x0r);
|
||||
a[j3 + 1] = wk1r * (x0i + x0r);
|
||||
}
|
||||
k1 = 0;
|
||||
m2 = 2 * m;
|
||||
for (k = m2; k < n; k += m2) {
|
||||
k1 += 2;
|
||||
k2 = 2 * k1;
|
||||
wk2r = rdft_w[k1 + 0];
|
||||
wk2i = rdft_w[k1 + 1];
|
||||
wk1r = rdft_w[k2 + 0];
|
||||
wk1i = rdft_w[k2 + 1];
|
||||
wk3r = rdft_wk3ri_first[k1 + 0];
|
||||
wk3i = rdft_wk3ri_first[k1 + 1];
|
||||
for (j0 = k; j0 < l + k; j0 += 2) {
|
||||
j1 = j0 + 8;
|
||||
j2 = j0 + 16;
|
||||
j3 = j0 + 24;
|
||||
x0r = a[j0 + 0] + a[j1 + 0];
|
||||
x0i = a[j0 + 1] + a[j1 + 1];
|
||||
x1r = a[j0 + 0] - a[j1 + 0];
|
||||
x1i = a[j0 + 1] - a[j1 + 1];
|
||||
x2r = a[j2 + 0] + a[j3 + 0];
|
||||
x2i = a[j2 + 1] + a[j3 + 1];
|
||||
x3r = a[j2 + 0] - a[j3 + 0];
|
||||
x3i = a[j2 + 1] - a[j3 + 1];
|
||||
a[j0 + 0] = x0r + x2r;
|
||||
a[j0 + 1] = x0i + x2i;
|
||||
x0r -= x2r;
|
||||
x0i -= x2i;
|
||||
a[j2 + 0] = wk2r * x0r - wk2i * x0i;
|
||||
a[j2 + 1] = wk2r * x0i + wk2i * x0r;
|
||||
x0r = x1r - x3i;
|
||||
x0i = x1i + x3r;
|
||||
a[j1 + 0] = wk1r * x0r - wk1i * x0i;
|
||||
a[j1 + 1] = wk1r * x0i + wk1i * x0r;
|
||||
x0r = x1r + x3i;
|
||||
x0i = x1i - x3r;
|
||||
a[j3 + 0] = wk3r * x0r - wk3i * x0i;
|
||||
a[j3 + 1] = wk3r * x0i + wk3i * x0r;
|
||||
}
|
||||
wk1r = rdft_w[k2 + 2];
|
||||
wk1i = rdft_w[k2 + 3];
|
||||
wk3r = rdft_wk3ri_second[k1 + 0];
|
||||
wk3i = rdft_wk3ri_second[k1 + 1];
|
||||
for (j0 = k + m; j0 < l + (k + m); j0 += 2) {
|
||||
j1 = j0 + 8;
|
||||
j2 = j0 + 16;
|
||||
j3 = j0 + 24;
|
||||
x0r = a[j0 + 0] + a[j1 + 0];
|
||||
x0i = a[j0 + 1] + a[j1 + 1];
|
||||
x1r = a[j0 + 0] - a[j1 + 0];
|
||||
x1i = a[j0 + 1] - a[j1 + 1];
|
||||
x2r = a[j2 + 0] + a[j3 + 0];
|
||||
x2i = a[j2 + 1] + a[j3 + 1];
|
||||
x3r = a[j2 + 0] - a[j3 + 0];
|
||||
x3i = a[j2 + 1] - a[j3 + 1];
|
||||
a[j0 + 0] = x0r + x2r;
|
||||
a[j0 + 1] = x0i + x2i;
|
||||
x0r -= x2r;
|
||||
x0i -= x2i;
|
||||
a[j2 + 0] = -wk2i * x0r - wk2r * x0i;
|
||||
a[j2 + 1] = -wk2i * x0i + wk2r * x0r;
|
||||
x0r = x1r - x3i;
|
||||
x0i = x1i + x3r;
|
||||
a[j1 + 0] = wk1r * x0r - wk1i * x0i;
|
||||
a[j1 + 1] = wk1r * x0i + wk1i * x0r;
|
||||
x0r = x1r + x3i;
|
||||
x0i = x1i - x3r;
|
||||
a[j3 + 0] = wk3r * x0r - wk3i * x0i;
|
||||
a[j3 + 1] = wk3r * x0i + wk3i * x0r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cftfsub_128_C(float* a) {
|
||||
int j, j1, j2, j3, l;
|
||||
float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
|
||||
|
||||
cft1st_128(a);
|
||||
cftmdl_128(a);
|
||||
l = 32;
|
||||
for (j = 0; j < l; j += 2) {
|
||||
j1 = j + l;
|
||||
j2 = j1 + l;
|
||||
j3 = j2 + l;
|
||||
x0r = a[j] + a[j1];
|
||||
x0i = a[j + 1] + a[j1 + 1];
|
||||
x1r = a[j] - a[j1];
|
||||
x1i = a[j + 1] - a[j1 + 1];
|
||||
x2r = a[j2] + a[j3];
|
||||
x2i = a[j2 + 1] + a[j3 + 1];
|
||||
x3r = a[j2] - a[j3];
|
||||
x3i = a[j2 + 1] - a[j3 + 1];
|
||||
a[j] = x0r + x2r;
|
||||
a[j + 1] = x0i + x2i;
|
||||
a[j2] = x0r - x2r;
|
||||
a[j2 + 1] = x0i - x2i;
|
||||
a[j1] = x1r - x3i;
|
||||
a[j1 + 1] = x1i + x3r;
|
||||
a[j3] = x1r + x3i;
|
||||
a[j3 + 1] = x1i - x3r;
|
||||
}
|
||||
}
|
||||
|
||||
static void cftbsub_128_C(float* a) {
|
||||
int j, j1, j2, j3, l;
|
||||
float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
|
||||
|
||||
cft1st_128(a);
|
||||
cftmdl_128(a);
|
||||
l = 32;
|
||||
|
||||
for (j = 0; j < l; j += 2) {
|
||||
j1 = j + l;
|
||||
j2 = j1 + l;
|
||||
j3 = j2 + l;
|
||||
x0r = a[j] + a[j1];
|
||||
x0i = -a[j + 1] - a[j1 + 1];
|
||||
x1r = a[j] - a[j1];
|
||||
x1i = -a[j + 1] + a[j1 + 1];
|
||||
x2r = a[j2] + a[j3];
|
||||
x2i = a[j2 + 1] + a[j3 + 1];
|
||||
x3r = a[j2] - a[j3];
|
||||
x3i = a[j2 + 1] - a[j3 + 1];
|
||||
a[j] = x0r + x2r;
|
||||
a[j + 1] = x0i - x2i;
|
||||
a[j2] = x0r - x2r;
|
||||
a[j2 + 1] = x0i + x2i;
|
||||
a[j1] = x1r - x3i;
|
||||
a[j1 + 1] = x1i - x3r;
|
||||
a[j3] = x1r + x3i;
|
||||
a[j3 + 1] = x1i + x3r;
|
||||
}
|
||||
}
|
||||
|
||||
static void rftfsub_128_C(float* a) {
|
||||
const float* c = rdft_w + 32;
|
||||
int j1, j2, k1, k2;
|
||||
float wkr, wki, xr, xi, yr, yi;
|
||||
|
||||
for (j1 = 1, j2 = 2; j2 < 64; j1 += 1, j2 += 2) {
|
||||
k2 = 128 - j2;
|
||||
k1 = 32 - j1;
|
||||
wkr = 0.5f - c[k1];
|
||||
wki = c[j1];
|
||||
xr = a[j2 + 0] - a[k2 + 0];
|
||||
xi = a[j2 + 1] + a[k2 + 1];
|
||||
yr = wkr * xr - wki * xi;
|
||||
yi = wkr * xi + wki * xr;
|
||||
a[j2 + 0] -= yr;
|
||||
a[j2 + 1] -= yi;
|
||||
a[k2 + 0] += yr;
|
||||
a[k2 + 1] -= yi;
|
||||
}
|
||||
}
|
||||
|
||||
static void rftbsub_128_C(float* a) {
|
||||
const float* c = rdft_w + 32;
|
||||
int j1, j2, k1, k2;
|
||||
float wkr, wki, xr, xi, yr, yi;
|
||||
|
||||
a[1] = -a[1];
|
||||
for (j1 = 1, j2 = 2; j2 < 64; j1 += 1, j2 += 2) {
|
||||
k2 = 128 - j2;
|
||||
k1 = 32 - j1;
|
||||
wkr = 0.5f - c[k1];
|
||||
wki = c[j1];
|
||||
xr = a[j2 + 0] - a[k2 + 0];
|
||||
xi = a[j2 + 1] + a[k2 + 1];
|
||||
yr = wkr * xr + wki * xi;
|
||||
yi = wkr * xi - wki * xr;
|
||||
a[j2 + 0] = a[j2 + 0] - yr;
|
||||
a[j2 + 1] = yi - a[j2 + 1];
|
||||
a[k2 + 0] = yr + a[k2 + 0];
|
||||
a[k2 + 1] = yi - a[k2 + 1];
|
||||
}
|
||||
a[65] = -a[65];
|
||||
}
|
||||
|
||||
void aec_rdft_forward_128(float* a) {
|
||||
float xi;
|
||||
bitrv2_128(a);
|
||||
cftfsub_128(a);
|
||||
rftfsub_128(a);
|
||||
xi = a[0] - a[1];
|
||||
a[0] += a[1];
|
||||
a[1] = xi;
|
||||
}
|
||||
|
||||
void aec_rdft_inverse_128(float* a) {
|
||||
a[1] = 0.5f * (a[0] - a[1]);
|
||||
a[0] -= a[1];
|
||||
rftbsub_128(a);
|
||||
bitrv2_128(a);
|
||||
cftbsub_128(a);
|
||||
}
|
||||
|
||||
// code path selection
|
||||
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)) {
|
||||
aec_rdft_init_sse2();
|
||||
}
|
||||
#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
|
||||
}
|
@ -1,61 +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_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
|
||||
#include <emmintrin.h>
|
||||
static __inline __m128 _mm_castsi128_ps(__m128i a) { return *(__m128*)&a; }
|
||||
static __inline __m128i _mm_castps_si128(__m128 a) { return *(__m128i*)&a; }
|
||||
#endif
|
||||
|
||||
// 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 (*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);
|
||||
|
||||
#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_
|
File diff suppressed because it is too large
Load Diff
@ -1,355 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
@ -1,427 +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.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/audio_processing/aec/aec_rdft.h"
|
||||
|
||||
#include <emmintrin.h>
|
||||
|
||||
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) {
|
||||
const __m128 mm_swap_sign = _mm_load_ps(k_swap_sign);
|
||||
int j, k2;
|
||||
|
||||
for (k2 = 0, j = 0; j < 128; j += 16, k2 += 4) {
|
||||
__m128 a00v = _mm_loadu_ps(&a[j + 0]);
|
||||
__m128 a04v = _mm_loadu_ps(&a[j + 4]);
|
||||
__m128 a08v = _mm_loadu_ps(&a[j + 8]);
|
||||
__m128 a12v = _mm_loadu_ps(&a[j + 12]);
|
||||
__m128 a01v = _mm_shuffle_ps(a00v, a08v, _MM_SHUFFLE(1, 0, 1, 0));
|
||||
__m128 a23v = _mm_shuffle_ps(a00v, a08v, _MM_SHUFFLE(3, 2, 3, 2));
|
||||
__m128 a45v = _mm_shuffle_ps(a04v, a12v, _MM_SHUFFLE(1, 0, 1, 0));
|
||||
__m128 a67v = _mm_shuffle_ps(a04v, a12v, _MM_SHUFFLE(3, 2, 3, 2));
|
||||
|
||||
const __m128 wk1rv = _mm_load_ps(&rdft_wk1r[k2]);
|
||||
const __m128 wk1iv = _mm_load_ps(&rdft_wk1i[k2]);
|
||||
const __m128 wk2rv = _mm_load_ps(&rdft_wk2r[k2]);
|
||||
const __m128 wk2iv = _mm_load_ps(&rdft_wk2i[k2]);
|
||||
const __m128 wk3rv = _mm_load_ps(&rdft_wk3r[k2]);
|
||||
const __m128 wk3iv = _mm_load_ps(&rdft_wk3i[k2]);
|
||||
__m128 x0v = _mm_add_ps(a01v, a23v);
|
||||
const __m128 x1v = _mm_sub_ps(a01v, a23v);
|
||||
const __m128 x2v = _mm_add_ps(a45v, a67v);
|
||||
const __m128 x3v = _mm_sub_ps(a45v, a67v);
|
||||
__m128 x0w;
|
||||
a01v = _mm_add_ps(x0v, x2v);
|
||||
x0v = _mm_sub_ps(x0v, x2v);
|
||||
x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
{
|
||||
const __m128 a45_0v = _mm_mul_ps(wk2rv, x0v);
|
||||
const __m128 a45_1v = _mm_mul_ps(wk2iv, x0w);
|
||||
a45v = _mm_add_ps(a45_0v, a45_1v);
|
||||
}
|
||||
{
|
||||
__m128 a23_0v, a23_1v;
|
||||
const __m128 x3w = _mm_shuffle_ps(x3v, x3v, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
const __m128 x3s = _mm_mul_ps(mm_swap_sign, x3w);
|
||||
x0v = _mm_add_ps(x1v, x3s);
|
||||
x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
a23_0v = _mm_mul_ps(wk1rv, x0v);
|
||||
a23_1v = _mm_mul_ps(wk1iv, x0w);
|
||||
a23v = _mm_add_ps(a23_0v, a23_1v);
|
||||
|
||||
x0v = _mm_sub_ps(x1v, x3s);
|
||||
x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0, 1));
|
||||
}
|
||||
{
|
||||
const __m128 a67_0v = _mm_mul_ps(wk3rv, x0v);
|
||||
const __m128 a67_1v = _mm_mul_ps(wk3iv, x0w);
|
||||
a67v = _mm_add_ps(a67_0v, a67_1v);
|
||||
}
|
||||
|
||||
a00v = _mm_shuffle_ps(a01v, a23v, _MM_SHUFFLE(1, 0, 1, 0));
|
||||
a04v = _mm_shuffle_ps(a45v, a67v, _MM_SHUFFLE(1, 0, 1, 0));
|
||||
a08v = _mm_shuffle_ps(a01v, a23v, _MM_SHUFFLE(3, 2, 3, 2));
|
||||
a12v = _mm_shuffle_ps(a45v, a67v, _MM_SHUFFLE(3, 2, 3, 2));
|
||||
_mm_storeu_ps(&a[j + 0], a00v);
|
||||
_mm_storeu_ps(&a[j + 4], a04v);
|
||||
_mm_storeu_ps(&a[j + 8], a08v);
|
||||
_mm_storeu_ps(&a[j + 12], a12v);
|
||||
}
|
||||
}
|
||||
|
||||
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_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]);
|
||||
const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]);
|
||||
const __m128 a_00_32 = _mm_shuffle_ps(_mm_castsi128_ps(a_00),
|
||||
_mm_castsi128_ps(a_32),
|
||||
_MM_SHUFFLE(1, 0, 1, 0));
|
||||
const __m128 a_08_40 = _mm_shuffle_ps(_mm_castsi128_ps(a_08),
|
||||
_mm_castsi128_ps(a_40),
|
||||
_MM_SHUFFLE(1, 0, 1, 0));
|
||||
__m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40);
|
||||
const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40);
|
||||
|
||||
const __m128i a_16 = _mm_loadl_epi64((__m128i*)&a[j0 + 16]);
|
||||
const __m128i a_24 = _mm_loadl_epi64((__m128i*)&a[j0 + 24]);
|
||||
const __m128i a_48 = _mm_loadl_epi64((__m128i*)&a[j0 + 48]);
|
||||
const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]);
|
||||
const __m128 a_16_48 = _mm_shuffle_ps(_mm_castsi128_ps(a_16),
|
||||
_mm_castsi128_ps(a_48),
|
||||
_MM_SHUFFLE(1, 0, 1, 0));
|
||||
const __m128 a_24_56 = _mm_shuffle_ps(_mm_castsi128_ps(a_24),
|
||||
_mm_castsi128_ps(a_56),
|
||||
_MM_SHUFFLE(1, 0, 1, 0));
|
||||
const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56);
|
||||
const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56);
|
||||
|
||||
const __m128 xx0 = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
|
||||
const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps(_mm_shuffle_epi32(
|
||||
_mm_castps_si128(x3r0_3i0_3r1_x3i1), _MM_SHUFFLE(2, 3, 0, 1)));
|
||||
const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1);
|
||||
const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped);
|
||||
const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped);
|
||||
|
||||
const __m128 yy0 =
|
||||
_mm_shuffle_ps(x1_x3_add, x1_x3_sub, _MM_SHUFFLE(2, 2, 2, 2));
|
||||
const __m128 yy1 =
|
||||
_mm_shuffle_ps(x1_x3_add, x1_x3_sub, _MM_SHUFFLE(3, 3, 3, 3));
|
||||
const __m128 yy2 = _mm_mul_ps(mm_swap_sign, yy1);
|
||||
const __m128 yy3 = _mm_add_ps(yy0, yy2);
|
||||
const __m128 yy4 = _mm_mul_ps(wk1rv, yy3);
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx0));
|
||||
_mm_storel_epi64(
|
||||
(__m128i*)&a[j0 + 32],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx0), _MM_SHUFFLE(3, 2, 3, 2)));
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 16], _mm_castps_si128(xx1));
|
||||
_mm_storel_epi64(
|
||||
(__m128i*)&a[j0 + 48],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx1), _MM_SHUFFLE(2, 3, 2, 3)));
|
||||
a[j0 + 48] = -a[j0 + 48];
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 8], _mm_castps_si128(x1_x3_add));
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 24], _mm_castps_si128(x1_x3_sub));
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 40], _mm_castps_si128(yy4));
|
||||
_mm_storel_epi64(
|
||||
(__m128i*)&a[j0 + 56],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(yy4), _MM_SHUFFLE(2, 3, 2, 3)));
|
||||
}
|
||||
|
||||
{
|
||||
int k = 64;
|
||||
int k1 = 2;
|
||||
int k2 = 2 * k1;
|
||||
const __m128 wk2rv = _mm_load_ps(&rdft_wk2r[k2 + 0]);
|
||||
const __m128 wk2iv = _mm_load_ps(&rdft_wk2i[k2 + 0]);
|
||||
const __m128 wk1iv = _mm_load_ps(&rdft_wk1i[k2 + 0]);
|
||||
const __m128 wk3rv = _mm_load_ps(&rdft_wk3r[k2 + 0]);
|
||||
const __m128 wk3iv = _mm_load_ps(&rdft_wk3i[k2 + 0]);
|
||||
wk1rv = _mm_load_ps(&rdft_wk1r[k2 + 0]);
|
||||
for (j0 = k; j0 < l + k; j0 += 2) {
|
||||
const __m128i a_00 = _mm_loadl_epi64((__m128i*)&a[j0 + 0]);
|
||||
const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]);
|
||||
const __m128i a_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]);
|
||||
const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]);
|
||||
const __m128 a_00_32 = _mm_shuffle_ps(_mm_castsi128_ps(a_00),
|
||||
_mm_castsi128_ps(a_32),
|
||||
_MM_SHUFFLE(1, 0, 1, 0));
|
||||
const __m128 a_08_40 = _mm_shuffle_ps(_mm_castsi128_ps(a_08),
|
||||
_mm_castsi128_ps(a_40),
|
||||
_MM_SHUFFLE(1, 0, 1, 0));
|
||||
__m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40);
|
||||
const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40);
|
||||
|
||||
const __m128i a_16 = _mm_loadl_epi64((__m128i*)&a[j0 + 16]);
|
||||
const __m128i a_24 = _mm_loadl_epi64((__m128i*)&a[j0 + 24]);
|
||||
const __m128i a_48 = _mm_loadl_epi64((__m128i*)&a[j0 + 48]);
|
||||
const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]);
|
||||
const __m128 a_16_48 = _mm_shuffle_ps(_mm_castsi128_ps(a_16),
|
||||
_mm_castsi128_ps(a_48),
|
||||
_MM_SHUFFLE(1, 0, 1, 0));
|
||||
const __m128 a_24_56 = _mm_shuffle_ps(_mm_castsi128_ps(a_24),
|
||||
_mm_castsi128_ps(a_56),
|
||||
_MM_SHUFFLE(1, 0, 1, 0));
|
||||
const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56);
|
||||
const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56);
|
||||
|
||||
const __m128 xx = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1);
|
||||
const __m128 xx2 = _mm_mul_ps(xx1, wk2rv);
|
||||
const __m128 xx3 =
|
||||
_mm_mul_ps(wk2iv,
|
||||
_mm_castsi128_ps(_mm_shuffle_epi32(
|
||||
_mm_castps_si128(xx1), _MM_SHUFFLE(2, 3, 0, 1))));
|
||||
const __m128 xx4 = _mm_add_ps(xx2, xx3);
|
||||
|
||||
const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps(_mm_shuffle_epi32(
|
||||
_mm_castps_si128(x3r0_3i0_3r1_x3i1), _MM_SHUFFLE(2, 3, 0, 1)));
|
||||
const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1);
|
||||
const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped);
|
||||
const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped);
|
||||
|
||||
const __m128 xx10 = _mm_mul_ps(x1_x3_add, wk1rv);
|
||||
const __m128 xx11 = _mm_mul_ps(
|
||||
wk1iv,
|
||||
_mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_add),
|
||||
_MM_SHUFFLE(2, 3, 0, 1))));
|
||||
const __m128 xx12 = _mm_add_ps(xx10, xx11);
|
||||
|
||||
const __m128 xx20 = _mm_mul_ps(x1_x3_sub, wk3rv);
|
||||
const __m128 xx21 = _mm_mul_ps(
|
||||
wk3iv,
|
||||
_mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_sub),
|
||||
_MM_SHUFFLE(2, 3, 0, 1))));
|
||||
const __m128 xx22 = _mm_add_ps(xx20, xx21);
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx));
|
||||
_mm_storel_epi64(
|
||||
(__m128i*)&a[j0 + 32],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx), _MM_SHUFFLE(3, 2, 3, 2)));
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 16], _mm_castps_si128(xx4));
|
||||
_mm_storel_epi64(
|
||||
(__m128i*)&a[j0 + 48],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx4), _MM_SHUFFLE(3, 2, 3, 2)));
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 8], _mm_castps_si128(xx12));
|
||||
_mm_storel_epi64(
|
||||
(__m128i*)&a[j0 + 40],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx12), _MM_SHUFFLE(3, 2, 3, 2)));
|
||||
|
||||
_mm_storel_epi64((__m128i*)&a[j0 + 24], _mm_castps_si128(xx22));
|
||||
_mm_storel_epi64(
|
||||
(__m128i*)&a[j0 + 56],
|
||||
_mm_shuffle_epi32(_mm_castps_si128(xx22), _MM_SHUFFLE(3, 2, 3, 2)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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};
|
||||
const __m128 mm_half = _mm_load_ps(k_half);
|
||||
|
||||
// Vectorized code (four at once).
|
||||
// Note: commented number are indexes for the first iteration of the loop.
|
||||
for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) {
|
||||
// Load 'wk'.
|
||||
const __m128 c_j1 = _mm_loadu_ps(&c[j1]); // 1, 2, 3, 4,
|
||||
const __m128 c_k1 = _mm_loadu_ps(&c[29 - j1]); // 28, 29, 30, 31,
|
||||
const __m128 wkrt = _mm_sub_ps(mm_half, c_k1); // 28, 29, 30, 31,
|
||||
const __m128 wkr_ =
|
||||
_mm_shuffle_ps(wkrt, wkrt, _MM_SHUFFLE(0, 1, 2, 3)); // 31, 30, 29, 28,
|
||||
const __m128 wki_ = c_j1; // 1, 2, 3, 4,
|
||||
// Load and shuffle 'a'.
|
||||
const __m128 a_j2_0 = _mm_loadu_ps(&a[0 + j2]); // 2, 3, 4, 5,
|
||||
const __m128 a_j2_4 = _mm_loadu_ps(&a[4 + j2]); // 6, 7, 8, 9,
|
||||
const __m128 a_k2_0 = _mm_loadu_ps(&a[122 - j2]); // 120, 121, 122, 123,
|
||||
const __m128 a_k2_4 = _mm_loadu_ps(&a[126 - j2]); // 124, 125, 126, 127,
|
||||
const __m128 a_j2_p0 = _mm_shuffle_ps(
|
||||
a_j2_0, a_j2_4, _MM_SHUFFLE(2, 0, 2, 0)); // 2, 4, 6, 8,
|
||||
const __m128 a_j2_p1 = _mm_shuffle_ps(
|
||||
a_j2_0, a_j2_4, _MM_SHUFFLE(3, 1, 3, 1)); // 3, 5, 7, 9,
|
||||
const __m128 a_k2_p0 = _mm_shuffle_ps(
|
||||
a_k2_4, a_k2_0, _MM_SHUFFLE(0, 2, 0, 2)); // 126, 124, 122, 120,
|
||||
const __m128 a_k2_p1 = _mm_shuffle_ps(
|
||||
a_k2_4, a_k2_0, _MM_SHUFFLE(1, 3, 1, 3)); // 127, 125, 123, 121,
|
||||
// Calculate 'x'.
|
||||
const __m128 xr_ = _mm_sub_ps(a_j2_p0, a_k2_p0);
|
||||
// 2-126, 4-124, 6-122, 8-120,
|
||||
const __m128 xi_ = _mm_add_ps(a_j2_p1, a_k2_p1);
|
||||
// 3-127, 5-125, 7-123, 9-121,
|
||||
// Calculate product into 'y'.
|
||||
// yr = wkr * xr - wki * xi;
|
||||
// yi = wkr * xi + wki * xr;
|
||||
const __m128 a_ = _mm_mul_ps(wkr_, xr_);
|
||||
const __m128 b_ = _mm_mul_ps(wki_, xi_);
|
||||
const __m128 c_ = _mm_mul_ps(wkr_, xi_);
|
||||
const __m128 d_ = _mm_mul_ps(wki_, xr_);
|
||||
const __m128 yr_ = _mm_sub_ps(a_, b_); // 2-126, 4-124, 6-122, 8-120,
|
||||
const __m128 yi_ = _mm_add_ps(c_, d_); // 3-127, 5-125, 7-123, 9-121,
|
||||
// Update 'a'.
|
||||
// a[j2 + 0] -= yr;
|
||||
// a[j2 + 1] -= yi;
|
||||
// a[k2 + 0] += yr;
|
||||
// a[k2 + 1] -= yi;
|
||||
const __m128 a_j2_p0n = _mm_sub_ps(a_j2_p0, yr_); // 2, 4, 6, 8,
|
||||
const __m128 a_j2_p1n = _mm_sub_ps(a_j2_p1, yi_); // 3, 5, 7, 9,
|
||||
const __m128 a_k2_p0n = _mm_add_ps(a_k2_p0, yr_); // 126, 124, 122, 120,
|
||||
const __m128 a_k2_p1n = _mm_sub_ps(a_k2_p1, yi_); // 127, 125, 123, 121,
|
||||
// Shuffle in right order and store.
|
||||
const __m128 a_j2_0n = _mm_unpacklo_ps(a_j2_p0n, a_j2_p1n);
|
||||
// 2, 3, 4, 5,
|
||||
const __m128 a_j2_4n = _mm_unpackhi_ps(a_j2_p0n, a_j2_p1n);
|
||||
// 6, 7, 8, 9,
|
||||
const __m128 a_k2_0nt = _mm_unpackhi_ps(a_k2_p0n, a_k2_p1n);
|
||||
// 122, 123, 120, 121,
|
||||
const __m128 a_k2_4nt = _mm_unpacklo_ps(a_k2_p0n, a_k2_p1n);
|
||||
// 126, 127, 124, 125,
|
||||
const __m128 a_k2_0n = _mm_shuffle_ps(
|
||||
a_k2_0nt, a_k2_0nt, _MM_SHUFFLE(1, 0, 3, 2)); // 120, 121, 122, 123,
|
||||
const __m128 a_k2_4n = _mm_shuffle_ps(
|
||||
a_k2_4nt, a_k2_4nt, _MM_SHUFFLE(1, 0, 3, 2)); // 124, 125, 126, 127,
|
||||
_mm_storeu_ps(&a[0 + j2], a_j2_0n);
|
||||
_mm_storeu_ps(&a[4 + j2], a_j2_4n);
|
||||
_mm_storeu_ps(&a[122 - j2], a_k2_0n);
|
||||
_mm_storeu_ps(&a[126 - j2], a_k2_4n);
|
||||
}
|
||||
// Scalar code for the remaining items.
|
||||
for (; j2 < 64; j1 += 1, j2 += 2) {
|
||||
k2 = 128 - j2;
|
||||
k1 = 32 - j1;
|
||||
wkr = 0.5f - c[k1];
|
||||
wki = c[j1];
|
||||
xr = a[j2 + 0] - a[k2 + 0];
|
||||
xi = a[j2 + 1] + a[k2 + 1];
|
||||
yr = wkr * xr - wki * xi;
|
||||
yi = wkr * xi + wki * xr;
|
||||
a[j2 + 0] -= yr;
|
||||
a[j2 + 1] -= yi;
|
||||
a[k2 + 0] += yr;
|
||||
a[k2 + 1] -= yi;
|
||||
}
|
||||
}
|
||||
|
||||
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};
|
||||
const __m128 mm_half = _mm_load_ps(k_half);
|
||||
|
||||
a[1] = -a[1];
|
||||
// Vectorized code (four at once).
|
||||
// Note: commented number are indexes for the first iteration of the loop.
|
||||
for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) {
|
||||
// Load 'wk'.
|
||||
const __m128 c_j1 = _mm_loadu_ps(&c[j1]); // 1, 2, 3, 4,
|
||||
const __m128 c_k1 = _mm_loadu_ps(&c[29 - j1]); // 28, 29, 30, 31,
|
||||
const __m128 wkrt = _mm_sub_ps(mm_half, c_k1); // 28, 29, 30, 31,
|
||||
const __m128 wkr_ =
|
||||
_mm_shuffle_ps(wkrt, wkrt, _MM_SHUFFLE(0, 1, 2, 3)); // 31, 30, 29, 28,
|
||||
const __m128 wki_ = c_j1; // 1, 2, 3, 4,
|
||||
// Load and shuffle 'a'.
|
||||
const __m128 a_j2_0 = _mm_loadu_ps(&a[0 + j2]); // 2, 3, 4, 5,
|
||||
const __m128 a_j2_4 = _mm_loadu_ps(&a[4 + j2]); // 6, 7, 8, 9,
|
||||
const __m128 a_k2_0 = _mm_loadu_ps(&a[122 - j2]); // 120, 121, 122, 123,
|
||||
const __m128 a_k2_4 = _mm_loadu_ps(&a[126 - j2]); // 124, 125, 126, 127,
|
||||
const __m128 a_j2_p0 = _mm_shuffle_ps(
|
||||
a_j2_0, a_j2_4, _MM_SHUFFLE(2, 0, 2, 0)); // 2, 4, 6, 8,
|
||||
const __m128 a_j2_p1 = _mm_shuffle_ps(
|
||||
a_j2_0, a_j2_4, _MM_SHUFFLE(3, 1, 3, 1)); // 3, 5, 7, 9,
|
||||
const __m128 a_k2_p0 = _mm_shuffle_ps(
|
||||
a_k2_4, a_k2_0, _MM_SHUFFLE(0, 2, 0, 2)); // 126, 124, 122, 120,
|
||||
const __m128 a_k2_p1 = _mm_shuffle_ps(
|
||||
a_k2_4, a_k2_0, _MM_SHUFFLE(1, 3, 1, 3)); // 127, 125, 123, 121,
|
||||
// Calculate 'x'.
|
||||
const __m128 xr_ = _mm_sub_ps(a_j2_p0, a_k2_p0);
|
||||
// 2-126, 4-124, 6-122, 8-120,
|
||||
const __m128 xi_ = _mm_add_ps(a_j2_p1, a_k2_p1);
|
||||
// 3-127, 5-125, 7-123, 9-121,
|
||||
// Calculate product into 'y'.
|
||||
// yr = wkr * xr + wki * xi;
|
||||
// yi = wkr * xi - wki * xr;
|
||||
const __m128 a_ = _mm_mul_ps(wkr_, xr_);
|
||||
const __m128 b_ = _mm_mul_ps(wki_, xi_);
|
||||
const __m128 c_ = _mm_mul_ps(wkr_, xi_);
|
||||
const __m128 d_ = _mm_mul_ps(wki_, xr_);
|
||||
const __m128 yr_ = _mm_add_ps(a_, b_); // 2-126, 4-124, 6-122, 8-120,
|
||||
const __m128 yi_ = _mm_sub_ps(c_, d_); // 3-127, 5-125, 7-123, 9-121,
|
||||
// Update 'a'.
|
||||
// a[j2 + 0] = a[j2 + 0] - yr;
|
||||
// a[j2 + 1] = yi - a[j2 + 1];
|
||||
// a[k2 + 0] = yr + a[k2 + 0];
|
||||
// a[k2 + 1] = yi - a[k2 + 1];
|
||||
const __m128 a_j2_p0n = _mm_sub_ps(a_j2_p0, yr_); // 2, 4, 6, 8,
|
||||
const __m128 a_j2_p1n = _mm_sub_ps(yi_, a_j2_p1); // 3, 5, 7, 9,
|
||||
const __m128 a_k2_p0n = _mm_add_ps(a_k2_p0, yr_); // 126, 124, 122, 120,
|
||||
const __m128 a_k2_p1n = _mm_sub_ps(yi_, a_k2_p1); // 127, 125, 123, 121,
|
||||
// Shuffle in right order and store.
|
||||
const __m128 a_j2_0n = _mm_unpacklo_ps(a_j2_p0n, a_j2_p1n);
|
||||
// 2, 3, 4, 5,
|
||||
const __m128 a_j2_4n = _mm_unpackhi_ps(a_j2_p0n, a_j2_p1n);
|
||||
// 6, 7, 8, 9,
|
||||
const __m128 a_k2_0nt = _mm_unpackhi_ps(a_k2_p0n, a_k2_p1n);
|
||||
// 122, 123, 120, 121,
|
||||
const __m128 a_k2_4nt = _mm_unpacklo_ps(a_k2_p0n, a_k2_p1n);
|
||||
// 126, 127, 124, 125,
|
||||
const __m128 a_k2_0n = _mm_shuffle_ps(
|
||||
a_k2_0nt, a_k2_0nt, _MM_SHUFFLE(1, 0, 3, 2)); // 120, 121, 122, 123,
|
||||
const __m128 a_k2_4n = _mm_shuffle_ps(
|
||||
a_k2_4nt, a_k2_4nt, _MM_SHUFFLE(1, 0, 3, 2)); // 124, 125, 126, 127,
|
||||
_mm_storeu_ps(&a[0 + j2], a_j2_0n);
|
||||
_mm_storeu_ps(&a[4 + j2], a_j2_4n);
|
||||
_mm_storeu_ps(&a[122 - j2], a_k2_0n);
|
||||
_mm_storeu_ps(&a[126 - j2], a_k2_4n);
|
||||
}
|
||||
// Scalar code for the remaining items.
|
||||
for (; j2 < 64; j1 += 1, j2 += 2) {
|
||||
k2 = 128 - j2;
|
||||
k1 = 32 - j1;
|
||||
wkr = 0.5f - c[k1];
|
||||
wki = c[j1];
|
||||
xr = a[j2 + 0] - a[k2 + 0];
|
||||
xi = a[j2 + 1] + a[k2 + 1];
|
||||
yr = wkr * xr + wki * xi;
|
||||
yi = wkr * xi - wki * xr;
|
||||
a[j2 + 0] = a[j2 + 0] - yr;
|
||||
a[j2 + 1] = yi - a[j2 + 1];
|
||||
a[k2 + 0] = yr + a[k2 + 0];
|
||||
a[k2 + 1] = yi - a[k2 + 1];
|
||||
}
|
||||
a[65] = -a[65];
|
||||
}
|
||||
|
||||
void aec_rdft_init_sse2(void) {
|
||||
cft1st_128 = cft1st_128_SSE2;
|
||||
cftmdl_128 = cftmdl_128_SSE2;
|
||||
rftfsub_128 = rftfsub_128_SSE2;
|
||||
rftbsub_128 = rftbsub_128_SSE2;
|
||||
}
|
@ -1,209 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* 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_
|
@ -1,923 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Contains the API functions for the AEC.
|
||||
*/
|
||||
#include "webrtc/modules/audio_processing/aec/include/echo_cancellation.h"
|
||||
|
||||
#include <math.h>
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "webrtc/common_audio/ring_buffer.h"
|
||||
#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_core.h"
|
||||
#include "webrtc/modules/audio_processing/aec/aec_resampler.h"
|
||||
#include "webrtc/modules/audio_processing/aec/echo_cancellation_internal.h"
|
||||
#include "webrtc/typedefs.h"
|
||||
|
||||
// Measured delays [ms]
|
||||
// Device Chrome GTP
|
||||
// MacBook Air 10
|
||||
// MacBook Retina 10 100
|
||||
// MacPro 30?
|
||||
//
|
||||
// Win7 Desktop 70 80?
|
||||
// Win7 T430s 110
|
||||
// Win8 T420s 70
|
||||
//
|
||||
// Daisy 50
|
||||
// Pixel (w/ preproc?) 240
|
||||
// Pixel (w/o preproc?) 110 110
|
||||
|
||||
// The extended filter mode gives us the flexibility to ignore the system's
|
||||
// reported delays. We do this for platforms which we believe provide results
|
||||
// which are incompatible with the AEC's expectations. Based on measurements
|
||||
// (some provided above) we set a conservative (i.e. lower than measured)
|
||||
// fixed delay.
|
||||
//
|
||||
// WEBRTC_UNTRUSTED_DELAY will only have an impact when |extended_filter_mode|
|
||||
// is enabled. See the note along with |DelayCorrection| in
|
||||
// echo_cancellation_impl.h for more details on the mode.
|
||||
//
|
||||
// Justification:
|
||||
// Chromium/Mac: Here, the true latency is so low (~10-20 ms), that it plays
|
||||
// havoc with the AEC's buffering. To avoid this, we set a fixed delay of 20 ms
|
||||
// and then compensate by rewinding by 10 ms (in wideband) through
|
||||
// kDelayDiffOffsetSamples. This trick does not seem to work for larger rewind
|
||||
// values, but fortunately this is sufficient.
|
||||
//
|
||||
// Chromium/Linux(ChromeOS): The values we get on this platform don't correspond
|
||||
// well to reality. The variance doesn't match the AEC's buffer changes, and the
|
||||
// bulk values tend to be too low. However, the range across different hardware
|
||||
// appears to be too large to choose a single value.
|
||||
//
|
||||
// GTP/Linux(ChromeOS): TBD, but for the moment we will trust the values.
|
||||
#if defined(WEBRTC_CHROMIUM_BUILD) && defined(WEBRTC_MAC)
|
||||
#define WEBRTC_UNTRUSTED_DELAY
|
||||
#endif
|
||||
|
||||
#if defined(WEBRTC_UNTRUSTED_DELAY) && defined(WEBRTC_MAC)
|
||||
static const int kDelayDiffOffsetSamples = -160;
|
||||
#else
|
||||
// Not enabled for now.
|
||||
static const int kDelayDiffOffsetSamples = 0;
|
||||
#endif
|
||||
|
||||
#if defined(WEBRTC_MAC)
|
||||
static const int kFixedDelayMs = 20;
|
||||
#else
|
||||
static const int kFixedDelayMs = 50;
|
||||
#endif
|
||||
#if !defined(WEBRTC_UNTRUSTED_DELAY)
|
||||
static const int kMinTrustedDelayMs = 20;
|
||||
#endif
|
||||
static const int kMaxTrustedDelayMs = 500;
|
||||
|
||||
// Maximum length of resampled signal. Must be an integer multiple of frames
|
||||
// (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN
|
||||
// The factor of 2 handles wb, and the + 1 is as a safety margin
|
||||
// TODO(bjornv): Replace with kResamplerBufferSize
|
||||
#define MAX_RESAMP_LEN (5 * FRAME_LEN)
|
||||
|
||||
static const int kMaxBufSizeStart = 62; // In partitions
|
||||
static const int sampMsNb = 8; // samples per ms in nb
|
||||
static const int initCheck = 42;
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
int webrtc_aec_instance_count = 0;
|
||||
#endif
|
||||
|
||||
// Estimates delay to set the position of the far-end buffer read pointer
|
||||
// (controlled by knownDelay)
|
||||
static void EstBufDelayNormal(Aec* aecInst);
|
||||
static void EstBufDelayExtended(Aec* aecInst);
|
||||
static int ProcessNormal(Aec* self,
|
||||
const float* const* near,
|
||||
size_t num_bands,
|
||||
float* const* out,
|
||||
size_t num_samples,
|
||||
int16_t reported_delay_ms,
|
||||
int32_t skew);
|
||||
static void ProcessExtended(Aec* self,
|
||||
const float* const* near,
|
||||
size_t num_bands,
|
||||
float* const* out,
|
||||
size_t num_samples,
|
||||
int16_t reported_delay_ms,
|
||||
int32_t skew);
|
||||
|
||||
void* WebRtcAec_Create() {
|
||||
Aec* aecpc = malloc(sizeof(Aec));
|
||||
|
||||
if (!aecpc) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
aecpc->aec = WebRtcAec_CreateAec();
|
||||
if (!aecpc->aec) {
|
||||
WebRtcAec_Free(aecpc);
|
||||
return NULL;
|
||||
}
|
||||
aecpc->resampler = WebRtcAec_CreateResampler();
|
||||
if (!aecpc->resampler) {
|
||||
WebRtcAec_Free(aecpc);
|
||||
return NULL;
|
||||
}
|
||||
// Create far-end pre-buffer. The buffer size has to be large enough for
|
||||
// largest possible drift compensation (kResamplerBufferSize) + "almost" an
|
||||
// FFT buffer (PART_LEN2 - 1).
|
||||
aecpc->far_pre_buf =
|
||||
WebRtc_CreateBuffer(PART_LEN2 + kResamplerBufferSize, sizeof(float));
|
||||
if (!aecpc->far_pre_buf) {
|
||||
WebRtcAec_Free(aecpc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
aecpc->initFlag = 0;
|
||||
aecpc->lastError = 0;
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
{
|
||||
char filename[64];
|
||||
sprintf(filename, "aec_buf%d.dat", webrtc_aec_instance_count);
|
||||
aecpc->bufFile = fopen(filename, "wb");
|
||||
sprintf(filename, "aec_skew%d.dat", webrtc_aec_instance_count);
|
||||
aecpc->skewFile = fopen(filename, "wb");
|
||||
sprintf(filename, "aec_delay%d.dat", webrtc_aec_instance_count);
|
||||
aecpc->delayFile = fopen(filename, "wb");
|
||||
webrtc_aec_instance_count++;
|
||||
}
|
||||
#endif
|
||||
|
||||
return aecpc;
|
||||
}
|
||||
|
||||
void WebRtcAec_Free(void* aecInst) {
|
||||
Aec* aecpc = aecInst;
|
||||
|
||||
if (aecpc == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
WebRtc_FreeBuffer(aecpc->far_pre_buf);
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
fclose(aecpc->bufFile);
|
||||
fclose(aecpc->skewFile);
|
||||
fclose(aecpc->delayFile);
|
||||
#endif
|
||||
|
||||
WebRtcAec_FreeAec(aecpc->aec);
|
||||
WebRtcAec_FreeResampler(aecpc->resampler);
|
||||
free(aecpc);
|
||||
}
|
||||
|
||||
int32_t WebRtcAec_Init(void* aecInst, int32_t sampFreq, int32_t scSampFreq) {
|
||||
Aec* aecpc = aecInst;
|
||||
AecConfig aecConfig;
|
||||
|
||||
if (sampFreq != 8000 &&
|
||||
sampFreq != 16000 &&
|
||||
sampFreq != 32000 &&
|
||||
sampFreq != 48000) {
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
aecpc->sampFreq = sampFreq;
|
||||
|
||||
if (scSampFreq < 1 || scSampFreq > 96000) {
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
aecpc->scSampFreq = scSampFreq;
|
||||
|
||||
// Initialize echo canceller core
|
||||
if (WebRtcAec_InitAec(aecpc->aec, aecpc->sampFreq) == -1) {
|
||||
aecpc->lastError = AEC_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (WebRtcAec_InitResampler(aecpc->resampler, aecpc->scSampFreq) == -1) {
|
||||
aecpc->lastError = AEC_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtc_InitBuffer(aecpc->far_pre_buf);
|
||||
WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN); // Start overlap.
|
||||
|
||||
aecpc->initFlag = initCheck; // indicates that initialization has been done
|
||||
|
||||
if (aecpc->sampFreq == 32000 || aecpc->sampFreq == 48000) {
|
||||
aecpc->splitSampFreq = 16000;
|
||||
} else {
|
||||
aecpc->splitSampFreq = sampFreq;
|
||||
}
|
||||
|
||||
aecpc->delayCtr = 0;
|
||||
aecpc->sampFactor = (aecpc->scSampFreq * 1.0f) / aecpc->splitSampFreq;
|
||||
// Sampling frequency multiplier (SWB is processed as 160 frame size).
|
||||
aecpc->rate_factor = aecpc->splitSampFreq / 8000;
|
||||
|
||||
aecpc->sum = 0;
|
||||
aecpc->counter = 0;
|
||||
aecpc->checkBuffSize = 1;
|
||||
aecpc->firstVal = 0;
|
||||
|
||||
// We skip the startup_phase completely (setting to 0) if DA-AEC is enabled,
|
||||
// but not extended_filter mode.
|
||||
aecpc->startup_phase = WebRtcAec_extended_filter_enabled(aecpc->aec) ||
|
||||
!WebRtcAec_delay_agnostic_enabled(aecpc->aec);
|
||||
aecpc->bufSizeStart = 0;
|
||||
aecpc->checkBufSizeCtr = 0;
|
||||
aecpc->msInSndCardBuf = 0;
|
||||
aecpc->filtDelay = -1; // -1 indicates an initialized state.
|
||||
aecpc->timeForDelayChange = 0;
|
||||
aecpc->knownDelay = 0;
|
||||
aecpc->lastDelayDiff = 0;
|
||||
|
||||
aecpc->skewFrCtr = 0;
|
||||
aecpc->resample = kAecFalse;
|
||||
aecpc->highSkewCtr = 0;
|
||||
aecpc->skew = 0;
|
||||
|
||||
aecpc->farend_started = 0;
|
||||
|
||||
// Default settings.
|
||||
aecConfig.nlpMode = kAecNlpModerate;
|
||||
aecConfig.skewMode = kAecFalse;
|
||||
aecConfig.metricsMode = kAecFalse;
|
||||
aecConfig.delay_logging = kAecFalse;
|
||||
|
||||
if (WebRtcAec_set_config(aecpc, aecConfig) == -1) {
|
||||
aecpc->lastError = AEC_UNSPECIFIED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// only buffer L band for farend
|
||||
int32_t WebRtcAec_BufferFarend(void* aecInst,
|
||||
const float* farend,
|
||||
size_t nrOfSamples) {
|
||||
Aec* aecpc = aecInst;
|
||||
size_t newNrOfSamples = nrOfSamples;
|
||||
float new_farend[MAX_RESAMP_LEN];
|
||||
const float* farend_ptr = farend;
|
||||
|
||||
if (farend == NULL) {
|
||||
aecpc->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecpc->initFlag != initCheck) {
|
||||
aecpc->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// number of samples == 160 for SWB input
|
||||
if (nrOfSamples != 80 && nrOfSamples != 160) {
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
|
||||
// Resample and get a new number of samples
|
||||
WebRtcAec_ResampleLinear(aecpc->resampler,
|
||||
farend,
|
||||
nrOfSamples,
|
||||
aecpc->skew,
|
||||
new_farend,
|
||||
&newNrOfSamples);
|
||||
farend_ptr = new_farend;
|
||||
}
|
||||
|
||||
aecpc->farend_started = 1;
|
||||
WebRtcAec_SetSystemDelay(
|
||||
aecpc->aec, WebRtcAec_system_delay(aecpc->aec) + (int)newNrOfSamples);
|
||||
|
||||
// Write the time-domain data to |far_pre_buf|.
|
||||
WebRtc_WriteBuffer(aecpc->far_pre_buf, farend_ptr, newNrOfSamples);
|
||||
|
||||
// Transform to frequency domain if we have enough data.
|
||||
while (WebRtc_available_read(aecpc->far_pre_buf) >= PART_LEN2) {
|
||||
// We have enough data to pass to the FFT, hence read PART_LEN2 samples.
|
||||
{
|
||||
float* ptmp = NULL;
|
||||
float tmp[PART_LEN2];
|
||||
WebRtc_ReadBuffer(aecpc->far_pre_buf, (void**)&ptmp, tmp, PART_LEN2);
|
||||
WebRtcAec_BufferFarendPartition(aecpc->aec, ptmp);
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
WebRtc_WriteBuffer(
|
||||
WebRtcAec_far_time_buf(aecpc->aec), &ptmp[PART_LEN], 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Rewind |far_pre_buf| PART_LEN samples for overlap before continuing.
|
||||
WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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) {
|
||||
Aec* aecpc = aecInst;
|
||||
int32_t retVal = 0;
|
||||
|
||||
if (out == NULL) {
|
||||
aecpc->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (aecpc->initFlag != initCheck) {
|
||||
aecpc->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// number of samples == 160 for SWB input
|
||||
if (nrOfSamples != 80 && nrOfSamples != 160) {
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msInSndCardBuf < 0) {
|
||||
msInSndCardBuf = 0;
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
|
||||
retVal = -1;
|
||||
} else if (msInSndCardBuf > kMaxTrustedDelayMs) {
|
||||
// The clamping is now done in ProcessExtended/Normal().
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
|
||||
retVal = -1;
|
||||
}
|
||||
|
||||
// This returns the value of aec->extended_filter_enabled.
|
||||
if (WebRtcAec_extended_filter_enabled(aecpc->aec)) {
|
||||
ProcessExtended(aecpc,
|
||||
nearend,
|
||||
num_bands,
|
||||
out,
|
||||
nrOfSamples,
|
||||
msInSndCardBuf,
|
||||
skew);
|
||||
} else {
|
||||
if (ProcessNormal(aecpc,
|
||||
nearend,
|
||||
num_bands,
|
||||
out,
|
||||
nrOfSamples,
|
||||
msInSndCardBuf,
|
||||
skew) != 0) {
|
||||
retVal = -1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
{
|
||||
int16_t far_buf_size_ms = (int16_t)(WebRtcAec_system_delay(aecpc->aec) /
|
||||
(sampMsNb * aecpc->rate_factor));
|
||||
(void)fwrite(&far_buf_size_ms, 2, 1, aecpc->bufFile);
|
||||
(void)fwrite(
|
||||
&aecpc->knownDelay, sizeof(aecpc->knownDelay), 1, aecpc->delayFile);
|
||||
}
|
||||
#endif
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
int WebRtcAec_set_config(void* handle, AecConfig config) {
|
||||
Aec* self = (Aec*)handle;
|
||||
if (self->initFlag != initCheck) {
|
||||
self->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config.skewMode != kAecFalse && config.skewMode != kAecTrue) {
|
||||
self->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
self->skewMode = config.skewMode;
|
||||
|
||||
if (config.nlpMode != kAecNlpConservative &&
|
||||
config.nlpMode != kAecNlpModerate &&
|
||||
config.nlpMode != kAecNlpAggressive) {
|
||||
self->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config.metricsMode != kAecFalse && config.metricsMode != kAecTrue) {
|
||||
self->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config.delay_logging != kAecFalse && config.delay_logging != kAecTrue) {
|
||||
self->lastError = AEC_BAD_PARAMETER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtcAec_SetConfigCore(
|
||||
self->aec, config.nlpMode, config.metricsMode, config.delay_logging);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcAec_get_echo_status(void* handle, int* status) {
|
||||
Aec* self = (Aec*)handle;
|
||||
if (status == NULL) {
|
||||
self->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (self->initFlag != initCheck) {
|
||||
self->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*status = WebRtcAec_echo_state(self->aec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcAec_GetMetrics(void* handle, AecMetrics* metrics) {
|
||||
const float kUpWeight = 0.7f;
|
||||
float dtmp;
|
||||
int stmp;
|
||||
Aec* self = (Aec*)handle;
|
||||
Stats erl;
|
||||
Stats erle;
|
||||
Stats a_nlp;
|
||||
|
||||
if (handle == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (metrics == NULL) {
|
||||
self->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (self->initFlag != initCheck) {
|
||||
self->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtcAec_GetEchoStats(self->aec, &erl, &erle, &a_nlp);
|
||||
|
||||
// ERL
|
||||
metrics->erl.instant = (int)erl.instant;
|
||||
|
||||
if ((erl.himean > kOffsetLevel) && (erl.average > kOffsetLevel)) {
|
||||
// Use a mix between regular average and upper part average.
|
||||
dtmp = kUpWeight * erl.himean + (1 - kUpWeight) * erl.average;
|
||||
metrics->erl.average = (int)dtmp;
|
||||
} else {
|
||||
metrics->erl.average = kOffsetLevel;
|
||||
}
|
||||
|
||||
metrics->erl.max = (int)erl.max;
|
||||
|
||||
if (erl.min < (kOffsetLevel * (-1))) {
|
||||
metrics->erl.min = (int)erl.min;
|
||||
} else {
|
||||
metrics->erl.min = kOffsetLevel;
|
||||
}
|
||||
|
||||
// ERLE
|
||||
metrics->erle.instant = (int)erle.instant;
|
||||
|
||||
if ((erle.himean > kOffsetLevel) && (erle.average > kOffsetLevel)) {
|
||||
// Use a mix between regular average and upper part average.
|
||||
dtmp = kUpWeight * erle.himean + (1 - kUpWeight) * erle.average;
|
||||
metrics->erle.average = (int)dtmp;
|
||||
} else {
|
||||
metrics->erle.average = kOffsetLevel;
|
||||
}
|
||||
|
||||
metrics->erle.max = (int)erle.max;
|
||||
|
||||
if (erle.min < (kOffsetLevel * (-1))) {
|
||||
metrics->erle.min = (int)erle.min;
|
||||
} else {
|
||||
metrics->erle.min = kOffsetLevel;
|
||||
}
|
||||
|
||||
// RERL
|
||||
if ((metrics->erl.average > kOffsetLevel) &&
|
||||
(metrics->erle.average > kOffsetLevel)) {
|
||||
stmp = metrics->erl.average + metrics->erle.average;
|
||||
} else {
|
||||
stmp = kOffsetLevel;
|
||||
}
|
||||
metrics->rerl.average = stmp;
|
||||
|
||||
// No other statistics needed, but returned for completeness.
|
||||
metrics->rerl.instant = stmp;
|
||||
metrics->rerl.max = stmp;
|
||||
metrics->rerl.min = stmp;
|
||||
|
||||
// A_NLP
|
||||
metrics->aNlp.instant = (int)a_nlp.instant;
|
||||
|
||||
if ((a_nlp.himean > kOffsetLevel) && (a_nlp.average > kOffsetLevel)) {
|
||||
// Use a mix between regular average and upper part average.
|
||||
dtmp = kUpWeight * a_nlp.himean + (1 - kUpWeight) * a_nlp.average;
|
||||
metrics->aNlp.average = (int)dtmp;
|
||||
} else {
|
||||
metrics->aNlp.average = kOffsetLevel;
|
||||
}
|
||||
|
||||
metrics->aNlp.max = (int)a_nlp.max;
|
||||
|
||||
if (a_nlp.min < (kOffsetLevel * (-1))) {
|
||||
metrics->aNlp.min = (int)a_nlp.min;
|
||||
} else {
|
||||
metrics->aNlp.min = kOffsetLevel;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WebRtcAec_GetDelayMetrics(void* handle,
|
||||
int* median,
|
||||
int* std,
|
||||
float* fraction_poor_delays) {
|
||||
Aec* self = handle;
|
||||
if (median == NULL) {
|
||||
self->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (std == NULL) {
|
||||
self->lastError = AEC_NULL_POINTER_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (self->initFlag != initCheck) {
|
||||
self->lastError = AEC_UNINITIALIZED_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (WebRtcAec_GetDelayMetricsCore(self->aec, median, std,
|
||||
fraction_poor_delays) ==
|
||||
-1) {
|
||||
// Logging disabled.
|
||||
self->lastError = AEC_UNSUPPORTED_FUNCTION_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t WebRtcAec_get_error_code(void* aecInst) {
|
||||
Aec* aecpc = aecInst;
|
||||
return aecpc->lastError;
|
||||
}
|
||||
|
||||
AecCore* WebRtcAec_aec_core(void* handle) {
|
||||
if (!handle) {
|
||||
return NULL;
|
||||
}
|
||||
return ((Aec*)handle)->aec;
|
||||
}
|
||||
|
||||
static int ProcessNormal(Aec* aecpc,
|
||||
const float* const* nearend,
|
||||
size_t num_bands,
|
||||
float* const* out,
|
||||
size_t nrOfSamples,
|
||||
int16_t msInSndCardBuf,
|
||||
int32_t skew) {
|
||||
int retVal = 0;
|
||||
size_t i;
|
||||
size_t nBlocks10ms;
|
||||
// Limit resampling to doubling/halving of signal
|
||||
const float minSkewEst = -0.5f;
|
||||
const float maxSkewEst = 1.0f;
|
||||
|
||||
msInSndCardBuf =
|
||||
msInSndCardBuf > kMaxTrustedDelayMs ? kMaxTrustedDelayMs : msInSndCardBuf;
|
||||
// TODO(andrew): we need to investigate if this +10 is really wanted.
|
||||
msInSndCardBuf += 10;
|
||||
aecpc->msInSndCardBuf = msInSndCardBuf;
|
||||
|
||||
if (aecpc->skewMode == kAecTrue) {
|
||||
if (aecpc->skewFrCtr < 25) {
|
||||
aecpc->skewFrCtr++;
|
||||
} else {
|
||||
retVal = WebRtcAec_GetSkew(aecpc->resampler, skew, &aecpc->skew);
|
||||
if (retVal == -1) {
|
||||
aecpc->skew = 0;
|
||||
aecpc->lastError = AEC_BAD_PARAMETER_WARNING;
|
||||
}
|
||||
|
||||
aecpc->skew /= aecpc->sampFactor * nrOfSamples;
|
||||
|
||||
if (aecpc->skew < 1.0e-3 && aecpc->skew > -1.0e-3) {
|
||||
aecpc->resample = kAecFalse;
|
||||
} else {
|
||||
aecpc->resample = kAecTrue;
|
||||
}
|
||||
|
||||
if (aecpc->skew < minSkewEst) {
|
||||
aecpc->skew = minSkewEst;
|
||||
} else if (aecpc->skew > maxSkewEst) {
|
||||
aecpc->skew = maxSkewEst;
|
||||
}
|
||||
|
||||
#ifdef WEBRTC_AEC_DEBUG_DUMP
|
||||
(void)fwrite(&aecpc->skew, sizeof(aecpc->skew), 1, aecpc->skewFile);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
nBlocks10ms = nrOfSamples / (FRAME_LEN * aecpc->rate_factor);
|
||||
|
||||
if (aecpc->startup_phase) {
|
||||
for (i = 0; i < num_bands; ++i) {
|
||||
// Only needed if they don't already point to the same place.
|
||||
if (nearend[i] != out[i]) {
|
||||
memcpy(out[i], nearend[i], sizeof(nearend[i][0]) * nrOfSamples);
|
||||
}
|
||||
}
|
||||
|
||||
// The AEC is in the start up mode
|
||||
// AEC is disabled until the system delay is OK
|
||||
|
||||
// Mechanism to ensure that the system delay is reasonably stable.
|
||||
if (aecpc->checkBuffSize) {
|
||||
aecpc->checkBufSizeCtr++;
|
||||
// Before we fill up the far-end buffer we require the system delay
|
||||
// to be stable (+/-8 ms) compared to the first value. This
|
||||
// comparison is made during the following 6 consecutive 10 ms
|
||||
// blocks. If it seems to be stable then we start to fill up the
|
||||
// far-end buffer.
|
||||
if (aecpc->counter == 0) {
|
||||
aecpc->firstVal = aecpc->msInSndCardBuf;
|
||||
aecpc->sum = 0;
|
||||
}
|
||||
|
||||
if (abs(aecpc->firstVal - aecpc->msInSndCardBuf) <
|
||||
WEBRTC_SPL_MAX(0.2 * aecpc->msInSndCardBuf, sampMsNb)) {
|
||||
aecpc->sum += aecpc->msInSndCardBuf;
|
||||
aecpc->counter++;
|
||||
} else {
|
||||
aecpc->counter = 0;
|
||||
}
|
||||
|
||||
if (aecpc->counter * nBlocks10ms >= 6) {
|
||||
// The far-end buffer size is determined in partitions of
|
||||
// PART_LEN samples. Use 75% of the average value of the system
|
||||
// delay as buffer size to start with.
|
||||
aecpc->bufSizeStart =
|
||||
WEBRTC_SPL_MIN((3 * aecpc->sum * aecpc->rate_factor * 8) /
|
||||
(4 * aecpc->counter * PART_LEN),
|
||||
kMaxBufSizeStart);
|
||||
// Buffer size has now been determined.
|
||||
aecpc->checkBuffSize = 0;
|
||||
}
|
||||
|
||||
if (aecpc->checkBufSizeCtr * nBlocks10ms > 50) {
|
||||
// For really bad systems, don't disable the echo canceller for
|
||||
// more than 0.5 sec.
|
||||
aecpc->bufSizeStart = WEBRTC_SPL_MIN(
|
||||
(aecpc->msInSndCardBuf * aecpc->rate_factor * 3) / 40,
|
||||
kMaxBufSizeStart);
|
||||
aecpc->checkBuffSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// If |checkBuffSize| changed in the if-statement above.
|
||||
if (!aecpc->checkBuffSize) {
|
||||
// The system delay is now reasonably stable (or has been unstable
|
||||
// for too long). When the far-end buffer is filled with
|
||||
// approximately the same amount of data as reported by the system
|
||||
// we end the startup phase.
|
||||
int overhead_elements =
|
||||
WebRtcAec_system_delay(aecpc->aec) / PART_LEN - aecpc->bufSizeStart;
|
||||
if (overhead_elements == 0) {
|
||||
// Enable the AEC
|
||||
aecpc->startup_phase = 0;
|
||||
} else if (overhead_elements > 0) {
|
||||
// TODO(bjornv): Do we need a check on how much we actually
|
||||
// moved the read pointer? It should always be possible to move
|
||||
// the pointer |overhead_elements| since we have only added data
|
||||
// to the buffer and no delay compensation nor AEC processing
|
||||
// has been done.
|
||||
WebRtcAec_MoveFarReadPtr(aecpc->aec, overhead_elements);
|
||||
|
||||
// Enable the AEC
|
||||
aecpc->startup_phase = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// AEC is enabled.
|
||||
EstBufDelayNormal(aecpc);
|
||||
|
||||
// Call the AEC.
|
||||
// TODO(bjornv): Re-structure such that we don't have to pass
|
||||
// |aecpc->knownDelay| as input. Change name to something like
|
||||
// |system_buffer_diff|.
|
||||
WebRtcAec_ProcessFrames(aecpc->aec,
|
||||
nearend,
|
||||
num_bands,
|
||||
nrOfSamples,
|
||||
aecpc->knownDelay,
|
||||
out);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static void ProcessExtended(Aec* self,
|
||||
const float* const* near,
|
||||
size_t num_bands,
|
||||
float* const* out,
|
||||
size_t num_samples,
|
||||
int16_t reported_delay_ms,
|
||||
int32_t skew) {
|
||||
size_t i;
|
||||
const int delay_diff_offset = kDelayDiffOffsetSamples;
|
||||
#if defined(WEBRTC_UNTRUSTED_DELAY)
|
||||
reported_delay_ms = kFixedDelayMs;
|
||||
#else
|
||||
// This is the usual mode where we trust the reported system delay values.
|
||||
// Due to the longer filter, we no longer add 10 ms to the reported delay
|
||||
// to reduce chance of non-causality. Instead we apply a minimum here to avoid
|
||||
// issues with the read pointer jumping around needlessly.
|
||||
reported_delay_ms = reported_delay_ms < kMinTrustedDelayMs
|
||||
? kMinTrustedDelayMs
|
||||
: reported_delay_ms;
|
||||
// If the reported delay appears to be bogus, we attempt to recover by using
|
||||
// the measured fixed delay values. We use >= here because higher layers
|
||||
// may already clamp to this maximum value, and we would otherwise not
|
||||
// detect it here.
|
||||
reported_delay_ms = reported_delay_ms >= kMaxTrustedDelayMs
|
||||
? kFixedDelayMs
|
||||
: reported_delay_ms;
|
||||
#endif
|
||||
self->msInSndCardBuf = reported_delay_ms;
|
||||
|
||||
if (!self->farend_started) {
|
||||
for (i = 0; i < num_bands; ++i) {
|
||||
// Only needed if they don't already point to the same place.
|
||||
if (near[i] != out[i]) {
|
||||
memcpy(out[i], near[i], sizeof(near[i][0]) * num_samples);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (self->startup_phase) {
|
||||
// In the extended mode, there isn't a startup "phase", just a special
|
||||
// action on the first frame. In the trusted delay case, we'll take the
|
||||
// current reported delay, unless it's less then our conservative
|
||||
// measurement.
|
||||
int startup_size_ms =
|
||||
reported_delay_ms < kFixedDelayMs ? kFixedDelayMs : reported_delay_ms;
|
||||
#if defined(WEBRTC_ANDROID)
|
||||
int target_delay = startup_size_ms * self->rate_factor * 8;
|
||||
#else
|
||||
// To avoid putting the AEC in a non-causal state we're being slightly
|
||||
// conservative and scale by 2. On Android we use a fixed delay and
|
||||
// therefore there is no need to scale the target_delay.
|
||||
int target_delay = startup_size_ms * self->rate_factor * 8 / 2;
|
||||
#endif
|
||||
int overhead_elements =
|
||||
(WebRtcAec_system_delay(self->aec) - target_delay) / PART_LEN;
|
||||
WebRtcAec_MoveFarReadPtr(self->aec, overhead_elements);
|
||||
self->startup_phase = 0;
|
||||
}
|
||||
|
||||
EstBufDelayExtended(self);
|
||||
|
||||
{
|
||||
// |delay_diff_offset| gives us the option to manually rewind the delay on
|
||||
// very low delay platforms which can't be expressed purely through
|
||||
// |reported_delay_ms|.
|
||||
const int adjusted_known_delay =
|
||||
WEBRTC_SPL_MAX(0, self->knownDelay + delay_diff_offset);
|
||||
|
||||
WebRtcAec_ProcessFrames(self->aec,
|
||||
near,
|
||||
num_bands,
|
||||
num_samples,
|
||||
adjusted_known_delay,
|
||||
out);
|
||||
}
|
||||
}
|
||||
|
||||
static void EstBufDelayNormal(Aec* aecpc) {
|
||||
int nSampSndCard = aecpc->msInSndCardBuf * sampMsNb * aecpc->rate_factor;
|
||||
int current_delay = nSampSndCard - WebRtcAec_system_delay(aecpc->aec);
|
||||
int delay_difference = 0;
|
||||
|
||||
// Before we proceed with the delay estimate filtering we:
|
||||
// 1) Compensate for the frame that will be read.
|
||||
// 2) Compensate for drift resampling.
|
||||
// 3) Compensate for non-causality if needed, since the estimated delay can't
|
||||
// be negative.
|
||||
|
||||
// 1) Compensating for the frame(s) that will be read/processed.
|
||||
current_delay += FRAME_LEN * aecpc->rate_factor;
|
||||
|
||||
// 2) Account for resampling frame delay.
|
||||
if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) {
|
||||
current_delay -= kResamplingDelay;
|
||||
}
|
||||
|
||||
// 3) Compensate for non-causality, if needed, by flushing one block.
|
||||
if (current_delay < PART_LEN) {
|
||||
current_delay += WebRtcAec_MoveFarReadPtr(aecpc->aec, 1) * PART_LEN;
|
||||
}
|
||||
|
||||
// We use -1 to signal an initialized state in the "extended" implementation;
|
||||
// compensate for that.
|
||||
aecpc->filtDelay = aecpc->filtDelay < 0 ? 0 : aecpc->filtDelay;
|
||||
aecpc->filtDelay =
|
||||
WEBRTC_SPL_MAX(0, (short)(0.8 * aecpc->filtDelay + 0.2 * current_delay));
|
||||
|
||||
delay_difference = aecpc->filtDelay - aecpc->knownDelay;
|
||||
if (delay_difference > 224) {
|
||||
if (aecpc->lastDelayDiff < 96) {
|
||||
aecpc->timeForDelayChange = 0;
|
||||
} else {
|
||||
aecpc->timeForDelayChange++;
|
||||
}
|
||||
} else if (delay_difference < 96 && aecpc->knownDelay > 0) {
|
||||
if (aecpc->lastDelayDiff > 224) {
|
||||
aecpc->timeForDelayChange = 0;
|
||||
} else {
|
||||
aecpc->timeForDelayChange++;
|
||||
}
|
||||
} else {
|
||||
aecpc->timeForDelayChange = 0;
|
||||
}
|
||||
aecpc->lastDelayDiff = delay_difference;
|
||||
|
||||
if (aecpc->timeForDelayChange > 25) {
|
||||
aecpc->knownDelay = WEBRTC_SPL_MAX((int)aecpc->filtDelay - 160, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void EstBufDelayExtended(Aec* self) {
|
||||
int reported_delay = self->msInSndCardBuf * sampMsNb * self->rate_factor;
|
||||
int current_delay = reported_delay - WebRtcAec_system_delay(self->aec);
|
||||
int delay_difference = 0;
|
||||
|
||||
// Before we proceed with the delay estimate filtering we:
|
||||
// 1) Compensate for the frame that will be read.
|
||||
// 2) Compensate for drift resampling.
|
||||
// 3) Compensate for non-causality if needed, since the estimated delay can't
|
||||
// be negative.
|
||||
|
||||
// 1) Compensating for the frame(s) that will be read/processed.
|
||||
current_delay += FRAME_LEN * self->rate_factor;
|
||||
|
||||
// 2) Account for resampling frame delay.
|
||||
if (self->skewMode == kAecTrue && self->resample == kAecTrue) {
|
||||
current_delay -= kResamplingDelay;
|
||||
}
|
||||
|
||||
// 3) Compensate for non-causality, if needed, by flushing two blocks.
|
||||
if (current_delay < PART_LEN) {
|
||||
current_delay += WebRtcAec_MoveFarReadPtr(self->aec, 2) * PART_LEN;
|
||||
}
|
||||
|
||||
if (self->filtDelay == -1) {
|
||||
self->filtDelay = WEBRTC_SPL_MAX(0, 0.5 * current_delay);
|
||||
} else {
|
||||
self->filtDelay = WEBRTC_SPL_MAX(
|
||||
0, (short)(0.95 * self->filtDelay + 0.05 * current_delay));
|
||||
}
|
||||
|
||||
delay_difference = self->filtDelay - self->knownDelay;
|
||||
if (delay_difference > 384) {
|
||||
if (self->lastDelayDiff < 128) {
|
||||
self->timeForDelayChange = 0;
|
||||
} else {
|
||||
self->timeForDelayChange++;
|
||||
}
|
||||
} else if (delay_difference < 128 && self->knownDelay > 0) {
|
||||
if (self->lastDelayDiff > 384) {
|
||||
self->timeForDelayChange = 0;
|
||||
} else {
|
||||
self->timeForDelayChange++;
|
||||
}
|
||||
} else {
|
||||
self->timeForDelayChange = 0;
|
||||
}
|
||||
self->lastDelayDiff = delay_difference;
|
||||
|
||||
if (self->timeForDelayChange > 25) {
|
||||
self->knownDelay = WEBRTC_SPL_MAX((int)self->filtDelay - 256, 0);
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
/*
|
||||
* 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_
|
@ -1,245 +0,0 @@
|
||||
/*
|
||||
* 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_
|
367
webrtc/modules/audio_processing/aec3/BUILD.gn
Normal file
367
webrtc/modules/audio_processing/aec3/BUILD.gn
Normal file
@ -0,0 +1,367 @@
|
||||
# Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
|
||||
#
|
||||
# Use of this source code is governed by a BSD-style license
|
||||
# that can be found in the LICENSE file in the root of the source
|
||||
# tree. An additional intellectual property rights grant can be found
|
||||
# in the file PATENTS. All contributing project authors may
|
||||
# be found in the AUTHORS file in the root of the source tree.
|
||||
|
||||
import("../../../webrtc.gni")
|
||||
|
||||
rtc_library("aec3") {
|
||||
visibility = [ "*" ]
|
||||
configs += [ "..:apm_debug_dump" ]
|
||||
sources = [
|
||||
"adaptive_fir_filter.cc",
|
||||
"adaptive_fir_filter_erl.cc",
|
||||
"aec3_common.cc",
|
||||
"aec3_fft.cc",
|
||||
"aec_state.cc",
|
||||
"aec_state.h",
|
||||
"alignment_mixer.cc",
|
||||
"alignment_mixer.h",
|
||||
"api_call_jitter_metrics.cc",
|
||||
"api_call_jitter_metrics.h",
|
||||
"block_buffer.cc",
|
||||
"block_delay_buffer.cc",
|
||||
"block_delay_buffer.h",
|
||||
"block_framer.cc",
|
||||
"block_framer.h",
|
||||
"block_processor.cc",
|
||||
"block_processor.h",
|
||||
"block_processor_metrics.cc",
|
||||
"block_processor_metrics.h",
|
||||
"clockdrift_detector.cc",
|
||||
"clockdrift_detector.h",
|
||||
"coarse_filter_update_gain.cc",
|
||||
"coarse_filter_update_gain.h",
|
||||
"comfort_noise_generator.cc",
|
||||
"comfort_noise_generator.h",
|
||||
"decimator.cc",
|
||||
"decimator.h",
|
||||
"delay_estimate.h",
|
||||
"dominant_nearend_detector.cc",
|
||||
"dominant_nearend_detector.h",
|
||||
"downsampled_render_buffer.cc",
|
||||
"downsampled_render_buffer.h",
|
||||
"echo_audibility.cc",
|
||||
"echo_audibility.h",
|
||||
"echo_canceller3.cc",
|
||||
"echo_canceller3.h",
|
||||
"echo_path_delay_estimator.cc",
|
||||
"echo_path_delay_estimator.h",
|
||||
"echo_path_variability.cc",
|
||||
"echo_path_variability.h",
|
||||
"echo_remover.cc",
|
||||
"echo_remover.h",
|
||||
"echo_remover_metrics.cc",
|
||||
"echo_remover_metrics.h",
|
||||
"erl_estimator.cc",
|
||||
"erl_estimator.h",
|
||||
"erle_estimator.cc",
|
||||
"erle_estimator.h",
|
||||
"fft_buffer.cc",
|
||||
"filter_analyzer.cc",
|
||||
"filter_analyzer.h",
|
||||
"frame_blocker.cc",
|
||||
"frame_blocker.h",
|
||||
"fullband_erle_estimator.cc",
|
||||
"fullband_erle_estimator.h",
|
||||
"matched_filter.cc",
|
||||
"matched_filter_lag_aggregator.cc",
|
||||
"matched_filter_lag_aggregator.h",
|
||||
"moving_average.cc",
|
||||
"moving_average.h",
|
||||
"nearend_detector.h",
|
||||
"refined_filter_update_gain.cc",
|
||||
"refined_filter_update_gain.h",
|
||||
"render_buffer.cc",
|
||||
"render_delay_buffer.cc",
|
||||
"render_delay_buffer.h",
|
||||
"render_delay_controller.cc",
|
||||
"render_delay_controller.h",
|
||||
"render_delay_controller_metrics.cc",
|
||||
"render_delay_controller_metrics.h",
|
||||
"render_signal_analyzer.cc",
|
||||
"render_signal_analyzer.h",
|
||||
"residual_echo_estimator.cc",
|
||||
"residual_echo_estimator.h",
|
||||
"reverb_decay_estimator.cc",
|
||||
"reverb_decay_estimator.h",
|
||||
"reverb_frequency_response.cc",
|
||||
"reverb_frequency_response.h",
|
||||
"reverb_model.cc",
|
||||
"reverb_model.h",
|
||||
"reverb_model_estimator.cc",
|
||||
"reverb_model_estimator.h",
|
||||
"signal_dependent_erle_estimator.cc",
|
||||
"signal_dependent_erle_estimator.h",
|
||||
"spectrum_buffer.cc",
|
||||
"stationarity_estimator.cc",
|
||||
"stationarity_estimator.h",
|
||||
"subband_erle_estimator.cc",
|
||||
"subband_erle_estimator.h",
|
||||
"subband_nearend_detector.cc",
|
||||
"subband_nearend_detector.h",
|
||||
"subtractor.cc",
|
||||
"subtractor.h",
|
||||
"subtractor_output.cc",
|
||||
"subtractor_output.h",
|
||||
"subtractor_output_analyzer.cc",
|
||||
"subtractor_output_analyzer.h",
|
||||
"suppression_filter.cc",
|
||||
"suppression_filter.h",
|
||||
"suppression_gain.cc",
|
||||
"suppression_gain.h",
|
||||
"transparent_mode.cc",
|
||||
"transparent_mode.h",
|
||||
]
|
||||
|
||||
defines = []
|
||||
if (rtc_build_with_neon && current_cpu != "arm64") {
|
||||
suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
|
||||
cflags = [ "-mfpu=neon" ]
|
||||
}
|
||||
|
||||
deps = [
|
||||
":adaptive_fir_filter",
|
||||
":adaptive_fir_filter_erl",
|
||||
":aec3_common",
|
||||
":aec3_fft",
|
||||
":fft_data",
|
||||
":matched_filter",
|
||||
":render_buffer",
|
||||
":vector_math",
|
||||
"..:apm_logging",
|
||||
"..:audio_buffer",
|
||||
"..:high_pass_filter",
|
||||
"../../../api:array_view",
|
||||
"../../../api/audio:aec3_config",
|
||||
"../../../api/audio:echo_control",
|
||||
"../../../common_audio:common_audio_c",
|
||||
"../../../rtc_base:checks",
|
||||
"../../../rtc_base:rtc_base_approved",
|
||||
"../../../rtc_base:safe_minmax",
|
||||
"../../../rtc_base/experiments:field_trial_parser",
|
||||
"../../../rtc_base/system:arch",
|
||||
"../../../system_wrappers",
|
||||
"../../../system_wrappers:field_trial",
|
||||
"../../../system_wrappers:metrics",
|
||||
"../utility:cascaded_biquad_filter",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||
|
||||
if (current_cpu == "x86" || current_cpu == "x64") {
|
||||
deps += [ ":aec3_avx2" ]
|
||||
}
|
||||
}
|
||||
|
||||
rtc_source_set("aec3_common") {
|
||||
sources = [ "aec3_common.h" ]
|
||||
}
|
||||
|
||||
rtc_source_set("aec3_fft") {
|
||||
sources = [ "aec3_fft.h" ]
|
||||
deps = [
|
||||
":aec3_common",
|
||||
":fft_data",
|
||||
"../../../api:array_view",
|
||||
"../../../common_audio/third_party/ooura:fft_size_128",
|
||||
"../../../rtc_base:checks",
|
||||
"../../../rtc_base:rtc_base_approved",
|
||||
"../../../rtc_base/system:arch",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_source_set("render_buffer") {
|
||||
sources = [
|
||||
"block_buffer.h",
|
||||
"fft_buffer.h",
|
||||
"render_buffer.h",
|
||||
"spectrum_buffer.h",
|
||||
]
|
||||
deps = [
|
||||
":aec3_common",
|
||||
":fft_data",
|
||||
"../../../api:array_view",
|
||||
"../../../rtc_base:checks",
|
||||
"../../../rtc_base:rtc_base_approved",
|
||||
"../../../rtc_base/system:arch",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_source_set("adaptive_fir_filter") {
|
||||
sources = [ "adaptive_fir_filter.h" ]
|
||||
deps = [
|
||||
":aec3_common",
|
||||
":aec3_fft",
|
||||
":fft_data",
|
||||
":render_buffer",
|
||||
"..:apm_logging",
|
||||
"../../../api:array_view",
|
||||
"../../../rtc_base/system:arch",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_source_set("adaptive_fir_filter_erl") {
|
||||
sources = [ "adaptive_fir_filter_erl.h" ]
|
||||
deps = [
|
||||
":aec3_common",
|
||||
"../../../api:array_view",
|
||||
"../../../rtc_base/system:arch",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_source_set("matched_filter") {
|
||||
sources = [ "matched_filter.h" ]
|
||||
deps = [
|
||||
":aec3_common",
|
||||
"../../../api:array_view",
|
||||
"../../../rtc_base:rtc_base_approved",
|
||||
"../../../rtc_base/system:arch",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_source_set("vector_math") {
|
||||
sources = [ "vector_math.h" ]
|
||||
deps = [
|
||||
":aec3_common",
|
||||
"../../../api:array_view",
|
||||
"../../../rtc_base:checks",
|
||||
"../../../rtc_base/system:arch",
|
||||
]
|
||||
}
|
||||
|
||||
rtc_source_set("fft_data") {
|
||||
sources = [ "fft_data.h" ]
|
||||
deps = [
|
||||
":aec3_common",
|
||||
"../../../api:array_view",
|
||||
"../../../rtc_base/system:arch",
|
||||
]
|
||||
}
|
||||
|
||||
if (current_cpu == "x86" || current_cpu == "x64") {
|
||||
rtc_library("aec3_avx2") {
|
||||
configs += [ "..:apm_debug_dump" ]
|
||||
sources = [
|
||||
"adaptive_fir_filter_avx2.cc",
|
||||
"adaptive_fir_filter_erl_avx2.cc",
|
||||
"fft_data_avx2.cc",
|
||||
"matched_filter_avx2.cc",
|
||||
"vector_math_avx2.cc",
|
||||
]
|
||||
|
||||
if (is_win) {
|
||||
cflags = [ "/arch:AVX2" ]
|
||||
} else {
|
||||
cflags = [
|
||||
"-mavx2",
|
||||
"-mfma",
|
||||
]
|
||||
}
|
||||
|
||||
deps = [
|
||||
":adaptive_fir_filter",
|
||||
":adaptive_fir_filter_erl",
|
||||
":fft_data",
|
||||
":matched_filter",
|
||||
":vector_math",
|
||||
"../../../api:array_view",
|
||||
"../../../rtc_base:checks",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (rtc_include_tests) {
|
||||
rtc_library("aec3_unittests") {
|
||||
testonly = true
|
||||
|
||||
configs += [ "..:apm_debug_dump" ]
|
||||
sources = [
|
||||
"mock/mock_block_processor.cc",
|
||||
"mock/mock_block_processor.h",
|
||||
"mock/mock_echo_remover.cc",
|
||||
"mock/mock_echo_remover.h",
|
||||
"mock/mock_render_delay_buffer.cc",
|
||||
"mock/mock_render_delay_buffer.h",
|
||||
"mock/mock_render_delay_controller.cc",
|
||||
"mock/mock_render_delay_controller.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":adaptive_fir_filter",
|
||||
":adaptive_fir_filter_erl",
|
||||
":aec3",
|
||||
":aec3_common",
|
||||
":aec3_fft",
|
||||
":fft_data",
|
||||
":matched_filter",
|
||||
":render_buffer",
|
||||
":vector_math",
|
||||
"..:apm_logging",
|
||||
"..:audio_buffer",
|
||||
"..:audio_processing",
|
||||
"..:audio_processing_unittests",
|
||||
"..:high_pass_filter",
|
||||
"../../../api:array_view",
|
||||
"../../../api/audio:aec3_config",
|
||||
"../../../rtc_base:checks",
|
||||
"../../../rtc_base:rtc_base_approved",
|
||||
"../../../rtc_base:safe_minmax",
|
||||
"../../../rtc_base/system:arch",
|
||||
"../../../system_wrappers",
|
||||
"../../../test:field_trial",
|
||||
"../../../test:test_support",
|
||||
"../utility:cascaded_biquad_filter",
|
||||
]
|
||||
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
|
||||
|
||||
defines = []
|
||||
|
||||
if (rtc_enable_protobuf) {
|
||||
sources += [
|
||||
"adaptive_fir_filter_erl_unittest.cc",
|
||||
"adaptive_fir_filter_unittest.cc",
|
||||
"aec3_fft_unittest.cc",
|
||||
"aec_state_unittest.cc",
|
||||
"alignment_mixer_unittest.cc",
|
||||
"api_call_jitter_metrics_unittest.cc",
|
||||
"block_delay_buffer_unittest.cc",
|
||||
"block_framer_unittest.cc",
|
||||
"block_processor_metrics_unittest.cc",
|
||||
"block_processor_unittest.cc",
|
||||
"clockdrift_detector_unittest.cc",
|
||||
"coarse_filter_update_gain_unittest.cc",
|
||||
"comfort_noise_generator_unittest.cc",
|
||||
"decimator_unittest.cc",
|
||||
"echo_canceller3_unittest.cc",
|
||||
"echo_path_delay_estimator_unittest.cc",
|
||||
"echo_path_variability_unittest.cc",
|
||||
"echo_remover_metrics_unittest.cc",
|
||||
"echo_remover_unittest.cc",
|
||||
"erl_estimator_unittest.cc",
|
||||
"erle_estimator_unittest.cc",
|
||||
"fft_data_unittest.cc",
|
||||
"filter_analyzer_unittest.cc",
|
||||
"frame_blocker_unittest.cc",
|
||||
"matched_filter_lag_aggregator_unittest.cc",
|
||||
"matched_filter_unittest.cc",
|
||||
"moving_average_unittest.cc",
|
||||
"refined_filter_update_gain_unittest.cc",
|
||||
"render_buffer_unittest.cc",
|
||||
"render_delay_buffer_unittest.cc",
|
||||
"render_delay_controller_metrics_unittest.cc",
|
||||
"render_delay_controller_unittest.cc",
|
||||
"render_signal_analyzer_unittest.cc",
|
||||
"residual_echo_estimator_unittest.cc",
|
||||
"reverb_model_estimator_unittest.cc",
|
||||
"signal_dependent_erle_estimator_unittest.cc",
|
||||
"subtractor_unittest.cc",
|
||||
"suppression_filter_unittest.cc",
|
||||
"suppression_gain_unittest.cc",
|
||||
"vector_math_unittest.cc",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
740
webrtc/modules/audio_processing/aec3/adaptive_fir_filter.cc
Normal file
740
webrtc/modules/audio_processing/aec3/adaptive_fir_filter.cc
Normal file
@ -0,0 +1,740 @@
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/audio_processing/aec3/adaptive_fir_filter.h"
|
||||
|
||||
// Defines WEBRTC_ARCH_X86_FAMILY, used below.
|
||||
#include "rtc_base/system/arch.h"
|
||||
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
#include <math.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include "modules/audio_processing/aec3/fft_data.h"
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace aec3 {
|
||||
|
||||
// Computes and stores the frequency response of the filter.
|
||||
void ComputeFrequencyResponse(
|
||||
size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H,
|
||||
std::vector<std::array<float, kFftLengthBy2Plus1>>* H2) {
|
||||
for (auto& H2_ch : *H2) {
|
||||
H2_ch.fill(0.f);
|
||||
}
|
||||
|
||||
const size_t num_render_channels = H[0].size();
|
||||
RTC_DCHECK_EQ(H.size(), H2->capacity());
|
||||
for (size_t p = 0; p < num_partitions; ++p) {
|
||||
RTC_DCHECK_EQ(kFftLengthBy2Plus1, (*H2)[p].size());
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
for (size_t j = 0; j < kFftLengthBy2Plus1; ++j) {
|
||||
float tmp =
|
||||
H[p][ch].re[j] * H[p][ch].re[j] + H[p][ch].im[j] * H[p][ch].im[j];
|
||||
(*H2)[p][j] = std::max((*H2)[p][j], tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
// Computes and stores the frequency response of the filter.
|
||||
void ComputeFrequencyResponse_Neon(
|
||||
size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H,
|
||||
std::vector<std::array<float, kFftLengthBy2Plus1>>* H2) {
|
||||
for (auto& H2_ch : *H2) {
|
||||
H2_ch.fill(0.f);
|
||||
}
|
||||
|
||||
const size_t num_render_channels = H[0].size();
|
||||
RTC_DCHECK_EQ(H.size(), H2->capacity());
|
||||
for (size_t p = 0; p < num_partitions; ++p) {
|
||||
RTC_DCHECK_EQ(kFftLengthBy2Plus1, (*H2)[p].size());
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
for (size_t j = 0; j < kFftLengthBy2; j += 4) {
|
||||
const float32x4_t re = vld1q_f32(&H[p][ch].re[j]);
|
||||
const float32x4_t im = vld1q_f32(&H[p][ch].im[j]);
|
||||
float32x4_t H2_new = vmulq_f32(re, re);
|
||||
H2_new = vmlaq_f32(H2_new, im, im);
|
||||
float32x4_t H2_p_j = vld1q_f32(&(*H2)[p][j]);
|
||||
H2_p_j = vmaxq_f32(H2_p_j, H2_new);
|
||||
vst1q_f32(&(*H2)[p][j], H2_p_j);
|
||||
}
|
||||
float H2_new = H[p][ch].re[kFftLengthBy2] * H[p][ch].re[kFftLengthBy2] +
|
||||
H[p][ch].im[kFftLengthBy2] * H[p][ch].im[kFftLengthBy2];
|
||||
(*H2)[p][kFftLengthBy2] = std::max((*H2)[p][kFftLengthBy2], H2_new);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
// Computes and stores the frequency response of the filter.
|
||||
void ComputeFrequencyResponse_Sse2(
|
||||
size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H,
|
||||
std::vector<std::array<float, kFftLengthBy2Plus1>>* H2) {
|
||||
for (auto& H2_ch : *H2) {
|
||||
H2_ch.fill(0.f);
|
||||
}
|
||||
|
||||
const size_t num_render_channels = H[0].size();
|
||||
RTC_DCHECK_EQ(H.size(), H2->capacity());
|
||||
// constexpr __mmmask8 kMaxMask = static_cast<__mmmask8>(256u);
|
||||
for (size_t p = 0; p < num_partitions; ++p) {
|
||||
RTC_DCHECK_EQ(kFftLengthBy2Plus1, (*H2)[p].size());
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
for (size_t j = 0; j < kFftLengthBy2; j += 4) {
|
||||
const __m128 re = _mm_loadu_ps(&H[p][ch].re[j]);
|
||||
const __m128 re2 = _mm_mul_ps(re, re);
|
||||
const __m128 im = _mm_loadu_ps(&H[p][ch].im[j]);
|
||||
const __m128 im2 = _mm_mul_ps(im, im);
|
||||
const __m128 H2_new = _mm_add_ps(re2, im2);
|
||||
__m128 H2_k_j = _mm_loadu_ps(&(*H2)[p][j]);
|
||||
H2_k_j = _mm_max_ps(H2_k_j, H2_new);
|
||||
_mm_storeu_ps(&(*H2)[p][j], H2_k_j);
|
||||
}
|
||||
float H2_new = H[p][ch].re[kFftLengthBy2] * H[p][ch].re[kFftLengthBy2] +
|
||||
H[p][ch].im[kFftLengthBy2] * H[p][ch].im[kFftLengthBy2];
|
||||
(*H2)[p][kFftLengthBy2] = std::max((*H2)[p][kFftLengthBy2], H2_new);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Adapts the filter partitions as H(t+1)=H(t)+G(t)*conj(X(t)).
|
||||
void AdaptPartitions(const RenderBuffer& render_buffer,
|
||||
const FftData& G,
|
||||
size_t num_partitions,
|
||||
std::vector<std::vector<FftData>>* H) {
|
||||
rtc::ArrayView<const std::vector<FftData>> render_buffer_data =
|
||||
render_buffer.GetFftBuffer();
|
||||
size_t index = render_buffer.Position();
|
||||
const size_t num_render_channels = render_buffer_data[index].size();
|
||||
for (size_t p = 0; p < num_partitions; ++p) {
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
const FftData& X_p_ch = render_buffer_data[index][ch];
|
||||
FftData& H_p_ch = (*H)[p][ch];
|
||||
for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
|
||||
H_p_ch.re[k] += X_p_ch.re[k] * G.re[k] + X_p_ch.im[k] * G.im[k];
|
||||
H_p_ch.im[k] += X_p_ch.re[k] * G.im[k] - X_p_ch.im[k] * G.re[k];
|
||||
}
|
||||
}
|
||||
index = index < (render_buffer_data.size() - 1) ? index + 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
// Adapts the filter partitions. (Neon variant)
|
||||
void AdaptPartitions_Neon(const RenderBuffer& render_buffer,
|
||||
const FftData& G,
|
||||
size_t num_partitions,
|
||||
std::vector<std::vector<FftData>>* H) {
|
||||
rtc::ArrayView<const std::vector<FftData>> render_buffer_data =
|
||||
render_buffer.GetFftBuffer();
|
||||
const size_t num_render_channels = render_buffer_data[0].size();
|
||||
const size_t lim1 = std::min(
|
||||
render_buffer_data.size() - render_buffer.Position(), num_partitions);
|
||||
const size_t lim2 = num_partitions;
|
||||
constexpr size_t kNumFourBinBands = kFftLengthBy2 / 4;
|
||||
|
||||
size_t X_partition = render_buffer.Position();
|
||||
size_t limit = lim1;
|
||||
size_t p = 0;
|
||||
do {
|
||||
for (; p < limit; ++p, ++X_partition) {
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
FftData& H_p_ch = (*H)[p][ch];
|
||||
const FftData& X = render_buffer_data[X_partition][ch];
|
||||
for (size_t k = 0, n = 0; n < kNumFourBinBands; ++n, k += 4) {
|
||||
const float32x4_t G_re = vld1q_f32(&G.re[k]);
|
||||
const float32x4_t G_im = vld1q_f32(&G.im[k]);
|
||||
const float32x4_t X_re = vld1q_f32(&X.re[k]);
|
||||
const float32x4_t X_im = vld1q_f32(&X.im[k]);
|
||||
const float32x4_t H_re = vld1q_f32(&H_p_ch.re[k]);
|
||||
const float32x4_t H_im = vld1q_f32(&H_p_ch.im[k]);
|
||||
const float32x4_t a = vmulq_f32(X_re, G_re);
|
||||
const float32x4_t e = vmlaq_f32(a, X_im, G_im);
|
||||
const float32x4_t c = vmulq_f32(X_re, G_im);
|
||||
const float32x4_t f = vmlsq_f32(c, X_im, G_re);
|
||||
const float32x4_t g = vaddq_f32(H_re, e);
|
||||
const float32x4_t h = vaddq_f32(H_im, f);
|
||||
vst1q_f32(&H_p_ch.re[k], g);
|
||||
vst1q_f32(&H_p_ch.im[k], h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
X_partition = 0;
|
||||
limit = lim2;
|
||||
} while (p < lim2);
|
||||
|
||||
X_partition = render_buffer.Position();
|
||||
limit = lim1;
|
||||
p = 0;
|
||||
do {
|
||||
for (; p < limit; ++p, ++X_partition) {
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
FftData& H_p_ch = (*H)[p][ch];
|
||||
const FftData& X = render_buffer_data[X_partition][ch];
|
||||
|
||||
H_p_ch.re[kFftLengthBy2] += X.re[kFftLengthBy2] * G.re[kFftLengthBy2] +
|
||||
X.im[kFftLengthBy2] * G.im[kFftLengthBy2];
|
||||
H_p_ch.im[kFftLengthBy2] += X.re[kFftLengthBy2] * G.im[kFftLengthBy2] -
|
||||
X.im[kFftLengthBy2] * G.re[kFftLengthBy2];
|
||||
}
|
||||
}
|
||||
X_partition = 0;
|
||||
limit = lim2;
|
||||
} while (p < lim2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
// Adapts the filter partitions. (SSE2 variant)
|
||||
void AdaptPartitions_Sse2(const RenderBuffer& render_buffer,
|
||||
const FftData& G,
|
||||
size_t num_partitions,
|
||||
std::vector<std::vector<FftData>>* H) {
|
||||
rtc::ArrayView<const std::vector<FftData>> render_buffer_data =
|
||||
render_buffer.GetFftBuffer();
|
||||
const size_t num_render_channels = render_buffer_data[0].size();
|
||||
const size_t lim1 = std::min(
|
||||
render_buffer_data.size() - render_buffer.Position(), num_partitions);
|
||||
const size_t lim2 = num_partitions;
|
||||
constexpr size_t kNumFourBinBands = kFftLengthBy2 / 4;
|
||||
|
||||
size_t X_partition = render_buffer.Position();
|
||||
size_t limit = lim1;
|
||||
size_t p = 0;
|
||||
do {
|
||||
for (; p < limit; ++p, ++X_partition) {
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
FftData& H_p_ch = (*H)[p][ch];
|
||||
const FftData& X = render_buffer_data[X_partition][ch];
|
||||
|
||||
for (size_t k = 0, n = 0; n < kNumFourBinBands; ++n, k += 4) {
|
||||
const __m128 G_re = _mm_loadu_ps(&G.re[k]);
|
||||
const __m128 G_im = _mm_loadu_ps(&G.im[k]);
|
||||
const __m128 X_re = _mm_loadu_ps(&X.re[k]);
|
||||
const __m128 X_im = _mm_loadu_ps(&X.im[k]);
|
||||
const __m128 H_re = _mm_loadu_ps(&H_p_ch.re[k]);
|
||||
const __m128 H_im = _mm_loadu_ps(&H_p_ch.im[k]);
|
||||
const __m128 a = _mm_mul_ps(X_re, G_re);
|
||||
const __m128 b = _mm_mul_ps(X_im, G_im);
|
||||
const __m128 c = _mm_mul_ps(X_re, G_im);
|
||||
const __m128 d = _mm_mul_ps(X_im, G_re);
|
||||
const __m128 e = _mm_add_ps(a, b);
|
||||
const __m128 f = _mm_sub_ps(c, d);
|
||||
const __m128 g = _mm_add_ps(H_re, e);
|
||||
const __m128 h = _mm_add_ps(H_im, f);
|
||||
_mm_storeu_ps(&H_p_ch.re[k], g);
|
||||
_mm_storeu_ps(&H_p_ch.im[k], h);
|
||||
}
|
||||
}
|
||||
}
|
||||
X_partition = 0;
|
||||
limit = lim2;
|
||||
} while (p < lim2);
|
||||
|
||||
X_partition = render_buffer.Position();
|
||||
limit = lim1;
|
||||
p = 0;
|
||||
do {
|
||||
for (; p < limit; ++p, ++X_partition) {
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
FftData& H_p_ch = (*H)[p][ch];
|
||||
const FftData& X = render_buffer_data[X_partition][ch];
|
||||
|
||||
H_p_ch.re[kFftLengthBy2] += X.re[kFftLengthBy2] * G.re[kFftLengthBy2] +
|
||||
X.im[kFftLengthBy2] * G.im[kFftLengthBy2];
|
||||
H_p_ch.im[kFftLengthBy2] += X.re[kFftLengthBy2] * G.im[kFftLengthBy2] -
|
||||
X.im[kFftLengthBy2] * G.re[kFftLengthBy2];
|
||||
}
|
||||
}
|
||||
|
||||
X_partition = 0;
|
||||
limit = lim2;
|
||||
} while (p < lim2);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Produces the filter output.
|
||||
void ApplyFilter(const RenderBuffer& render_buffer,
|
||||
size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H,
|
||||
FftData* S) {
|
||||
S->re.fill(0.f);
|
||||
S->im.fill(0.f);
|
||||
|
||||
rtc::ArrayView<const std::vector<FftData>> render_buffer_data =
|
||||
render_buffer.GetFftBuffer();
|
||||
size_t index = render_buffer.Position();
|
||||
const size_t num_render_channels = render_buffer_data[index].size();
|
||||
for (size_t p = 0; p < num_partitions; ++p) {
|
||||
RTC_DCHECK_EQ(num_render_channels, H[p].size());
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
const FftData& X_p_ch = render_buffer_data[index][ch];
|
||||
const FftData& H_p_ch = H[p][ch];
|
||||
for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
|
||||
S->re[k] += X_p_ch.re[k] * H_p_ch.re[k] - X_p_ch.im[k] * H_p_ch.im[k];
|
||||
S->im[k] += X_p_ch.re[k] * H_p_ch.im[k] + X_p_ch.im[k] * H_p_ch.re[k];
|
||||
}
|
||||
}
|
||||
index = index < (render_buffer_data.size() - 1) ? index + 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
// Produces the filter output (Neon variant).
|
||||
void ApplyFilter_Neon(const RenderBuffer& render_buffer,
|
||||
size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H,
|
||||
FftData* S) {
|
||||
// const RenderBuffer& render_buffer,
|
||||
// rtc::ArrayView<const FftData> H,
|
||||
// FftData* S) {
|
||||
RTC_DCHECK_GE(H.size(), H.size() - 1);
|
||||
S->Clear();
|
||||
|
||||
rtc::ArrayView<const std::vector<FftData>> render_buffer_data =
|
||||
render_buffer.GetFftBuffer();
|
||||
const size_t num_render_channels = render_buffer_data[0].size();
|
||||
const size_t lim1 = std::min(
|
||||
render_buffer_data.size() - render_buffer.Position(), num_partitions);
|
||||
const size_t lim2 = num_partitions;
|
||||
constexpr size_t kNumFourBinBands = kFftLengthBy2 / 4;
|
||||
|
||||
size_t X_partition = render_buffer.Position();
|
||||
size_t p = 0;
|
||||
size_t limit = lim1;
|
||||
do {
|
||||
for (; p < limit; ++p, ++X_partition) {
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
const FftData& H_p_ch = H[p][ch];
|
||||
const FftData& X = render_buffer_data[X_partition][ch];
|
||||
for (size_t k = 0, n = 0; n < kNumFourBinBands; ++n, k += 4) {
|
||||
const float32x4_t X_re = vld1q_f32(&X.re[k]);
|
||||
const float32x4_t X_im = vld1q_f32(&X.im[k]);
|
||||
const float32x4_t H_re = vld1q_f32(&H_p_ch.re[k]);
|
||||
const float32x4_t H_im = vld1q_f32(&H_p_ch.im[k]);
|
||||
const float32x4_t S_re = vld1q_f32(&S->re[k]);
|
||||
const float32x4_t S_im = vld1q_f32(&S->im[k]);
|
||||
const float32x4_t a = vmulq_f32(X_re, H_re);
|
||||
const float32x4_t e = vmlsq_f32(a, X_im, H_im);
|
||||
const float32x4_t c = vmulq_f32(X_re, H_im);
|
||||
const float32x4_t f = vmlaq_f32(c, X_im, H_re);
|
||||
const float32x4_t g = vaddq_f32(S_re, e);
|
||||
const float32x4_t h = vaddq_f32(S_im, f);
|
||||
vst1q_f32(&S->re[k], g);
|
||||
vst1q_f32(&S->im[k], h);
|
||||
}
|
||||
}
|
||||
}
|
||||
limit = lim2;
|
||||
X_partition = 0;
|
||||
} while (p < lim2);
|
||||
|
||||
X_partition = render_buffer.Position();
|
||||
p = 0;
|
||||
limit = lim1;
|
||||
do {
|
||||
for (; p < limit; ++p, ++X_partition) {
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
const FftData& H_p_ch = H[p][ch];
|
||||
const FftData& X = render_buffer_data[X_partition][ch];
|
||||
S->re[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2] -
|
||||
X.im[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2];
|
||||
S->im[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2] +
|
||||
X.im[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2];
|
||||
}
|
||||
}
|
||||
limit = lim2;
|
||||
X_partition = 0;
|
||||
} while (p < lim2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
// Produces the filter output (SSE2 variant).
|
||||
void ApplyFilter_Sse2(const RenderBuffer& render_buffer,
|
||||
size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H,
|
||||
FftData* S) {
|
||||
// const RenderBuffer& render_buffer,
|
||||
// rtc::ArrayView<const FftData> H,
|
||||
// FftData* S) {
|
||||
RTC_DCHECK_GE(H.size(), H.size() - 1);
|
||||
S->re.fill(0.f);
|
||||
S->im.fill(0.f);
|
||||
|
||||
rtc::ArrayView<const std::vector<FftData>> render_buffer_data =
|
||||
render_buffer.GetFftBuffer();
|
||||
const size_t num_render_channels = render_buffer_data[0].size();
|
||||
const size_t lim1 = std::min(
|
||||
render_buffer_data.size() - render_buffer.Position(), num_partitions);
|
||||
const size_t lim2 = num_partitions;
|
||||
constexpr size_t kNumFourBinBands = kFftLengthBy2 / 4;
|
||||
|
||||
size_t X_partition = render_buffer.Position();
|
||||
size_t p = 0;
|
||||
size_t limit = lim1;
|
||||
do {
|
||||
for (; p < limit; ++p, ++X_partition) {
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
const FftData& H_p_ch = H[p][ch];
|
||||
const FftData& X = render_buffer_data[X_partition][ch];
|
||||
for (size_t k = 0, n = 0; n < kNumFourBinBands; ++n, k += 4) {
|
||||
const __m128 X_re = _mm_loadu_ps(&X.re[k]);
|
||||
const __m128 X_im = _mm_loadu_ps(&X.im[k]);
|
||||
const __m128 H_re = _mm_loadu_ps(&H_p_ch.re[k]);
|
||||
const __m128 H_im = _mm_loadu_ps(&H_p_ch.im[k]);
|
||||
const __m128 S_re = _mm_loadu_ps(&S->re[k]);
|
||||
const __m128 S_im = _mm_loadu_ps(&S->im[k]);
|
||||
const __m128 a = _mm_mul_ps(X_re, H_re);
|
||||
const __m128 b = _mm_mul_ps(X_im, H_im);
|
||||
const __m128 c = _mm_mul_ps(X_re, H_im);
|
||||
const __m128 d = _mm_mul_ps(X_im, H_re);
|
||||
const __m128 e = _mm_sub_ps(a, b);
|
||||
const __m128 f = _mm_add_ps(c, d);
|
||||
const __m128 g = _mm_add_ps(S_re, e);
|
||||
const __m128 h = _mm_add_ps(S_im, f);
|
||||
_mm_storeu_ps(&S->re[k], g);
|
||||
_mm_storeu_ps(&S->im[k], h);
|
||||
}
|
||||
}
|
||||
}
|
||||
limit = lim2;
|
||||
X_partition = 0;
|
||||
} while (p < lim2);
|
||||
|
||||
X_partition = render_buffer.Position();
|
||||
p = 0;
|
||||
limit = lim1;
|
||||
do {
|
||||
for (; p < limit; ++p, ++X_partition) {
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
const FftData& H_p_ch = H[p][ch];
|
||||
const FftData& X = render_buffer_data[X_partition][ch];
|
||||
S->re[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2] -
|
||||
X.im[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2];
|
||||
S->im[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2] +
|
||||
X.im[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2];
|
||||
}
|
||||
}
|
||||
limit = lim2;
|
||||
X_partition = 0;
|
||||
} while (p < lim2);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace aec3
|
||||
|
||||
namespace {
|
||||
|
||||
// Ensures that the newly added filter partitions after a size increase are set
|
||||
// to zero.
|
||||
void ZeroFilter(size_t old_size,
|
||||
size_t new_size,
|
||||
std::vector<std::vector<FftData>>* H) {
|
||||
RTC_DCHECK_GE(H->size(), old_size);
|
||||
RTC_DCHECK_GE(H->size(), new_size);
|
||||
|
||||
for (size_t p = old_size; p < new_size; ++p) {
|
||||
RTC_DCHECK_EQ((*H)[p].size(), (*H)[0].size());
|
||||
for (size_t ch = 0; ch < (*H)[0].size(); ++ch) {
|
||||
(*H)[p][ch].Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AdaptiveFirFilter::AdaptiveFirFilter(size_t max_size_partitions,
|
||||
size_t initial_size_partitions,
|
||||
size_t size_change_duration_blocks,
|
||||
size_t num_render_channels,
|
||||
Aec3Optimization optimization,
|
||||
ApmDataDumper* data_dumper)
|
||||
: data_dumper_(data_dumper),
|
||||
fft_(),
|
||||
optimization_(optimization),
|
||||
num_render_channels_(num_render_channels),
|
||||
max_size_partitions_(max_size_partitions),
|
||||
size_change_duration_blocks_(
|
||||
static_cast<int>(size_change_duration_blocks)),
|
||||
current_size_partitions_(initial_size_partitions),
|
||||
target_size_partitions_(initial_size_partitions),
|
||||
old_target_size_partitions_(initial_size_partitions),
|
||||
H_(max_size_partitions_, std::vector<FftData>(num_render_channels_)) {
|
||||
RTC_DCHECK(data_dumper_);
|
||||
RTC_DCHECK_GE(max_size_partitions, initial_size_partitions);
|
||||
|
||||
RTC_DCHECK_LT(0, size_change_duration_blocks_);
|
||||
one_by_size_change_duration_blocks_ = 1.f / size_change_duration_blocks_;
|
||||
|
||||
ZeroFilter(0, max_size_partitions_, &H_);
|
||||
|
||||
SetSizePartitions(current_size_partitions_, true);
|
||||
}
|
||||
|
||||
AdaptiveFirFilter::~AdaptiveFirFilter() = default;
|
||||
|
||||
void AdaptiveFirFilter::HandleEchoPathChange() {
|
||||
// TODO(peah): Check the value and purpose of the code below.
|
||||
ZeroFilter(current_size_partitions_, max_size_partitions_, &H_);
|
||||
}
|
||||
|
||||
void AdaptiveFirFilter::SetSizePartitions(size_t size, bool immediate_effect) {
|
||||
RTC_DCHECK_EQ(max_size_partitions_, H_.capacity());
|
||||
RTC_DCHECK_LE(size, max_size_partitions_);
|
||||
|
||||
target_size_partitions_ = std::min(max_size_partitions_, size);
|
||||
if (immediate_effect) {
|
||||
size_t old_size_partitions_ = current_size_partitions_;
|
||||
current_size_partitions_ = old_target_size_partitions_ =
|
||||
target_size_partitions_;
|
||||
ZeroFilter(old_size_partitions_, current_size_partitions_, &H_);
|
||||
|
||||
partition_to_constrain_ =
|
||||
std::min(partition_to_constrain_, current_size_partitions_ - 1);
|
||||
size_change_counter_ = 0;
|
||||
} else {
|
||||
size_change_counter_ = size_change_duration_blocks_;
|
||||
}
|
||||
}
|
||||
|
||||
void AdaptiveFirFilter::UpdateSize() {
|
||||
RTC_DCHECK_GE(size_change_duration_blocks_, size_change_counter_);
|
||||
size_t old_size_partitions_ = current_size_partitions_;
|
||||
if (size_change_counter_ > 0) {
|
||||
--size_change_counter_;
|
||||
|
||||
auto average = [](float from, float to, float from_weight) {
|
||||
return from * from_weight + to * (1.f - from_weight);
|
||||
};
|
||||
|
||||
float change_factor =
|
||||
size_change_counter_ * one_by_size_change_duration_blocks_;
|
||||
|
||||
current_size_partitions_ = average(old_target_size_partitions_,
|
||||
target_size_partitions_, change_factor);
|
||||
|
||||
partition_to_constrain_ =
|
||||
std::min(partition_to_constrain_, current_size_partitions_ - 1);
|
||||
} else {
|
||||
current_size_partitions_ = old_target_size_partitions_ =
|
||||
target_size_partitions_;
|
||||
}
|
||||
ZeroFilter(old_size_partitions_, current_size_partitions_, &H_);
|
||||
RTC_DCHECK_LE(0, size_change_counter_);
|
||||
}
|
||||
|
||||
void AdaptiveFirFilter::Filter(const RenderBuffer& render_buffer,
|
||||
FftData* S) const {
|
||||
RTC_DCHECK(S);
|
||||
switch (optimization_) {
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
case Aec3Optimization::kSse2:
|
||||
aec3::ApplyFilter_Sse2(render_buffer, current_size_partitions_, H_, S);
|
||||
break;
|
||||
case Aec3Optimization::kAvx2:
|
||||
aec3::ApplyFilter_Avx2(render_buffer, current_size_partitions_, H_, S);
|
||||
break;
|
||||
#endif
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
case Aec3Optimization::kNeon:
|
||||
aec3::ApplyFilter_Neon(render_buffer, current_size_partitions_, H_, S);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
aec3::ApplyFilter(render_buffer, current_size_partitions_, H_, S);
|
||||
}
|
||||
}
|
||||
|
||||
void AdaptiveFirFilter::Adapt(const RenderBuffer& render_buffer,
|
||||
const FftData& G) {
|
||||
// Adapt the filter and update the filter size.
|
||||
AdaptAndUpdateSize(render_buffer, G);
|
||||
|
||||
// Constrain the filter partitions in a cyclic manner.
|
||||
Constrain();
|
||||
}
|
||||
|
||||
void AdaptiveFirFilter::Adapt(const RenderBuffer& render_buffer,
|
||||
const FftData& G,
|
||||
std::vector<float>* impulse_response) {
|
||||
// Adapt the filter and update the filter size.
|
||||
AdaptAndUpdateSize(render_buffer, G);
|
||||
|
||||
// Constrain the filter partitions in a cyclic manner.
|
||||
ConstrainAndUpdateImpulseResponse(impulse_response);
|
||||
}
|
||||
|
||||
void AdaptiveFirFilter::ComputeFrequencyResponse(
|
||||
std::vector<std::array<float, kFftLengthBy2Plus1>>* H2) const {
|
||||
RTC_DCHECK_GE(max_size_partitions_, H2->capacity());
|
||||
|
||||
H2->resize(current_size_partitions_);
|
||||
|
||||
switch (optimization_) {
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
case Aec3Optimization::kSse2:
|
||||
aec3::ComputeFrequencyResponse_Sse2(current_size_partitions_, H_, H2);
|
||||
break;
|
||||
case Aec3Optimization::kAvx2:
|
||||
aec3::ComputeFrequencyResponse_Avx2(current_size_partitions_, H_, H2);
|
||||
break;
|
||||
#endif
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
case Aec3Optimization::kNeon:
|
||||
aec3::ComputeFrequencyResponse_Neon(current_size_partitions_, H_, H2);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
aec3::ComputeFrequencyResponse(current_size_partitions_, H_, H2);
|
||||
}
|
||||
}
|
||||
|
||||
void AdaptiveFirFilter::AdaptAndUpdateSize(const RenderBuffer& render_buffer,
|
||||
const FftData& G) {
|
||||
// Update the filter size if needed.
|
||||
UpdateSize();
|
||||
|
||||
// Adapt the filter.
|
||||
switch (optimization_) {
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
case Aec3Optimization::kSse2:
|
||||
aec3::AdaptPartitions_Sse2(render_buffer, G, current_size_partitions_,
|
||||
&H_);
|
||||
break;
|
||||
case Aec3Optimization::kAvx2:
|
||||
aec3::AdaptPartitions_Avx2(render_buffer, G, current_size_partitions_,
|
||||
&H_);
|
||||
break;
|
||||
#endif
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
case Aec3Optimization::kNeon:
|
||||
aec3::AdaptPartitions_Neon(render_buffer, G, current_size_partitions_,
|
||||
&H_);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
aec3::AdaptPartitions(render_buffer, G, current_size_partitions_, &H_);
|
||||
}
|
||||
}
|
||||
|
||||
// Constrains the partition of the frequency domain filter to be limited in
|
||||
// time via setting the relevant time-domain coefficients to zero and updates
|
||||
// the corresponding values in an externally stored impulse response estimate.
|
||||
void AdaptiveFirFilter::ConstrainAndUpdateImpulseResponse(
|
||||
std::vector<float>* impulse_response) {
|
||||
RTC_DCHECK_EQ(GetTimeDomainLength(max_size_partitions_),
|
||||
impulse_response->capacity());
|
||||
impulse_response->resize(GetTimeDomainLength(current_size_partitions_));
|
||||
std::array<float, kFftLength> h;
|
||||
impulse_response->resize(GetTimeDomainLength(current_size_partitions_));
|
||||
std::fill(
|
||||
impulse_response->begin() + partition_to_constrain_ * kFftLengthBy2,
|
||||
impulse_response->begin() + (partition_to_constrain_ + 1) * kFftLengthBy2,
|
||||
0.f);
|
||||
|
||||
for (size_t ch = 0; ch < num_render_channels_; ++ch) {
|
||||
fft_.Ifft(H_[partition_to_constrain_][ch], &h);
|
||||
|
||||
static constexpr float kScale = 1.0f / kFftLengthBy2;
|
||||
std::for_each(h.begin(), h.begin() + kFftLengthBy2,
|
||||
[](float& a) { a *= kScale; });
|
||||
std::fill(h.begin() + kFftLengthBy2, h.end(), 0.f);
|
||||
|
||||
if (ch == 0) {
|
||||
std::copy(
|
||||
h.begin(), h.begin() + kFftLengthBy2,
|
||||
impulse_response->begin() + partition_to_constrain_ * kFftLengthBy2);
|
||||
} else {
|
||||
for (size_t k = 0, j = partition_to_constrain_ * kFftLengthBy2;
|
||||
k < kFftLengthBy2; ++k, ++j) {
|
||||
if (fabsf((*impulse_response)[j]) < fabsf(h[k])) {
|
||||
(*impulse_response)[j] = h[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fft_.Fft(&h, &H_[partition_to_constrain_][ch]);
|
||||
}
|
||||
|
||||
partition_to_constrain_ =
|
||||
partition_to_constrain_ < (current_size_partitions_ - 1)
|
||||
? partition_to_constrain_ + 1
|
||||
: 0;
|
||||
}
|
||||
|
||||
// Constrains the a partiton of the frequency domain filter to be limited in
|
||||
// time via setting the relevant time-domain coefficients to zero.
|
||||
void AdaptiveFirFilter::Constrain() {
|
||||
std::array<float, kFftLength> h;
|
||||
for (size_t ch = 0; ch < num_render_channels_; ++ch) {
|
||||
fft_.Ifft(H_[partition_to_constrain_][ch], &h);
|
||||
|
||||
static constexpr float kScale = 1.0f / kFftLengthBy2;
|
||||
std::for_each(h.begin(), h.begin() + kFftLengthBy2,
|
||||
[](float& a) { a *= kScale; });
|
||||
std::fill(h.begin() + kFftLengthBy2, h.end(), 0.f);
|
||||
|
||||
fft_.Fft(&h, &H_[partition_to_constrain_][ch]);
|
||||
}
|
||||
|
||||
partition_to_constrain_ =
|
||||
partition_to_constrain_ < (current_size_partitions_ - 1)
|
||||
? partition_to_constrain_ + 1
|
||||
: 0;
|
||||
}
|
||||
|
||||
void AdaptiveFirFilter::ScaleFilter(float factor) {
|
||||
for (auto& H_p : H_) {
|
||||
for (auto& H_p_ch : H_p) {
|
||||
for (auto& re : H_p_ch.re) {
|
||||
re *= factor;
|
||||
}
|
||||
for (auto& im : H_p_ch.im) {
|
||||
im *= factor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the filter coefficients.
|
||||
void AdaptiveFirFilter::SetFilter(size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H) {
|
||||
const size_t min_num_partitions =
|
||||
std::min(current_size_partitions_, num_partitions);
|
||||
for (size_t p = 0; p < min_num_partitions; ++p) {
|
||||
RTC_DCHECK_EQ(H_[p].size(), H[p].size());
|
||||
RTC_DCHECK_EQ(num_render_channels_, H_[p].size());
|
||||
|
||||
for (size_t ch = 0; ch < num_render_channels_; ++ch) {
|
||||
std::copy(H[p][ch].re.begin(), H[p][ch].re.end(), H_[p][ch].re.begin());
|
||||
std::copy(H[p][ch].im.begin(), H[p][ch].im.end(), H_[p][ch].im.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
191
webrtc/modules/audio_processing/aec3/adaptive_fir_filter.h
Normal file
191
webrtc/modules/audio_processing/aec3/adaptive_fir_filter.h
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_H_
|
||||
#define MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||
#include "modules/audio_processing/aec3/aec3_fft.h"
|
||||
#include "modules/audio_processing/aec3/fft_data.h"
|
||||
#include "modules/audio_processing/aec3/render_buffer.h"
|
||||
#include "modules/audio_processing/logging/apm_data_dumper.h"
|
||||
#include "rtc_base/system/arch.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace aec3 {
|
||||
// Computes and stores the frequency response of the filter.
|
||||
void ComputeFrequencyResponse(
|
||||
size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H,
|
||||
std::vector<std::array<float, kFftLengthBy2Plus1>>* H2);
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
void ComputeFrequencyResponse_Neon(
|
||||
size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H,
|
||||
std::vector<std::array<float, kFftLengthBy2Plus1>>* H2);
|
||||
#endif
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
void ComputeFrequencyResponse_Sse2(
|
||||
size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H,
|
||||
std::vector<std::array<float, kFftLengthBy2Plus1>>* H2);
|
||||
|
||||
void ComputeFrequencyResponse_Avx2(
|
||||
size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H,
|
||||
std::vector<std::array<float, kFftLengthBy2Plus1>>* H2);
|
||||
#endif
|
||||
|
||||
// Adapts the filter partitions.
|
||||
void AdaptPartitions(const RenderBuffer& render_buffer,
|
||||
const FftData& G,
|
||||
size_t num_partitions,
|
||||
std::vector<std::vector<FftData>>* H);
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
void AdaptPartitions_Neon(const RenderBuffer& render_buffer,
|
||||
const FftData& G,
|
||||
size_t num_partitions,
|
||||
std::vector<std::vector<FftData>>* H);
|
||||
#endif
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
void AdaptPartitions_Sse2(const RenderBuffer& render_buffer,
|
||||
const FftData& G,
|
||||
size_t num_partitions,
|
||||
std::vector<std::vector<FftData>>* H);
|
||||
|
||||
void AdaptPartitions_Avx2(const RenderBuffer& render_buffer,
|
||||
const FftData& G,
|
||||
size_t num_partitions,
|
||||
std::vector<std::vector<FftData>>* H);
|
||||
#endif
|
||||
|
||||
// Produces the filter output.
|
||||
void ApplyFilter(const RenderBuffer& render_buffer,
|
||||
size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H,
|
||||
FftData* S);
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
void ApplyFilter_Neon(const RenderBuffer& render_buffer,
|
||||
size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H,
|
||||
FftData* S);
|
||||
#endif
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
void ApplyFilter_Sse2(const RenderBuffer& render_buffer,
|
||||
size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H,
|
||||
FftData* S);
|
||||
|
||||
void ApplyFilter_Avx2(const RenderBuffer& render_buffer,
|
||||
size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H,
|
||||
FftData* S);
|
||||
#endif
|
||||
|
||||
} // namespace aec3
|
||||
|
||||
// Provides a frequency domain adaptive filter functionality.
|
||||
class AdaptiveFirFilter {
|
||||
public:
|
||||
AdaptiveFirFilter(size_t max_size_partitions,
|
||||
size_t initial_size_partitions,
|
||||
size_t size_change_duration_blocks,
|
||||
size_t num_render_channels,
|
||||
Aec3Optimization optimization,
|
||||
ApmDataDumper* data_dumper);
|
||||
|
||||
~AdaptiveFirFilter();
|
||||
|
||||
AdaptiveFirFilter(const AdaptiveFirFilter&) = delete;
|
||||
AdaptiveFirFilter& operator=(const AdaptiveFirFilter&) = delete;
|
||||
|
||||
// Produces the output of the filter.
|
||||
void Filter(const RenderBuffer& render_buffer, FftData* S) const;
|
||||
|
||||
// Adapts the filter and updates an externally stored impulse response
|
||||
// estimate.
|
||||
void Adapt(const RenderBuffer& render_buffer,
|
||||
const FftData& G,
|
||||
std::vector<float>* impulse_response);
|
||||
|
||||
// Adapts the filter.
|
||||
void Adapt(const RenderBuffer& render_buffer, const FftData& G);
|
||||
|
||||
// Receives reports that known echo path changes have occured and adjusts
|
||||
// the filter adaptation accordingly.
|
||||
void HandleEchoPathChange();
|
||||
|
||||
// Returns the filter size.
|
||||
size_t SizePartitions() const { return current_size_partitions_; }
|
||||
|
||||
// Sets the filter size.
|
||||
void SetSizePartitions(size_t size, bool immediate_effect);
|
||||
|
||||
// Computes the frequency responses for the filter partitions.
|
||||
void ComputeFrequencyResponse(
|
||||
std::vector<std::array<float, kFftLengthBy2Plus1>>* H2) const;
|
||||
|
||||
// Returns the maximum number of partitions for the filter.
|
||||
size_t max_filter_size_partitions() const { return max_size_partitions_; }
|
||||
|
||||
void DumpFilter(const char* name_frequency_domain) {
|
||||
for (size_t p = 0; p < max_size_partitions_; ++p) {
|
||||
data_dumper_->DumpRaw(name_frequency_domain, H_[p][0].re);
|
||||
data_dumper_->DumpRaw(name_frequency_domain, H_[p][0].im);
|
||||
}
|
||||
}
|
||||
|
||||
// Scale the filter impulse response and spectrum by a factor.
|
||||
void ScaleFilter(float factor);
|
||||
|
||||
// Set the filter coefficients.
|
||||
void SetFilter(size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H);
|
||||
|
||||
// Gets the filter coefficients.
|
||||
const std::vector<std::vector<FftData>>& GetFilter() const { return H_; }
|
||||
|
||||
private:
|
||||
// Adapts the filter and updates the filter size.
|
||||
void AdaptAndUpdateSize(const RenderBuffer& render_buffer, const FftData& G);
|
||||
|
||||
// Constrain the filter partitions in a cyclic manner.
|
||||
void Constrain();
|
||||
// Constrains the filter in a cyclic manner and updates the corresponding
|
||||
// values in the supplied impulse response.
|
||||
void ConstrainAndUpdateImpulseResponse(std::vector<float>* impulse_response);
|
||||
|
||||
// Gradually Updates the current filter size towards the target size.
|
||||
void UpdateSize();
|
||||
|
||||
ApmDataDumper* const data_dumper_;
|
||||
const Aec3Fft fft_;
|
||||
const Aec3Optimization optimization_;
|
||||
const size_t num_render_channels_;
|
||||
const size_t max_size_partitions_;
|
||||
const int size_change_duration_blocks_;
|
||||
float one_by_size_change_duration_blocks_;
|
||||
size_t current_size_partitions_;
|
||||
size_t target_size_partitions_;
|
||||
size_t old_target_size_partitions_;
|
||||
int size_change_counter_ = 0;
|
||||
std::vector<std::vector<FftData>> H_;
|
||||
size_t partition_to_constrain_ = 0;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_H_
|
187
webrtc/modules/audio_processing/aec3/adaptive_fir_filter_avx2.cc
Normal file
187
webrtc/modules/audio_processing/aec3/adaptive_fir_filter_avx2.cc
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/audio_processing/aec3/adaptive_fir_filter.h"
|
||||
|
||||
#include <immintrin.h>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace aec3 {
|
||||
|
||||
// Computes and stores the frequency response of the filter.
|
||||
void ComputeFrequencyResponse_Avx2(
|
||||
size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H,
|
||||
std::vector<std::array<float, kFftLengthBy2Plus1>>* H2) {
|
||||
for (auto& H2_ch : *H2) {
|
||||
H2_ch.fill(0.f);
|
||||
}
|
||||
|
||||
const size_t num_render_channels = H[0].size();
|
||||
RTC_DCHECK_EQ(H.size(), H2->capacity());
|
||||
for (size_t p = 0; p < num_partitions; ++p) {
|
||||
RTC_DCHECK_EQ(kFftLengthBy2Plus1, (*H2)[p].size());
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
for (size_t j = 0; j < kFftLengthBy2; j += 8) {
|
||||
__m256 re = _mm256_loadu_ps(&H[p][ch].re[j]);
|
||||
__m256 re2 = _mm256_mul_ps(re, re);
|
||||
__m256 im = _mm256_loadu_ps(&H[p][ch].im[j]);
|
||||
re2 = _mm256_fmadd_ps(im, im, re2);
|
||||
__m256 H2_k_j = _mm256_loadu_ps(&(*H2)[p][j]);
|
||||
H2_k_j = _mm256_max_ps(H2_k_j, re2);
|
||||
_mm256_storeu_ps(&(*H2)[p][j], H2_k_j);
|
||||
}
|
||||
float H2_new = H[p][ch].re[kFftLengthBy2] * H[p][ch].re[kFftLengthBy2] +
|
||||
H[p][ch].im[kFftLengthBy2] * H[p][ch].im[kFftLengthBy2];
|
||||
(*H2)[p][kFftLengthBy2] = std::max((*H2)[p][kFftLengthBy2], H2_new);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adapts the filter partitions.
|
||||
void AdaptPartitions_Avx2(const RenderBuffer& render_buffer,
|
||||
const FftData& G,
|
||||
size_t num_partitions,
|
||||
std::vector<std::vector<FftData>>* H) {
|
||||
rtc::ArrayView<const std::vector<FftData>> render_buffer_data =
|
||||
render_buffer.GetFftBuffer();
|
||||
const size_t num_render_channels = render_buffer_data[0].size();
|
||||
const size_t lim1 = std::min(
|
||||
render_buffer_data.size() - render_buffer.Position(), num_partitions);
|
||||
const size_t lim2 = num_partitions;
|
||||
constexpr size_t kNumEightBinBands = kFftLengthBy2 / 8;
|
||||
|
||||
size_t X_partition = render_buffer.Position();
|
||||
size_t limit = lim1;
|
||||
size_t p = 0;
|
||||
do {
|
||||
for (; p < limit; ++p, ++X_partition) {
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
FftData& H_p_ch = (*H)[p][ch];
|
||||
const FftData& X = render_buffer_data[X_partition][ch];
|
||||
|
||||
for (size_t k = 0, n = 0; n < kNumEightBinBands; ++n, k += 8) {
|
||||
const __m256 G_re = _mm256_loadu_ps(&G.re[k]);
|
||||
const __m256 G_im = _mm256_loadu_ps(&G.im[k]);
|
||||
const __m256 X_re = _mm256_loadu_ps(&X.re[k]);
|
||||
const __m256 X_im = _mm256_loadu_ps(&X.im[k]);
|
||||
const __m256 H_re = _mm256_loadu_ps(&H_p_ch.re[k]);
|
||||
const __m256 H_im = _mm256_loadu_ps(&H_p_ch.im[k]);
|
||||
const __m256 a = _mm256_mul_ps(X_re, G_re);
|
||||
const __m256 b = _mm256_mul_ps(X_im, G_im);
|
||||
const __m256 c = _mm256_mul_ps(X_re, G_im);
|
||||
const __m256 d = _mm256_mul_ps(X_im, G_re);
|
||||
const __m256 e = _mm256_add_ps(a, b);
|
||||
const __m256 f = _mm256_sub_ps(c, d);
|
||||
const __m256 g = _mm256_add_ps(H_re, e);
|
||||
const __m256 h = _mm256_add_ps(H_im, f);
|
||||
_mm256_storeu_ps(&H_p_ch.re[k], g);
|
||||
_mm256_storeu_ps(&H_p_ch.im[k], h);
|
||||
}
|
||||
}
|
||||
}
|
||||
X_partition = 0;
|
||||
limit = lim2;
|
||||
} while (p < lim2);
|
||||
|
||||
X_partition = render_buffer.Position();
|
||||
limit = lim1;
|
||||
p = 0;
|
||||
do {
|
||||
for (; p < limit; ++p, ++X_partition) {
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
FftData& H_p_ch = (*H)[p][ch];
|
||||
const FftData& X = render_buffer_data[X_partition][ch];
|
||||
|
||||
H_p_ch.re[kFftLengthBy2] += X.re[kFftLengthBy2] * G.re[kFftLengthBy2] +
|
||||
X.im[kFftLengthBy2] * G.im[kFftLengthBy2];
|
||||
H_p_ch.im[kFftLengthBy2] += X.re[kFftLengthBy2] * G.im[kFftLengthBy2] -
|
||||
X.im[kFftLengthBy2] * G.re[kFftLengthBy2];
|
||||
}
|
||||
}
|
||||
|
||||
X_partition = 0;
|
||||
limit = lim2;
|
||||
} while (p < lim2);
|
||||
}
|
||||
|
||||
// Produces the filter output (AVX2 variant).
|
||||
void ApplyFilter_Avx2(const RenderBuffer& render_buffer,
|
||||
size_t num_partitions,
|
||||
const std::vector<std::vector<FftData>>& H,
|
||||
FftData* S) {
|
||||
RTC_DCHECK_GE(H.size(), H.size() - 1);
|
||||
S->re.fill(0.f);
|
||||
S->im.fill(0.f);
|
||||
|
||||
rtc::ArrayView<const std::vector<FftData>> render_buffer_data =
|
||||
render_buffer.GetFftBuffer();
|
||||
const size_t num_render_channels = render_buffer_data[0].size();
|
||||
const size_t lim1 = std::min(
|
||||
render_buffer_data.size() - render_buffer.Position(), num_partitions);
|
||||
const size_t lim2 = num_partitions;
|
||||
constexpr size_t kNumEightBinBands = kFftLengthBy2 / 8;
|
||||
|
||||
size_t X_partition = render_buffer.Position();
|
||||
size_t p = 0;
|
||||
size_t limit = lim1;
|
||||
do {
|
||||
for (; p < limit; ++p, ++X_partition) {
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
const FftData& H_p_ch = H[p][ch];
|
||||
const FftData& X = render_buffer_data[X_partition][ch];
|
||||
for (size_t k = 0, n = 0; n < kNumEightBinBands; ++n, k += 8) {
|
||||
const __m256 X_re = _mm256_loadu_ps(&X.re[k]);
|
||||
const __m256 X_im = _mm256_loadu_ps(&X.im[k]);
|
||||
const __m256 H_re = _mm256_loadu_ps(&H_p_ch.re[k]);
|
||||
const __m256 H_im = _mm256_loadu_ps(&H_p_ch.im[k]);
|
||||
const __m256 S_re = _mm256_loadu_ps(&S->re[k]);
|
||||
const __m256 S_im = _mm256_loadu_ps(&S->im[k]);
|
||||
const __m256 a = _mm256_mul_ps(X_re, H_re);
|
||||
const __m256 b = _mm256_mul_ps(X_im, H_im);
|
||||
const __m256 c = _mm256_mul_ps(X_re, H_im);
|
||||
const __m256 d = _mm256_mul_ps(X_im, H_re);
|
||||
const __m256 e = _mm256_sub_ps(a, b);
|
||||
const __m256 f = _mm256_add_ps(c, d);
|
||||
const __m256 g = _mm256_add_ps(S_re, e);
|
||||
const __m256 h = _mm256_add_ps(S_im, f);
|
||||
_mm256_storeu_ps(&S->re[k], g);
|
||||
_mm256_storeu_ps(&S->im[k], h);
|
||||
}
|
||||
}
|
||||
}
|
||||
limit = lim2;
|
||||
X_partition = 0;
|
||||
} while (p < lim2);
|
||||
|
||||
X_partition = render_buffer.Position();
|
||||
p = 0;
|
||||
limit = lim1;
|
||||
do {
|
||||
for (; p < limit; ++p, ++X_partition) {
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
const FftData& H_p_ch = H[p][ch];
|
||||
const FftData& X = render_buffer_data[X_partition][ch];
|
||||
S->re[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2] -
|
||||
X.im[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2];
|
||||
S->im[kFftLengthBy2] += X.re[kFftLengthBy2] * H_p_ch.im[kFftLengthBy2] +
|
||||
X.im[kFftLengthBy2] * H_p_ch.re[kFftLengthBy2];
|
||||
}
|
||||
}
|
||||
limit = lim2;
|
||||
X_partition = 0;
|
||||
} while (p < lim2);
|
||||
}
|
||||
|
||||
} // namespace aec3
|
||||
} // namespace webrtc
|
102
webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl.cc
Normal file
102
webrtc/modules/audio_processing/aec3/adaptive_fir_filter_erl.cc
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can 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 "modules/audio_processing/aec3/adaptive_fir_filter_erl.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace aec3 {
|
||||
|
||||
// Computes and stores the echo return loss estimate of the filter, which is the
|
||||
// sum of the partition frequency responses.
|
||||
void ErlComputer(const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
|
||||
rtc::ArrayView<float> erl) {
|
||||
std::fill(erl.begin(), erl.end(), 0.f);
|
||||
for (auto& H2_j : H2) {
|
||||
std::transform(H2_j.begin(), H2_j.end(), erl.begin(), erl.begin(),
|
||||
std::plus<float>());
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
// Computes and stores the echo return loss estimate of the filter, which is the
|
||||
// sum of the partition frequency responses.
|
||||
void ErlComputer_NEON(
|
||||
const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
|
||||
rtc::ArrayView<float> erl) {
|
||||
std::fill(erl.begin(), erl.end(), 0.f);
|
||||
for (auto& H2_j : H2) {
|
||||
for (size_t k = 0; k < kFftLengthBy2; k += 4) {
|
||||
const float32x4_t H2_j_k = vld1q_f32(&H2_j[k]);
|
||||
float32x4_t erl_k = vld1q_f32(&erl[k]);
|
||||
erl_k = vaddq_f32(erl_k, H2_j_k);
|
||||
vst1q_f32(&erl[k], erl_k);
|
||||
}
|
||||
erl[kFftLengthBy2] += H2_j[kFftLengthBy2];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
// Computes and stores the echo return loss estimate of the filter, which is the
|
||||
// sum of the partition frequency responses.
|
||||
void ErlComputer_SSE2(
|
||||
const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
|
||||
rtc::ArrayView<float> erl) {
|
||||
std::fill(erl.begin(), erl.end(), 0.f);
|
||||
for (auto& H2_j : H2) {
|
||||
for (size_t k = 0; k < kFftLengthBy2; k += 4) {
|
||||
const __m128 H2_j_k = _mm_loadu_ps(&H2_j[k]);
|
||||
__m128 erl_k = _mm_loadu_ps(&erl[k]);
|
||||
erl_k = _mm_add_ps(erl_k, H2_j_k);
|
||||
_mm_storeu_ps(&erl[k], erl_k);
|
||||
}
|
||||
erl[kFftLengthBy2] += H2_j[kFftLengthBy2];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace aec3
|
||||
|
||||
void ComputeErl(const Aec3Optimization& optimization,
|
||||
const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
|
||||
rtc::ArrayView<float> erl) {
|
||||
RTC_DCHECK_EQ(kFftLengthBy2Plus1, erl.size());
|
||||
// Update the frequency response and echo return loss for the filter.
|
||||
switch (optimization) {
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
case Aec3Optimization::kSse2:
|
||||
aec3::ErlComputer_SSE2(H2, erl);
|
||||
break;
|
||||
case Aec3Optimization::kAvx2:
|
||||
aec3::ErlComputer_AVX2(H2, erl);
|
||||
break;
|
||||
#endif
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
case Aec3Optimization::kNeon:
|
||||
aec3::ErlComputer_NEON(H2, erl);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
aec3::ErlComputer(H2, erl);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_ERL_H_
|
||||
#define MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_ERL_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||
#include "rtc_base/system/arch.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace aec3 {
|
||||
|
||||
// Computes and stores the echo return loss estimate of the filter, which is the
|
||||
// sum of the partition frequency responses.
|
||||
void ErlComputer(const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
|
||||
rtc::ArrayView<float> erl);
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
void ErlComputer_NEON(
|
||||
const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
|
||||
rtc::ArrayView<float> erl);
|
||||
#endif
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
void ErlComputer_SSE2(
|
||||
const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
|
||||
rtc::ArrayView<float> erl);
|
||||
|
||||
void ErlComputer_AVX2(
|
||||
const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
|
||||
rtc::ArrayView<float> erl);
|
||||
#endif
|
||||
|
||||
} // namespace aec3
|
||||
|
||||
// Computes the echo return loss based on a frequency response.
|
||||
void ComputeErl(const Aec3Optimization& optimization,
|
||||
const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
|
||||
rtc::ArrayView<float> erl);
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_AUDIO_PROCESSING_AEC3_ADAPTIVE_FIR_FILTER_ERL_H_
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/audio_processing/aec3/adaptive_fir_filter_erl.h"
|
||||
|
||||
#include <immintrin.h>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace aec3 {
|
||||
|
||||
// Computes and stores the echo return loss estimate of the filter, which is the
|
||||
// sum of the partition frequency responses.
|
||||
void ErlComputer_AVX2(
|
||||
const std::vector<std::array<float, kFftLengthBy2Plus1>>& H2,
|
||||
rtc::ArrayView<float> erl) {
|
||||
std::fill(erl.begin(), erl.end(), 0.f);
|
||||
for (auto& H2_j : H2) {
|
||||
for (size_t k = 0; k < kFftLengthBy2; k += 8) {
|
||||
const __m256 H2_j_k = _mm256_loadu_ps(&H2_j[k]);
|
||||
__m256 erl_k = _mm256_loadu_ps(&erl[k]);
|
||||
erl_k = _mm256_add_ps(erl_k, H2_j_k);
|
||||
_mm256_storeu_ps(&erl[k], erl_k);
|
||||
}
|
||||
erl[kFftLengthBy2] += H2_j[kFftLengthBy2];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace aec3
|
||||
} // namespace webrtc
|
58
webrtc/modules/audio_processing/aec3/aec3_common.cc
Normal file
58
webrtc/modules/audio_processing/aec3/aec3_common.cc
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/system/arch.h"
|
||||
#include "system_wrappers/include/cpu_features_wrapper.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
Aec3Optimization DetectOptimization() {
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
if (GetCPUInfo(kAVX2) != 0) {
|
||||
return Aec3Optimization::kAvx2;
|
||||
} else if (GetCPUInfo(kSSE2) != 0) {
|
||||
return Aec3Optimization::kSse2;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
return Aec3Optimization::kNeon;
|
||||
#endif
|
||||
|
||||
return Aec3Optimization::kNone;
|
||||
}
|
||||
|
||||
float FastApproxLog2f(const float in) {
|
||||
RTC_DCHECK_GT(in, .0f);
|
||||
// Read and interpret float as uint32_t and then cast to float.
|
||||
// This is done to extract the exponent (bits 30 - 23).
|
||||
// "Right shift" of the exponent is then performed by multiplying
|
||||
// with the constant (1/2^23). Finally, we subtract a constant to
|
||||
// remove the bias (https://en.wikipedia.org/wiki/Exponent_bias).
|
||||
union {
|
||||
float dummy;
|
||||
uint32_t a;
|
||||
} x = {in};
|
||||
float out = x.a;
|
||||
out *= 1.1920929e-7f; // 1/2^23
|
||||
out -= 126.942695f; // Remove bias.
|
||||
return out;
|
||||
}
|
||||
|
||||
float Log2TodB(const float in_log2) {
|
||||
return 3.0102999566398121 * in_log2;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
114
webrtc/modules/audio_processing/aec3/aec3_common.h
Normal file
114
webrtc/modules/audio_processing/aec3/aec3_common.h
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_AUDIO_PROCESSING_AEC3_AEC3_COMMON_H_
|
||||
#define MODULES_AUDIO_PROCESSING_AEC3_AEC3_COMMON_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
#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
|
||||
|
||||
enum class Aec3Optimization { kNone, kSse2, kAvx2, kNeon };
|
||||
|
||||
constexpr int kNumBlocksPerSecond = 250;
|
||||
|
||||
constexpr int kMetricsReportingIntervalBlocks = 10 * kNumBlocksPerSecond;
|
||||
constexpr int kMetricsComputationBlocks = 7;
|
||||
constexpr int kMetricsCollectionBlocks =
|
||||
kMetricsReportingIntervalBlocks - kMetricsComputationBlocks;
|
||||
|
||||
constexpr size_t kFftLengthBy2 = 64;
|
||||
constexpr size_t kFftLengthBy2Plus1 = kFftLengthBy2 + 1;
|
||||
constexpr size_t kFftLengthBy2Minus1 = kFftLengthBy2 - 1;
|
||||
constexpr size_t kFftLength = 2 * kFftLengthBy2;
|
||||
constexpr size_t kFftLengthBy2Log2 = 6;
|
||||
|
||||
constexpr int kRenderTransferQueueSizeFrames = 100;
|
||||
|
||||
constexpr size_t kMaxNumBands = 3;
|
||||
constexpr size_t kFrameSize = 160;
|
||||
constexpr size_t kSubFrameLength = kFrameSize / 2;
|
||||
|
||||
constexpr size_t kBlockSize = kFftLengthBy2;
|
||||
constexpr size_t kBlockSizeLog2 = kFftLengthBy2Log2;
|
||||
|
||||
constexpr size_t kExtendedBlockSize = 2 * kFftLengthBy2;
|
||||
constexpr size_t kMatchedFilterWindowSizeSubBlocks = 32;
|
||||
constexpr size_t kMatchedFilterAlignmentShiftSizeSubBlocks =
|
||||
kMatchedFilterWindowSizeSubBlocks * 3 / 4;
|
||||
|
||||
// TODO(peah): Integrate this with how it is done inside audio_processing_impl.
|
||||
constexpr size_t NumBandsForRate(int sample_rate_hz) {
|
||||
return static_cast<size_t>(sample_rate_hz / 16000);
|
||||
}
|
||||
|
||||
constexpr bool ValidFullBandRate(int sample_rate_hz) {
|
||||
return sample_rate_hz == 16000 || sample_rate_hz == 32000 ||
|
||||
sample_rate_hz == 48000;
|
||||
}
|
||||
|
||||
constexpr int GetTimeDomainLength(int filter_length_blocks) {
|
||||
return filter_length_blocks * kFftLengthBy2;
|
||||
}
|
||||
|
||||
constexpr size_t GetDownSampledBufferSize(size_t down_sampling_factor,
|
||||
size_t num_matched_filters) {
|
||||
return kBlockSize / down_sampling_factor *
|
||||
(kMatchedFilterAlignmentShiftSizeSubBlocks * num_matched_filters +
|
||||
kMatchedFilterWindowSizeSubBlocks + 1);
|
||||
}
|
||||
|
||||
constexpr size_t GetRenderDelayBufferSize(size_t down_sampling_factor,
|
||||
size_t num_matched_filters,
|
||||
size_t filter_length_blocks) {
|
||||
return GetDownSampledBufferSize(down_sampling_factor, num_matched_filters) /
|
||||
(kBlockSize / down_sampling_factor) +
|
||||
filter_length_blocks + 1;
|
||||
}
|
||||
|
||||
// Detects what kind of optimizations to use for the code.
|
||||
Aec3Optimization DetectOptimization();
|
||||
|
||||
// Computes the log2 of the input in a fast an approximate manner.
|
||||
float FastApproxLog2f(const float in);
|
||||
|
||||
// Returns dB from a power quantity expressed in log2.
|
||||
float Log2TodB(const float in_log2);
|
||||
|
||||
static_assert(1 << kBlockSizeLog2 == kBlockSize,
|
||||
"Proper number of shifts for blocksize");
|
||||
|
||||
static_assert(1 << kFftLengthBy2Log2 == kFftLengthBy2,
|
||||
"Proper number of shifts for the fft length");
|
||||
|
||||
static_assert(1 == NumBandsForRate(16000), "Number of bands for 16 kHz");
|
||||
static_assert(2 == NumBandsForRate(32000), "Number of bands for 32 kHz");
|
||||
static_assert(3 == NumBandsForRate(48000), "Number of bands for 48 kHz");
|
||||
|
||||
static_assert(ValidFullBandRate(16000),
|
||||
"Test that 16 kHz is a valid sample rate");
|
||||
static_assert(ValidFullBandRate(32000),
|
||||
"Test that 32 kHz is a valid sample rate");
|
||||
static_assert(ValidFullBandRate(48000),
|
||||
"Test that 48 kHz is a valid sample rate");
|
||||
static_assert(!ValidFullBandRate(8001),
|
||||
"Test that 8001 Hz is not a valid sample rate");
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_AUDIO_PROCESSING_AEC3_AEC3_COMMON_H_
|
144
webrtc/modules/audio_processing/aec3/aec3_fft.cc
Normal file
144
webrtc/modules/audio_processing/aec3/aec3_fft.cc
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/audio_processing/aec3/aec3_fft.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "system_wrappers/include/cpu_features_wrapper.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
||||
const float kHanning64[kFftLengthBy2] = {
|
||||
0.f, 0.00248461f, 0.00991376f, 0.0222136f, 0.03926189f,
|
||||
0.06088921f, 0.08688061f, 0.11697778f, 0.15088159f, 0.1882551f,
|
||||
0.22872687f, 0.27189467f, 0.31732949f, 0.36457977f, 0.41317591f,
|
||||
0.46263495f, 0.51246535f, 0.56217185f, 0.61126047f, 0.65924333f,
|
||||
0.70564355f, 0.75f, 0.79187184f, 0.83084292f, 0.86652594f,
|
||||
0.89856625f, 0.92664544f, 0.95048443f, 0.96984631f, 0.98453864f,
|
||||
0.99441541f, 0.99937846f, 0.99937846f, 0.99441541f, 0.98453864f,
|
||||
0.96984631f, 0.95048443f, 0.92664544f, 0.89856625f, 0.86652594f,
|
||||
0.83084292f, 0.79187184f, 0.75f, 0.70564355f, 0.65924333f,
|
||||
0.61126047f, 0.56217185f, 0.51246535f, 0.46263495f, 0.41317591f,
|
||||
0.36457977f, 0.31732949f, 0.27189467f, 0.22872687f, 0.1882551f,
|
||||
0.15088159f, 0.11697778f, 0.08688061f, 0.06088921f, 0.03926189f,
|
||||
0.0222136f, 0.00991376f, 0.00248461f, 0.f};
|
||||
|
||||
// Hanning window from Matlab command win = sqrt(hanning(128)).
|
||||
const float kSqrtHanning128[kFftLength] = {
|
||||
0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f,
|
||||
0.09801714032956f, 0.12241067519922f, 0.14673047445536f, 0.17096188876030f,
|
||||
0.19509032201613f, 0.21910124015687f, 0.24298017990326f, 0.26671275747490f,
|
||||
0.29028467725446f, 0.31368174039889f, 0.33688985339222f, 0.35989503653499f,
|
||||
0.38268343236509f, 0.40524131400499f, 0.42755509343028f, 0.44961132965461f,
|
||||
0.47139673682600f, 0.49289819222978f, 0.51410274419322f, 0.53499761988710f,
|
||||
0.55557023301960f, 0.57580819141785f, 0.59569930449243f, 0.61523159058063f,
|
||||
0.63439328416365f, 0.65317284295378f, 0.67155895484702f, 0.68954054473707f,
|
||||
0.70710678118655f, 0.72424708295147f, 0.74095112535496f, 0.75720884650648f,
|
||||
0.77301045336274f, 0.78834642762661f, 0.80320753148064f, 0.81758481315158f,
|
||||
0.83146961230255f, 0.84485356524971f, 0.85772861000027f, 0.87008699110871f,
|
||||
0.88192126434835f, 0.89322430119552f, 0.90398929312344f, 0.91420975570353f,
|
||||
0.92387953251129f, 0.93299279883474f, 0.94154406518302f, 0.94952818059304f,
|
||||
0.95694033573221f, 0.96377606579544f, 0.97003125319454f, 0.97570213003853f,
|
||||
0.98078528040323f, 0.98527764238894f, 0.98917650996478f, 0.99247953459871f,
|
||||
0.99518472667220f, 0.99729045667869f, 0.99879545620517f, 0.99969881869620f,
|
||||
1.00000000000000f, 0.99969881869620f, 0.99879545620517f, 0.99729045667869f,
|
||||
0.99518472667220f, 0.99247953459871f, 0.98917650996478f, 0.98527764238894f,
|
||||
0.98078528040323f, 0.97570213003853f, 0.97003125319454f, 0.96377606579544f,
|
||||
0.95694033573221f, 0.94952818059304f, 0.94154406518302f, 0.93299279883474f,
|
||||
0.92387953251129f, 0.91420975570353f, 0.90398929312344f, 0.89322430119552f,
|
||||
0.88192126434835f, 0.87008699110871f, 0.85772861000027f, 0.84485356524971f,
|
||||
0.83146961230255f, 0.81758481315158f, 0.80320753148064f, 0.78834642762661f,
|
||||
0.77301045336274f, 0.75720884650648f, 0.74095112535496f, 0.72424708295147f,
|
||||
0.70710678118655f, 0.68954054473707f, 0.67155895484702f, 0.65317284295378f,
|
||||
0.63439328416365f, 0.61523159058063f, 0.59569930449243f, 0.57580819141785f,
|
||||
0.55557023301960f, 0.53499761988710f, 0.51410274419322f, 0.49289819222978f,
|
||||
0.47139673682600f, 0.44961132965461f, 0.42755509343028f, 0.40524131400499f,
|
||||
0.38268343236509f, 0.35989503653499f, 0.33688985339222f, 0.31368174039889f,
|
||||
0.29028467725446f, 0.26671275747490f, 0.24298017990326f, 0.21910124015687f,
|
||||
0.19509032201613f, 0.17096188876030f, 0.14673047445536f, 0.12241067519922f,
|
||||
0.09801714032956f, 0.07356456359967f, 0.04906767432742f, 0.02454122852291f};
|
||||
|
||||
bool IsSse2Available() {
|
||||
#if defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
return GetCPUInfo(kSSE2) != 0;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Aec3Fft::Aec3Fft() : ooura_fft_(IsSse2Available()) {}
|
||||
|
||||
// TODO(peah): Change x to be std::array once the rest of the code allows this.
|
||||
void Aec3Fft::ZeroPaddedFft(rtc::ArrayView<const float> x,
|
||||
Window window,
|
||||
FftData* X) const {
|
||||
RTC_DCHECK(X);
|
||||
RTC_DCHECK_EQ(kFftLengthBy2, x.size());
|
||||
std::array<float, kFftLength> fft;
|
||||
std::fill(fft.begin(), fft.begin() + kFftLengthBy2, 0.f);
|
||||
switch (window) {
|
||||
case Window::kRectangular:
|
||||
std::copy(x.begin(), x.end(), fft.begin() + kFftLengthBy2);
|
||||
break;
|
||||
case Window::kHanning:
|
||||
std::transform(x.begin(), x.end(), std::begin(kHanning64),
|
||||
fft.begin() + kFftLengthBy2,
|
||||
[](float a, float b) { return a * b; });
|
||||
break;
|
||||
case Window::kSqrtHanning:
|
||||
RTC_NOTREACHED();
|
||||
break;
|
||||
default:
|
||||
RTC_NOTREACHED();
|
||||
}
|
||||
|
||||
Fft(&fft, X);
|
||||
}
|
||||
|
||||
void Aec3Fft::PaddedFft(rtc::ArrayView<const float> x,
|
||||
rtc::ArrayView<const float> x_old,
|
||||
Window window,
|
||||
FftData* X) const {
|
||||
RTC_DCHECK(X);
|
||||
RTC_DCHECK_EQ(kFftLengthBy2, x.size());
|
||||
RTC_DCHECK_EQ(kFftLengthBy2, x_old.size());
|
||||
std::array<float, kFftLength> fft;
|
||||
|
||||
switch (window) {
|
||||
case Window::kRectangular:
|
||||
std::copy(x_old.begin(), x_old.end(), fft.begin());
|
||||
std::copy(x.begin(), x.end(), fft.begin() + x_old.size());
|
||||
break;
|
||||
case Window::kHanning:
|
||||
RTC_NOTREACHED();
|
||||
break;
|
||||
case Window::kSqrtHanning:
|
||||
std::transform(x_old.begin(), x_old.end(), std::begin(kSqrtHanning128),
|
||||
fft.begin(), std::multiplies<float>());
|
||||
std::transform(x.begin(), x.end(),
|
||||
std::begin(kSqrtHanning128) + x_old.size(),
|
||||
fft.begin() + x_old.size(), std::multiplies<float>());
|
||||
break;
|
||||
default:
|
||||
RTC_NOTREACHED();
|
||||
}
|
||||
|
||||
Fft(&fft, X);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
75
webrtc/modules/audio_processing/aec3/aec3_fft.h
Normal file
75
webrtc/modules/audio_processing/aec3/aec3_fft.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_AUDIO_PROCESSING_AEC3_AEC3_FFT_H_
|
||||
#define MODULES_AUDIO_PROCESSING_AEC3_AEC3_FFT_H_
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "api/array_view.h"
|
||||
#include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h"
|
||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||
#include "modules/audio_processing/aec3/fft_data.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Wrapper class that provides 128 point real valued FFT functionality with the
|
||||
// FftData type.
|
||||
class Aec3Fft {
|
||||
public:
|
||||
enum class Window { kRectangular, kHanning, kSqrtHanning };
|
||||
|
||||
Aec3Fft();
|
||||
|
||||
// Computes the FFT. Note that both the input and output are modified.
|
||||
void Fft(std::array<float, kFftLength>* x, FftData* X) const {
|
||||
RTC_DCHECK(x);
|
||||
RTC_DCHECK(X);
|
||||
ooura_fft_.Fft(x->data());
|
||||
X->CopyFromPackedArray(*x);
|
||||
}
|
||||
// Computes the inverse Fft.
|
||||
void Ifft(const FftData& X, std::array<float, kFftLength>* x) const {
|
||||
RTC_DCHECK(x);
|
||||
X.CopyToPackedArray(x);
|
||||
ooura_fft_.InverseFft(x->data());
|
||||
}
|
||||
|
||||
// Windows the input using a Hanning window, and then adds padding of
|
||||
// kFftLengthBy2 initial zeros before computing the Fft.
|
||||
void ZeroPaddedFft(rtc::ArrayView<const float> x,
|
||||
Window window,
|
||||
FftData* X) const;
|
||||
|
||||
// Concatenates the kFftLengthBy2 values long x and x_old before computing the
|
||||
// Fft. After that, x is copied to x_old.
|
||||
void PaddedFft(rtc::ArrayView<const float> x,
|
||||
rtc::ArrayView<const float> x_old,
|
||||
FftData* X) const {
|
||||
PaddedFft(x, x_old, Window::kRectangular, X);
|
||||
}
|
||||
|
||||
// Padded Fft using a time-domain window.
|
||||
void PaddedFft(rtc::ArrayView<const float> x,
|
||||
rtc::ArrayView<const float> x_old,
|
||||
Window window,
|
||||
FftData* X) const;
|
||||
|
||||
private:
|
||||
const OouraFft ooura_fft_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(Aec3Fft);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_AUDIO_PROCESSING_AEC3_AEC3_FFT_H_
|
477
webrtc/modules/audio_processing/aec3/aec_state.cc
Normal file
477
webrtc/modules/audio_processing/aec3/aec_state.cc
Normal file
@ -0,0 +1,477 @@
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "modules/audio_processing/aec3/aec_state.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/array_view.h"
|
||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||
#include "modules/audio_processing/logging/apm_data_dumper.h"
|
||||
#include "rtc_base/atomic_ops.h"
|
||||
#include "rtc_base/checks.h"
|
||||
#include "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
|
||||
bool DeactivateInitialStateResetAtEchoPathChange() {
|
||||
return field_trial::IsEnabled(
|
||||
"WebRTC-Aec3DeactivateInitialStateResetKillSwitch");
|
||||
}
|
||||
|
||||
bool FullResetAtEchoPathChange() {
|
||||
return !field_trial::IsEnabled("WebRTC-Aec3AecStateFullResetKillSwitch");
|
||||
}
|
||||
|
||||
bool SubtractorAnalyzerResetAtEchoPathChange() {
|
||||
return !field_trial::IsEnabled(
|
||||
"WebRTC-Aec3AecStateSubtractorAnalyzerResetKillSwitch");
|
||||
}
|
||||
|
||||
void ComputeAvgRenderReverb(
|
||||
const SpectrumBuffer& spectrum_buffer,
|
||||
int delay_blocks,
|
||||
float reverb_decay,
|
||||
ReverbModel* reverb_model,
|
||||
rtc::ArrayView<float, kFftLengthBy2Plus1> reverb_power_spectrum) {
|
||||
RTC_DCHECK(reverb_model);
|
||||
const size_t num_render_channels = spectrum_buffer.buffer[0].size();
|
||||
int idx_at_delay =
|
||||
spectrum_buffer.OffsetIndex(spectrum_buffer.read, delay_blocks);
|
||||
int idx_past = spectrum_buffer.IncIndex(idx_at_delay);
|
||||
|
||||
std::array<float, kFftLengthBy2Plus1> X2_data;
|
||||
rtc::ArrayView<const float> X2;
|
||||
if (num_render_channels > 1) {
|
||||
auto average_channels =
|
||||
[](size_t num_render_channels,
|
||||
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>>
|
||||
spectrum_band_0,
|
||||
rtc::ArrayView<float, kFftLengthBy2Plus1> render_power) {
|
||||
std::fill(render_power.begin(), render_power.end(), 0.f);
|
||||
for (size_t ch = 0; ch < num_render_channels; ++ch) {
|
||||
for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
|
||||
render_power[k] += spectrum_band_0[ch][k];
|
||||
}
|
||||
}
|
||||
const float normalizer = 1.f / num_render_channels;
|
||||
for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) {
|
||||
render_power[k] *= normalizer;
|
||||
}
|
||||
};
|
||||
average_channels(num_render_channels, spectrum_buffer.buffer[idx_past],
|
||||
X2_data);
|
||||
reverb_model->UpdateReverbNoFreqShaping(
|
||||
X2_data, /*power_spectrum_scaling=*/1.0f, reverb_decay);
|
||||
|
||||
average_channels(num_render_channels, spectrum_buffer.buffer[idx_at_delay],
|
||||
X2_data);
|
||||
X2 = X2_data;
|
||||
} else {
|
||||
reverb_model->UpdateReverbNoFreqShaping(
|
||||
spectrum_buffer.buffer[idx_past][/*channel=*/0],
|
||||
/*power_spectrum_scaling=*/1.0f, reverb_decay);
|
||||
|
||||
X2 = spectrum_buffer.buffer[idx_at_delay][/*channel=*/0];
|
||||
}
|
||||
|
||||
rtc::ArrayView<const float, kFftLengthBy2Plus1> reverb_power =
|
||||
reverb_model->reverb();
|
||||
for (size_t k = 0; k < X2.size(); ++k) {
|
||||
reverb_power_spectrum[k] = X2[k] + reverb_power[k];
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int AecState::instance_count_ = 0;
|
||||
|
||||
void AecState::GetResidualEchoScaling(
|
||||
rtc::ArrayView<float> residual_scaling) const {
|
||||
bool filter_has_had_time_to_converge;
|
||||
if (config_.filter.conservative_initial_phase) {
|
||||
filter_has_had_time_to_converge =
|
||||
strong_not_saturated_render_blocks_ >= 1.5f * kNumBlocksPerSecond;
|
||||
} else {
|
||||
filter_has_had_time_to_converge =
|
||||
strong_not_saturated_render_blocks_ >= 0.8f * kNumBlocksPerSecond;
|
||||
}
|
||||
echo_audibility_.GetResidualEchoScaling(filter_has_had_time_to_converge,
|
||||
residual_scaling);
|
||||
}
|
||||
|
||||
absl::optional<float> AecState::ErleUncertainty() const {
|
||||
if (SaturatedEcho()) {
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
AecState::AecState(const EchoCanceller3Config& config,
|
||||
size_t num_capture_channels)
|
||||
: data_dumper_(
|
||||
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
|
||||
config_(config),
|
||||
num_capture_channels_(num_capture_channels),
|
||||
deactivate_initial_state_reset_at_echo_path_change_(
|
||||
DeactivateInitialStateResetAtEchoPathChange()),
|
||||
full_reset_at_echo_path_change_(FullResetAtEchoPathChange()),
|
||||
subtractor_analyzer_reset_at_echo_path_change_(
|
||||
SubtractorAnalyzerResetAtEchoPathChange()),
|
||||
initial_state_(config_),
|
||||
delay_state_(config_, num_capture_channels_),
|
||||
transparent_state_(TransparentMode::Create(config_)),
|
||||
filter_quality_state_(config_, num_capture_channels_),
|
||||
erl_estimator_(2 * kNumBlocksPerSecond),
|
||||
erle_estimator_(2 * kNumBlocksPerSecond, config_, num_capture_channels_),
|
||||
filter_analyzer_(config_, num_capture_channels_),
|
||||
echo_audibility_(
|
||||
config_.echo_audibility.use_stationarity_properties_at_init),
|
||||
reverb_model_estimator_(config_, num_capture_channels_),
|
||||
subtractor_output_analyzer_(num_capture_channels_) {}
|
||||
|
||||
AecState::~AecState() = default;
|
||||
|
||||
void AecState::HandleEchoPathChange(
|
||||
const EchoPathVariability& echo_path_variability) {
|
||||
const auto full_reset = [&]() {
|
||||
filter_analyzer_.Reset();
|
||||
capture_signal_saturation_ = false;
|
||||
strong_not_saturated_render_blocks_ = 0;
|
||||
blocks_with_active_render_ = 0;
|
||||
if (!deactivate_initial_state_reset_at_echo_path_change_) {
|
||||
initial_state_.Reset();
|
||||
}
|
||||
if (transparent_state_) {
|
||||
transparent_state_->Reset();
|
||||
}
|
||||
erle_estimator_.Reset(true);
|
||||
erl_estimator_.Reset();
|
||||
filter_quality_state_.Reset();
|
||||
};
|
||||
|
||||
// TODO(peah): Refine the reset scheme according to the type of gain and
|
||||
// delay adjustment.
|
||||
|
||||
if (full_reset_at_echo_path_change_ &&
|
||||
echo_path_variability.delay_change !=
|
||||
EchoPathVariability::DelayAdjustment::kNone) {
|
||||
full_reset();
|
||||
} else if (echo_path_variability.gain_change) {
|
||||
erle_estimator_.Reset(false);
|
||||
}
|
||||
if (subtractor_analyzer_reset_at_echo_path_change_) {
|
||||
subtractor_output_analyzer_.HandleEchoPathChange();
|
||||
}
|
||||
}
|
||||
|
||||
void AecState::Update(
|
||||
const absl::optional<DelayEstimate>& external_delay,
|
||||
rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>>
|
||||
adaptive_filter_frequency_responses,
|
||||
rtc::ArrayView<const std::vector<float>> adaptive_filter_impulse_responses,
|
||||
const RenderBuffer& render_buffer,
|
||||
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2_refined,
|
||||
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
|
||||
rtc::ArrayView<const SubtractorOutput> subtractor_output) {
|
||||
RTC_DCHECK_EQ(num_capture_channels_, Y2.size());
|
||||
RTC_DCHECK_EQ(num_capture_channels_, subtractor_output.size());
|
||||
RTC_DCHECK_EQ(num_capture_channels_,
|
||||
adaptive_filter_frequency_responses.size());
|
||||
RTC_DCHECK_EQ(num_capture_channels_,
|
||||
adaptive_filter_impulse_responses.size());
|
||||
|
||||
// Analyze the filter outputs and filters.
|
||||
bool any_filter_converged;
|
||||
bool all_filters_diverged;
|
||||
subtractor_output_analyzer_.Update(subtractor_output, &any_filter_converged,
|
||||
&all_filters_diverged);
|
||||
|
||||
bool any_filter_consistent;
|
||||
float max_echo_path_gain;
|
||||
filter_analyzer_.Update(adaptive_filter_impulse_responses, render_buffer,
|
||||
&any_filter_consistent, &max_echo_path_gain);
|
||||
|
||||
// Estimate the direct path delay of the filter.
|
||||
if (config_.filter.use_linear_filter) {
|
||||
delay_state_.Update(filter_analyzer_.FilterDelaysBlocks(), external_delay,
|
||||
strong_not_saturated_render_blocks_);
|
||||
}
|
||||
|
||||
const std::vector<std::vector<float>>& aligned_render_block =
|
||||
render_buffer.Block(-delay_state_.MinDirectPathFilterDelay())[0];
|
||||
|
||||
// Update render counters.
|
||||
bool active_render = false;
|
||||
for (size_t ch = 0; ch < aligned_render_block.size(); ++ch) {
|
||||
const float render_energy = std::inner_product(
|
||||
aligned_render_block[ch].begin(), aligned_render_block[ch].end(),
|
||||
aligned_render_block[ch].begin(), 0.f);
|
||||
if (render_energy > (config_.render_levels.active_render_limit *
|
||||
config_.render_levels.active_render_limit) *
|
||||
kFftLengthBy2) {
|
||||
active_render = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
blocks_with_active_render_ += active_render ? 1 : 0;
|
||||
strong_not_saturated_render_blocks_ +=
|
||||
active_render && !SaturatedCapture() ? 1 : 0;
|
||||
|
||||
std::array<float, kFftLengthBy2Plus1> avg_render_spectrum_with_reverb;
|
||||
|
||||
ComputeAvgRenderReverb(render_buffer.GetSpectrumBuffer(),
|
||||
delay_state_.MinDirectPathFilterDelay(), ReverbDecay(),
|
||||
&avg_render_reverb_, avg_render_spectrum_with_reverb);
|
||||
|
||||
if (config_.echo_audibility.use_stationarity_properties) {
|
||||
// Update the echo audibility evaluator.
|
||||
echo_audibility_.Update(render_buffer, avg_render_reverb_.reverb(),
|
||||
delay_state_.MinDirectPathFilterDelay(),
|
||||
delay_state_.ExternalDelayReported());
|
||||
}
|
||||
|
||||
// Update the ERL and ERLE measures.
|
||||
if (initial_state_.TransitionTriggered()) {
|
||||
erle_estimator_.Reset(false);
|
||||
}
|
||||
|
||||
erle_estimator_.Update(render_buffer, adaptive_filter_frequency_responses,
|
||||
avg_render_spectrum_with_reverb, Y2, E2_refined,
|
||||
subtractor_output_analyzer_.ConvergedFilters());
|
||||
|
||||
erl_estimator_.Update(
|
||||
subtractor_output_analyzer_.ConvergedFilters(),
|
||||
render_buffer.Spectrum(delay_state_.MinDirectPathFilterDelay()), Y2);
|
||||
|
||||
// Detect and flag echo saturation.
|
||||
if (config_.ep_strength.echo_can_saturate) {
|
||||
saturation_detector_.Update(aligned_render_block, SaturatedCapture(),
|
||||
UsableLinearEstimate(), subtractor_output,
|
||||
max_echo_path_gain);
|
||||
} else {
|
||||
RTC_DCHECK(!saturation_detector_.SaturatedEcho());
|
||||
}
|
||||
|
||||
// Update the decision on whether to use the initial state parameter set.
|
||||
initial_state_.Update(active_render, SaturatedCapture());
|
||||
|
||||
// Detect whether the transparent mode should be activated.
|
||||
if (transparent_state_) {
|
||||
transparent_state_->Update(delay_state_.MinDirectPathFilterDelay(),
|
||||
any_filter_consistent, any_filter_converged,
|
||||
all_filters_diverged, active_render,
|
||||
SaturatedCapture());
|
||||
}
|
||||
|
||||
// Analyze the quality of the filter.
|
||||
filter_quality_state_.Update(active_render, TransparentModeActive(),
|
||||
SaturatedCapture(), external_delay,
|
||||
any_filter_converged);
|
||||
|
||||
// Update the reverb estimate.
|
||||
const bool stationary_block =
|
||||
config_.echo_audibility.use_stationarity_properties &&
|
||||
echo_audibility_.IsBlockStationary();
|
||||
|
||||
reverb_model_estimator_.Update(
|
||||
filter_analyzer_.GetAdjustedFilters(),
|
||||
adaptive_filter_frequency_responses,
|
||||
erle_estimator_.GetInstLinearQualityEstimates(),
|
||||
delay_state_.DirectPathFilterDelays(),
|
||||
filter_quality_state_.UsableLinearFilterOutputs(), stationary_block);
|
||||
|
||||
erle_estimator_.Dump(data_dumper_);
|
||||
reverb_model_estimator_.Dump(data_dumper_.get());
|
||||
data_dumper_->DumpRaw("aec3_active_render", active_render);
|
||||
data_dumper_->DumpRaw("aec3_erl", Erl());
|
||||
data_dumper_->DumpRaw("aec3_erl_time_domain", ErlTimeDomain());
|
||||
data_dumper_->DumpRaw("aec3_erle", Erle()[0]);
|
||||
data_dumper_->DumpRaw("aec3_usable_linear_estimate", UsableLinearEstimate());
|
||||
data_dumper_->DumpRaw("aec3_transparent_mode", TransparentModeActive());
|
||||
data_dumper_->DumpRaw("aec3_filter_delay",
|
||||
filter_analyzer_.MinFilterDelayBlocks());
|
||||
|
||||
data_dumper_->DumpRaw("aec3_any_filter_consistent", any_filter_consistent);
|
||||
data_dumper_->DumpRaw("aec3_initial_state",
|
||||
initial_state_.InitialStateActive());
|
||||
data_dumper_->DumpRaw("aec3_capture_saturation", SaturatedCapture());
|
||||
data_dumper_->DumpRaw("aec3_echo_saturation", SaturatedEcho());
|
||||
data_dumper_->DumpRaw("aec3_any_filter_converged", any_filter_converged);
|
||||
data_dumper_->DumpRaw("aec3_all_filters_diverged", all_filters_diverged);
|
||||
|
||||
data_dumper_->DumpRaw("aec3_external_delay_avaliable",
|
||||
external_delay ? 1 : 0);
|
||||
data_dumper_->DumpRaw("aec3_filter_tail_freq_resp_est",
|
||||
GetReverbFrequencyResponse());
|
||||
}
|
||||
|
||||
AecState::InitialState::InitialState(const EchoCanceller3Config& config)
|
||||
: conservative_initial_phase_(config.filter.conservative_initial_phase),
|
||||
initial_state_seconds_(config.filter.initial_state_seconds) {
|
||||
Reset();
|
||||
}
|
||||
void AecState::InitialState::InitialState::Reset() {
|
||||
initial_state_ = true;
|
||||
strong_not_saturated_render_blocks_ = 0;
|
||||
}
|
||||
void AecState::InitialState::InitialState::Update(bool active_render,
|
||||
bool saturated_capture) {
|
||||
strong_not_saturated_render_blocks_ +=
|
||||
active_render && !saturated_capture ? 1 : 0;
|
||||
|
||||
// Flag whether the initial state is still active.
|
||||
bool prev_initial_state = initial_state_;
|
||||
if (conservative_initial_phase_) {
|
||||
initial_state_ =
|
||||
strong_not_saturated_render_blocks_ < 5 * kNumBlocksPerSecond;
|
||||
} else {
|
||||
initial_state_ = strong_not_saturated_render_blocks_ <
|
||||
initial_state_seconds_ * kNumBlocksPerSecond;
|
||||
}
|
||||
|
||||
// Flag whether the transition from the initial state has started.
|
||||
transition_triggered_ = !initial_state_ && prev_initial_state;
|
||||
}
|
||||
|
||||
AecState::FilterDelay::FilterDelay(const EchoCanceller3Config& config,
|
||||
size_t num_capture_channels)
|
||||
: delay_headroom_blocks_(config.delay.delay_headroom_samples / kBlockSize),
|
||||
filter_delays_blocks_(num_capture_channels, delay_headroom_blocks_),
|
||||
min_filter_delay_(delay_headroom_blocks_) {}
|
||||
|
||||
void AecState::FilterDelay::Update(
|
||||
rtc::ArrayView<const int> analyzer_filter_delay_estimates_blocks,
|
||||
const absl::optional<DelayEstimate>& external_delay,
|
||||
size_t blocks_with_proper_filter_adaptation) {
|
||||
// Update the delay based on the external delay.
|
||||
if (external_delay &&
|
||||
(!external_delay_ || external_delay_->delay != external_delay->delay)) {
|
||||
external_delay_ = external_delay;
|
||||
external_delay_reported_ = true;
|
||||
}
|
||||
|
||||
// Override the estimated delay if it is not certain that the filter has had
|
||||
// time to converge.
|
||||
const bool delay_estimator_may_not_have_converged =
|
||||
blocks_with_proper_filter_adaptation < 2 * kNumBlocksPerSecond;
|
||||
if (delay_estimator_may_not_have_converged && external_delay_) {
|
||||
const int delay_guess = delay_headroom_blocks_;
|
||||
std::fill(filter_delays_blocks_.begin(), filter_delays_blocks_.end(),
|
||||
delay_guess);
|
||||
} else {
|
||||
RTC_DCHECK_EQ(filter_delays_blocks_.size(),
|
||||
analyzer_filter_delay_estimates_blocks.size());
|
||||
std::copy(analyzer_filter_delay_estimates_blocks.begin(),
|
||||
analyzer_filter_delay_estimates_blocks.end(),
|
||||
filter_delays_blocks_.begin());
|
||||
}
|
||||
|
||||
min_filter_delay_ = *std::min_element(filter_delays_blocks_.begin(),
|
||||
filter_delays_blocks_.end());
|
||||
}
|
||||
|
||||
AecState::FilteringQualityAnalyzer::FilteringQualityAnalyzer(
|
||||
const EchoCanceller3Config& config,
|
||||
size_t num_capture_channels)
|
||||
: use_linear_filter_(config.filter.use_linear_filter),
|
||||
usable_linear_filter_estimates_(num_capture_channels, false) {}
|
||||
|
||||
void AecState::FilteringQualityAnalyzer::Reset() {
|
||||
std::fill(usable_linear_filter_estimates_.begin(),
|
||||
usable_linear_filter_estimates_.end(), false);
|
||||
overall_usable_linear_estimates_ = false;
|
||||
filter_update_blocks_since_reset_ = 0;
|
||||
}
|
||||
|
||||
void AecState::FilteringQualityAnalyzer::Update(
|
||||
bool active_render,
|
||||
bool transparent_mode,
|
||||
bool saturated_capture,
|
||||
const absl::optional<DelayEstimate>& external_delay,
|
||||
bool any_filter_converged) {
|
||||
// Update blocks counter.
|
||||
const bool filter_update = active_render && !saturated_capture;
|
||||
filter_update_blocks_since_reset_ += filter_update ? 1 : 0;
|
||||
filter_update_blocks_since_start_ += filter_update ? 1 : 0;
|
||||
|
||||
// Store convergence flag when observed.
|
||||
convergence_seen_ = convergence_seen_ || any_filter_converged;
|
||||
|
||||
// Verify requirements for achieving a decent filter. The requirements for
|
||||
// filter adaptation at call startup are more restrictive than after an
|
||||
// in-call reset.
|
||||
const bool sufficient_data_to_converge_at_startup =
|
||||
filter_update_blocks_since_start_ > kNumBlocksPerSecond * 0.4f;
|
||||
const bool sufficient_data_to_converge_at_reset =
|
||||
sufficient_data_to_converge_at_startup &&
|
||||
filter_update_blocks_since_reset_ > kNumBlocksPerSecond * 0.2f;
|
||||
|
||||
// The linear filter can only be used if it has had time to converge.
|
||||
overall_usable_linear_estimates_ = sufficient_data_to_converge_at_startup &&
|
||||
sufficient_data_to_converge_at_reset;
|
||||
|
||||
// The linear filter can only be used if an external delay or convergence have
|
||||
// been identified
|
||||
overall_usable_linear_estimates_ =
|
||||
overall_usable_linear_estimates_ && (external_delay || convergence_seen_);
|
||||
|
||||
// If transparent mode is on, deactivate usign the linear filter.
|
||||
overall_usable_linear_estimates_ =
|
||||
overall_usable_linear_estimates_ && !transparent_mode;
|
||||
|
||||
if (use_linear_filter_) {
|
||||
std::fill(usable_linear_filter_estimates_.begin(),
|
||||
usable_linear_filter_estimates_.end(),
|
||||
overall_usable_linear_estimates_);
|
||||
}
|
||||
}
|
||||
|
||||
void AecState::SaturationDetector::Update(
|
||||
rtc::ArrayView<const std::vector<float>> x,
|
||||
bool saturated_capture,
|
||||
bool usable_linear_estimate,
|
||||
rtc::ArrayView<const SubtractorOutput> subtractor_output,
|
||||
float echo_path_gain) {
|
||||
saturated_echo_ = false;
|
||||
if (!saturated_capture) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (usable_linear_estimate) {
|
||||
constexpr float kSaturationThreshold = 20000.f;
|
||||
for (size_t ch = 0; ch < subtractor_output.size(); ++ch) {
|
||||
saturated_echo_ =
|
||||
saturated_echo_ ||
|
||||
(subtractor_output[ch].s_refined_max_abs > kSaturationThreshold ||
|
||||
subtractor_output[ch].s_coarse_max_abs > kSaturationThreshold);
|
||||
}
|
||||
} else {
|
||||
float max_sample = 0.f;
|
||||
for (auto& channel : x) {
|
||||
for (float sample : channel) {
|
||||
max_sample = std::max(max_sample, fabsf(sample));
|
||||
}
|
||||
}
|
||||
|
||||
const float kMargin = 10.f;
|
||||
float peak_echo_amplitude = max_sample * echo_path_gain * kMargin;
|
||||
saturated_echo_ = saturated_echo_ || peak_echo_amplitude > 32000;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
294
webrtc/modules/audio_processing/aec3/aec_state.h
Normal file
294
webrtc/modules/audio_processing/aec3/aec_state.h
Normal file
@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef MODULES_AUDIO_PROCESSING_AEC3_AEC_STATE_H_
|
||||
#define MODULES_AUDIO_PROCESSING_AEC3_AEC_STATE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/array_view.h"
|
||||
#include "api/audio/echo_canceller3_config.h"
|
||||
#include "modules/audio_processing/aec3/aec3_common.h"
|
||||
#include "modules/audio_processing/aec3/delay_estimate.h"
|
||||
#include "modules/audio_processing/aec3/echo_audibility.h"
|
||||
#include "modules/audio_processing/aec3/echo_path_variability.h"
|
||||
#include "modules/audio_processing/aec3/erl_estimator.h"
|
||||
#include "modules/audio_processing/aec3/erle_estimator.h"
|
||||
#include "modules/audio_processing/aec3/filter_analyzer.h"
|
||||
#include "modules/audio_processing/aec3/render_buffer.h"
|
||||
#include "modules/audio_processing/aec3/reverb_model_estimator.h"
|
||||
#include "modules/audio_processing/aec3/subtractor_output.h"
|
||||
#include "modules/audio_processing/aec3/subtractor_output_analyzer.h"
|
||||
#include "modules/audio_processing/aec3/transparent_mode.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class ApmDataDumper;
|
||||
|
||||
// Handles the state and the conditions for the echo removal functionality.
|
||||
class AecState {
|
||||
public:
|
||||
AecState(const EchoCanceller3Config& config, size_t num_capture_channels);
|
||||
~AecState();
|
||||
|
||||
// Returns whether the echo subtractor can be used to determine the residual
|
||||
// echo.
|
||||
bool UsableLinearEstimate() const {
|
||||
return filter_quality_state_.LinearFilterUsable() &&
|
||||
config_.filter.use_linear_filter;
|
||||
}
|
||||
|
||||
// Returns whether the echo subtractor output should be used as output.
|
||||
bool UseLinearFilterOutput() const {
|
||||
return filter_quality_state_.LinearFilterUsable() &&
|
||||
config_.filter.use_linear_filter;
|
||||
}
|
||||
|
||||
// Returns whether the render signal is currently active.
|
||||
bool ActiveRender() const { return blocks_with_active_render_ > 200; }
|
||||
|
||||
// Returns the appropriate scaling of the residual echo to match the
|
||||
// audibility.
|
||||
void GetResidualEchoScaling(rtc::ArrayView<float> residual_scaling) const;
|
||||
|
||||
// Returns whether the stationary properties of the signals are used in the
|
||||
// aec.
|
||||
bool UseStationarityProperties() const {
|
||||
return config_.echo_audibility.use_stationarity_properties;
|
||||
}
|
||||
|
||||
// Returns the ERLE.
|
||||
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Erle() const {
|
||||
return erle_estimator_.Erle();
|
||||
}
|
||||
|
||||
// Returns an offset to apply to the estimation of the residual echo
|
||||
// computation. Returning nullopt means that no offset should be used, while
|
||||
// any other value will be applied as a multiplier to the estimated residual
|
||||
// echo.
|
||||
absl::optional<float> ErleUncertainty() const;
|
||||
|
||||
// Returns the fullband ERLE estimate in log2 units.
|
||||
float FullBandErleLog2() const { return erle_estimator_.FullbandErleLog2(); }
|
||||
|
||||
// Returns the ERL.
|
||||
const std::array<float, kFftLengthBy2Plus1>& Erl() const {
|
||||
return erl_estimator_.Erl();
|
||||
}
|
||||
|
||||
// Returns the time-domain ERL.
|
||||
float ErlTimeDomain() const { return erl_estimator_.ErlTimeDomain(); }
|
||||
|
||||
// Returns the delay estimate based on the linear filter.
|
||||
int MinDirectPathFilterDelay() const {
|
||||
return delay_state_.MinDirectPathFilterDelay();
|
||||
}
|
||||
|
||||
// Returns whether the capture signal is saturated.
|
||||
bool SaturatedCapture() const { return capture_signal_saturation_; }
|
||||
|
||||
// Returns whether the echo signal is saturated.
|
||||
bool SaturatedEcho() const { return saturation_detector_.SaturatedEcho(); }
|
||||
|
||||
// Updates the capture signal saturation.
|
||||
void UpdateCaptureSaturation(bool capture_signal_saturation) {
|
||||
capture_signal_saturation_ = capture_signal_saturation;
|
||||
}
|
||||
|
||||
// Returns whether the transparent mode is active
|
||||
bool TransparentModeActive() const {
|
||||
return transparent_state_ && transparent_state_->Active();
|
||||
}
|
||||
|
||||
// Takes appropriate action at an echo path change.
|
||||
void HandleEchoPathChange(const EchoPathVariability& echo_path_variability);
|
||||
|
||||
// Returns the decay factor for the echo reverberation.
|
||||
float ReverbDecay() const { return reverb_model_estimator_.ReverbDecay(); }
|
||||
|
||||
// Return the frequency response of the reverberant echo.
|
||||
rtc::ArrayView<const float> GetReverbFrequencyResponse() const {
|
||||
return reverb_model_estimator_.GetReverbFrequencyResponse();
|
||||
}
|
||||
|
||||
// Returns whether the transition for going out of the initial stated has
|
||||
// been triggered.
|
||||
bool TransitionTriggered() const {
|
||||
return initial_state_.TransitionTriggered();
|
||||
}
|
||||
|
||||
// Updates the aec state.
|
||||
// TODO(bugs.webrtc.org/10913): Compute multi-channel ERL.
|
||||
void Update(
|
||||
const absl::optional<DelayEstimate>& external_delay,
|
||||
rtc::ArrayView<const std::vector<std::array<float, kFftLengthBy2Plus1>>>
|
||||
adaptive_filter_frequency_responses,
|
||||
rtc::ArrayView<const std::vector<float>>
|
||||
adaptive_filter_impulse_responses,
|
||||
const RenderBuffer& render_buffer,
|
||||
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> E2_refined,
|
||||
rtc::ArrayView<const std::array<float, kFftLengthBy2Plus1>> Y2,
|
||||
rtc::ArrayView<const SubtractorOutput> subtractor_output);
|
||||
|
||||
// Returns filter length in blocks.
|
||||
int FilterLengthBlocks() const {
|
||||
// All filters have the same length, so arbitrarily return channel 0 length.
|
||||
return filter_analyzer_.FilterLengthBlocks();
|
||||
}
|
||||
|
||||
private:
|
||||
static int instance_count_;
|
||||
std::unique_ptr<ApmDataDumper> data_dumper_;
|
||||
const EchoCanceller3Config config_;
|
||||
const size_t num_capture_channels_;
|
||||
const bool deactivate_initial_state_reset_at_echo_path_change_;
|
||||
const bool full_reset_at_echo_path_change_;
|
||||
const bool subtractor_analyzer_reset_at_echo_path_change_;
|
||||
|
||||
// Class for controlling the transition from the intial state, which in turn
|
||||
// controls when the filter parameters for the initial state should be used.
|
||||
class InitialState {
|
||||
public:
|
||||
explicit InitialState(const EchoCanceller3Config& config);
|
||||
// Resets the state to again begin in the initial state.
|
||||
void Reset();
|
||||
|
||||
// Updates the state based on new data.
|
||||
void Update(bool active_render, bool saturated_capture);
|
||||
|
||||
// Returns whether the initial state is active or not.
|
||||
bool InitialStateActive() const { return initial_state_; }
|
||||
|
||||
// Returns that the transition from the initial state has was started.
|
||||
bool TransitionTriggered() const { return transition_triggered_; }
|
||||
|
||||
private:
|
||||
const bool conservative_initial_phase_;
|
||||
const float initial_state_seconds_;
|
||||
bool transition_triggered_ = false;
|
||||
bool initial_state_ = true;
|
||||
size_t strong_not_saturated_render_blocks_ = 0;
|
||||
} initial_state_;
|
||||
|
||||
// Class for choosing the direct-path delay relative to the beginning of the
|
||||
// filter, as well as any other data related to the delay used within
|
||||
// AecState.
|
||||
class FilterDelay {
|
||||
public:
|
||||
FilterDelay(const EchoCanceller3Config& config,
|
||||
size_t num_capture_channels);
|
||||
|
||||
// Returns whether an external delay has been reported to the AecState (from
|
||||
// the delay estimator).
|
||||
bool ExternalDelayReported() const { return external_delay_reported_; }
|
||||
|
||||
// Returns the delay in blocks relative to the beginning of the filter that
|
||||
// corresponds to the direct path of the echo.
|
||||
rtc::ArrayView<const int> DirectPathFilterDelays() const {
|
||||
return filter_delays_blocks_;
|
||||
}
|
||||
|
||||
// Returns the minimum delay among the direct path delays relative to the
|
||||
// beginning of the filter
|
||||
int MinDirectPathFilterDelay() const { return min_filter_delay_; }
|
||||
|
||||
// Updates the delay estimates based on new data.
|
||||
void Update(
|
||||
rtc::ArrayView<const int> analyzer_filter_delay_estimates_blocks,
|
||||
const absl::optional<DelayEstimate>& external_delay,
|
||||
size_t blocks_with_proper_filter_adaptation);
|
||||
|
||||
private:
|
||||
const int delay_headroom_blocks_;
|
||||
bool external_delay_reported_ = false;
|
||||
std::vector<int> filter_delays_blocks_;
|
||||
int min_filter_delay_;
|
||||
absl::optional<DelayEstimate> external_delay_;
|
||||
} delay_state_;
|
||||
|
||||
// Classifier for toggling transparent mode when there is no echo.
|
||||
std::unique_ptr<TransparentMode> transparent_state_;
|
||||
|
||||
// Class for analyzing how well the linear filter is, and can be expected to,
|
||||
// perform on the current signals. The purpose of this is for using to
|
||||
// select the echo suppression functionality as well as the input to the echo
|
||||
// suppressor.
|
||||
class FilteringQualityAnalyzer {
|
||||
public:
|
||||
FilteringQualityAnalyzer(const EchoCanceller3Config& config,
|
||||
size_t num_capture_channels);
|
||||
|
||||
// Returns whether the linear filter can be used for the echo
|
||||
// canceller output.
|
||||
bool LinearFilterUsable() const { return overall_usable_linear_estimates_; }
|
||||
|
||||
// Returns whether an individual filter output can be used for the echo
|
||||
// canceller output.
|
||||
const std::vector<bool>& UsableLinearFilterOutputs() const {
|
||||
return usable_linear_filter_estimates_;
|
||||
}
|
||||
|
||||
// Resets the state of the analyzer.
|
||||
void Reset();
|
||||
|
||||
// Updates the analysis based on new data.
|
||||
void Update(bool active_render,
|
||||
bool transparent_mode,
|
||||
bool saturated_capture,
|
||||
const absl::optional<DelayEstimate>& external_delay,
|
||||
bool any_filter_converged);
|
||||
|
||||
private:
|
||||
const bool use_linear_filter_;
|
||||
bool overall_usable_linear_estimates_ = false;
|
||||
size_t filter_update_blocks_since_reset_ = 0;
|
||||
size_t filter_update_blocks_since_start_ = 0;
|
||||
bool convergence_seen_ = false;
|
||||
std::vector<bool> usable_linear_filter_estimates_;
|
||||
} filter_quality_state_;
|
||||
|
||||
// Class for detecting whether the echo is to be considered to be
|
||||
// saturated.
|
||||
class SaturationDetector {
|
||||
public:
|
||||
// Returns whether the echo is to be considered saturated.
|
||||
bool SaturatedEcho() const { return saturated_echo_; }
|
||||
|
||||
// Updates the detection decision based on new data.
|
||||
void Update(rtc::ArrayView<const std::vector<float>> x,
|
||||
bool saturated_capture,
|
||||
bool usable_linear_estimate,
|
||||
rtc::ArrayView<const SubtractorOutput> subtractor_output,
|
||||
float echo_path_gain);
|
||||
|
||||
private:
|
||||
bool saturated_echo_ = false;
|
||||
} saturation_detector_;
|
||||
|
||||
ErlEstimator erl_estimator_;
|
||||
ErleEstimator erle_estimator_;
|
||||
size_t strong_not_saturated_render_blocks_ = 0;
|
||||
size_t blocks_with_active_render_ = 0;
|
||||
bool capture_signal_saturation_ = false;
|
||||
FilterAnalyzer filter_analyzer_;
|
||||
EchoAudibility echo_audibility_;
|
||||
ReverbModelEstimator reverb_model_estimator_;
|
||||
ReverbModel avg_render_reverb_;
|
||||
SubtractorOutputAnalyzer subtractor_output_analyzer_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_AUDIO_PROCESSING_AEC3_AEC_STATE_H_
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user