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:
Arun Raghavan
2020-10-12 18:08:02 -04:00
parent b1b02581d3
commit bcec8b0b21
859 changed files with 76187 additions and 49580 deletions

247
webrtc/modules/BUILD.gn Normal file
View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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"
/*

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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_ \
*/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 */

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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] = {

View File

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

View File

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

View File

@ -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()

View File

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

View File

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

View File

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

View File

@ -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 ************************/

View File

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

View File

@ -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 ************************/

View File

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

View File

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

View File

@ -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 */

View File

@ -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_ \
*/

View File

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

View File

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

View File

@ -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'
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View 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

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

View 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

View 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

View File

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

View File

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

View 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

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

View 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

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

View 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

View 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