Bump to WebRTC M120 release
Some API deprecation -- ExperimentalAgc and ExperimentalNs are gone. We're continuing to carry iSAC even though it's gone upstream, but maybe we'll want to drop that soon.
This commit is contained in:
@ -48,8 +48,10 @@ rtc_library("common_audio") {
|
||||
"../api:array_view",
|
||||
"../rtc_base:checks",
|
||||
"../rtc_base:gtest_prod",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
"../rtc_base:logging",
|
||||
"../rtc_base:safe_conversions",
|
||||
"../rtc_base:sanitizer",
|
||||
"../rtc_base:timeutils",
|
||||
"../rtc_base/memory:aligned_malloc",
|
||||
"../rtc_base/system:arch",
|
||||
"../rtc_base/system:file_wrapper",
|
||||
@ -180,7 +182,6 @@ rtc_library("common_audio_c") {
|
||||
":common_audio_cc",
|
||||
"../rtc_base:checks",
|
||||
"../rtc_base:compile_assert_c",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
"../rtc_base:sanitizer",
|
||||
"../rtc_base/system:arch",
|
||||
"../system_wrappers",
|
||||
@ -196,7 +197,7 @@ rtc_library("common_audio_cc") {
|
||||
]
|
||||
|
||||
deps = [
|
||||
"../rtc_base:rtc_base_approved",
|
||||
"../rtc_base:safe_conversions",
|
||||
"../system_wrappers",
|
||||
]
|
||||
}
|
||||
@ -205,7 +206,6 @@ rtc_source_set("sinc_resampler") {
|
||||
sources = [ "resampler/sinc_resampler.h" ]
|
||||
deps = [
|
||||
"../rtc_base:gtest_prod",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
"../rtc_base/memory:aligned_malloc",
|
||||
"../rtc_base/system:arch",
|
||||
"../system_wrappers",
|
||||
@ -228,7 +228,6 @@ rtc_library("fir_filter_factory") {
|
||||
deps = [
|
||||
":fir_filter",
|
||||
"../rtc_base:checks",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
"../rtc_base/system:arch",
|
||||
"../system_wrappers",
|
||||
]
|
||||
@ -257,7 +256,6 @@ if (current_cpu == "x86" || current_cpu == "x64") {
|
||||
":fir_filter",
|
||||
":sinc_resampler",
|
||||
"../rtc_base:checks",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
"../rtc_base/memory:aligned_malloc",
|
||||
]
|
||||
}
|
||||
@ -282,7 +280,6 @@ if (current_cpu == "x86" || current_cpu == "x64") {
|
||||
":fir_filter",
|
||||
":sinc_resampler",
|
||||
"../rtc_base:checks",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
"../rtc_base/memory:aligned_malloc",
|
||||
]
|
||||
}
|
||||
@ -307,7 +304,6 @@ if (rtc_build_with_neon) {
|
||||
":fir_filter",
|
||||
":sinc_resampler",
|
||||
"../rtc_base:checks",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
"../rtc_base/memory:aligned_malloc",
|
||||
]
|
||||
}
|
||||
@ -329,13 +325,12 @@ if (rtc_build_with_neon) {
|
||||
deps = [
|
||||
":common_audio_c",
|
||||
"../rtc_base:checks",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
"../rtc_base/system:arch",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (rtc_include_tests) {
|
||||
if (rtc_include_tests && !build_with_chromium) {
|
||||
rtc_test("common_audio_unittests") {
|
||||
visibility += webrtc_default_visibility
|
||||
testonly = true
|
||||
@ -378,8 +373,10 @@ if (rtc_include_tests) {
|
||||
":fir_filter_factory",
|
||||
":sinc_resampler",
|
||||
"../rtc_base:checks",
|
||||
"../rtc_base:rtc_base_approved",
|
||||
"../rtc_base:macromagic",
|
||||
"../rtc_base:rtc_base_tests_utils",
|
||||
"../rtc_base:stringutils",
|
||||
"../rtc_base:timeutils",
|
||||
"../rtc_base/system:arch",
|
||||
"../system_wrappers",
|
||||
"../test:fileutils",
|
||||
|
@ -15,12 +15,10 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Format conversion (remixing and resampling) for audio. Only simple remixing
|
||||
// conversions are supported: downmix to mono (i.e. |dst_channels| == 1) or
|
||||
// conversions are supported: downmix to mono (i.e. `dst_channels` == 1) or
|
||||
// upmix from mono (i.e. |src_channels == 1|).
|
||||
//
|
||||
// The source and destination chunks have the same duration in time; specifying
|
||||
@ -35,8 +33,11 @@ class AudioConverter {
|
||||
size_t dst_frames);
|
||||
virtual ~AudioConverter() {}
|
||||
|
||||
// Convert |src|, containing |src_size| samples, to |dst|, having a sample
|
||||
// capacity of |dst_capacity|. Both point to a series of buffers containing
|
||||
AudioConverter(const AudioConverter&) = delete;
|
||||
AudioConverter& operator=(const AudioConverter&) = delete;
|
||||
|
||||
// Convert `src`, containing `src_size` samples, to `dst`, having a sample
|
||||
// capacity of `dst_capacity`. Both point to a series of buffers containing
|
||||
// the samples for each channel. The sizes must correspond to the format
|
||||
// passed to Create().
|
||||
virtual void Convert(const float* const* src,
|
||||
@ -64,8 +65,6 @@ class AudioConverter {
|
||||
const size_t src_frames_;
|
||||
const size_t dst_channels_;
|
||||
const size_t dst_frames_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(AudioConverter);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -29,15 +29,15 @@ namespace webrtc {
|
||||
//
|
||||
// The buffer structure is showed below for a 2 channel and 2 bands case:
|
||||
//
|
||||
// |data_|:
|
||||
// `data_`:
|
||||
// { [ --- b1ch1 --- ] [ --- b2ch1 --- ] [ --- b1ch2 --- ] [ --- b2ch2 --- ] }
|
||||
//
|
||||
// The pointer arrays for the same example are as follows:
|
||||
//
|
||||
// |channels_|:
|
||||
// `channels_`:
|
||||
// { [ b1ch1* ] [ b1ch2* ] [ b2ch1* ] [ b2ch2* ] }
|
||||
//
|
||||
// |bands_|:
|
||||
// `bands_`:
|
||||
// { [ b1ch1* ] [ b2ch1* ] [ b1ch2* ] [ b2ch2* ] }
|
||||
template <typename T>
|
||||
class ChannelBuffer {
|
||||
@ -81,15 +81,15 @@ class ChannelBuffer {
|
||||
// If band is explicitly specificed, the channels for a specific band are
|
||||
// returned and the usage becomes: channels(band)[channel][sample].
|
||||
// Where:
|
||||
// 0 <= band < |num_bands_|
|
||||
// 0 <= channel < |num_allocated_channels_|
|
||||
// 0 <= sample < |num_frames_per_band_|
|
||||
// 0 <= band < `num_bands_`
|
||||
// 0 <= channel < `num_allocated_channels_`
|
||||
// 0 <= sample < `num_frames_per_band_`
|
||||
|
||||
// If band is not explicitly specified, the full-band channels (or lower band
|
||||
// channels) are returned and the usage becomes: channels()[channel][sample].
|
||||
// Where:
|
||||
// 0 <= channel < |num_allocated_channels_|
|
||||
// 0 <= sample < |num_frames_|
|
||||
// 0 <= channel < `num_allocated_channels_`
|
||||
// 0 <= sample < `num_frames_`
|
||||
const T* const* channels(size_t band = 0) const {
|
||||
RTC_DCHECK_LT(band, num_bands_);
|
||||
return &channels_[band * num_allocated_channels_];
|
||||
@ -109,9 +109,9 @@ class ChannelBuffer {
|
||||
// Usage:
|
||||
// bands(channel)[band][sample].
|
||||
// Where:
|
||||
// 0 <= channel < |num_channels_|
|
||||
// 0 <= band < |num_bands_|
|
||||
// 0 <= sample < |num_frames_per_band_|
|
||||
// 0 <= channel < `num_channels_`
|
||||
// 0 <= band < `num_bands_`
|
||||
// 0 <= sample < `num_frames_per_band_`
|
||||
const T* const* bands(size_t channel) const {
|
||||
RTC_DCHECK_LT(channel, num_channels_);
|
||||
RTC_DCHECK_GE(channel, 0);
|
||||
@ -129,8 +129,8 @@ class ChannelBuffer {
|
||||
return bands_view_[channel];
|
||||
}
|
||||
|
||||
// Sets the |slice| pointers to the |start_frame| position for each channel.
|
||||
// Returns |slice| for convenience.
|
||||
// Sets the `slice` pointers to the `start_frame` position for each channel.
|
||||
// Returns `slice` for convenience.
|
||||
const T* const* Slice(T** slice, size_t start_frame) const {
|
||||
RTC_DCHECK_LT(start_frame, num_frames_);
|
||||
for (size_t i = 0; i < num_channels_; ++i)
|
||||
|
@ -20,8 +20,8 @@ class FIRFilter {
|
||||
public:
|
||||
virtual ~FIRFilter() {}
|
||||
|
||||
// Filters the |in| data supplied.
|
||||
// |out| must be previously allocated and it must be at least of |length|.
|
||||
// Filters the `in` data supplied.
|
||||
// `out` must be previously allocated and it must be at least of `length`.
|
||||
virtual void Filter(const float* in, size_t length, float* out) = 0;
|
||||
};
|
||||
|
||||
|
@ -52,7 +52,7 @@ void FIRFilterAVX2::Filter(const float* in, size_t length, float* out) {
|
||||
|
||||
memcpy(&state_[state_length_], in, length * sizeof(*in));
|
||||
|
||||
// Convolves the input signal |in| with the filter kernel |coefficients_|
|
||||
// Convolves the input signal `in` with the filter kernel `coefficients_`
|
||||
// taking into account the previous state.
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
float* in_ptr = &state_[i];
|
||||
|
@ -34,7 +34,7 @@ FIRFilterC::FIRFilterC(const float* coefficients, size_t coefficients_length)
|
||||
void FIRFilterC::Filter(const float* in, size_t length, float* out) {
|
||||
RTC_DCHECK_GT(length, 0);
|
||||
|
||||
// Convolves the input signal |in| with the filter kernel |coefficients_|
|
||||
// Convolves the input signal `in` with the filter kernel `coefficients_`
|
||||
// taking into account the previous state.
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
out[i] = 0.f;
|
||||
|
@ -28,7 +28,7 @@ FIRFilter* CreateFirFilter(const float* coefficients,
|
||||
size_t coefficients_length,
|
||||
size_t max_input_length) {
|
||||
if (!coefficients || coefficients_length <= 0 || max_input_length <= 0) {
|
||||
RTC_NOTREACHED();
|
||||
RTC_DCHECK_NOTREACHED();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ class FIRFilter;
|
||||
// Creates a filter with the given coefficients. All initial state values will
|
||||
// be zeros.
|
||||
// The length of the chunks fed to the filter should never be greater than
|
||||
// |max_input_length|. This is needed because, when vectorizing it is
|
||||
// `max_input_length`. This is needed because, when vectorizing it is
|
||||
// necessary to concatenate the input after the state, and resizing this array
|
||||
// dynamically is expensive.
|
||||
FIRFilter* CreateFirFilter(const float* coefficients,
|
||||
|
@ -48,7 +48,7 @@ void FIRFilterNEON::Filter(const float* in, size_t length, float* out) {
|
||||
|
||||
memcpy(&state_[state_length_], in, length * sizeof(*in));
|
||||
|
||||
// Convolves the input signal |in| with the filter kernel |coefficients_|
|
||||
// Convolves the input signal `in` with the filter kernel `coefficients_`
|
||||
// taking into account the previous state.
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
float* in_ptr = &state_[i];
|
||||
|
@ -49,7 +49,7 @@ void FIRFilterSSE2::Filter(const float* in, size_t length, float* out) {
|
||||
|
||||
memcpy(&state_[state_length_], in, length * sizeof(*in));
|
||||
|
||||
// Convolves the input signal |in| with the filter kernel |coefficients_|
|
||||
// Convolves the input signal `in` with the filter kernel `coefficients_`
|
||||
// taking into account the previous state.
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
float* in_ptr = &state_[i];
|
||||
|
@ -91,9 +91,9 @@ inline float FloatS16ToDbfs(float v) {
|
||||
return 20.0f * std::log10(v) + kMinDbfs;
|
||||
}
|
||||
|
||||
// Copy audio from |src| channels to |dest| channels unless |src| and |dest|
|
||||
// point to the same address. |src| and |dest| must have the same number of
|
||||
// channels, and there must be sufficient space allocated in |dest|.
|
||||
// Copy audio from `src` channels to `dest` channels unless `src` and `dest`
|
||||
// point to the same address. `src` and `dest` must have the same number of
|
||||
// channels, and there must be sufficient space allocated in `dest`.
|
||||
template <typename T>
|
||||
void CopyAudioIfNeeded(const T* const* src,
|
||||
int num_frames,
|
||||
@ -106,9 +106,9 @@ void CopyAudioIfNeeded(const T* const* src,
|
||||
}
|
||||
}
|
||||
|
||||
// Deinterleave audio from |interleaved| to the channel buffers pointed to
|
||||
// by |deinterleaved|. There must be sufficient space allocated in the
|
||||
// |deinterleaved| buffers (|num_channel| buffers with |samples_per_channel|
|
||||
// Deinterleave audio from `interleaved` to the channel buffers pointed to
|
||||
// by `deinterleaved`. There must be sufficient space allocated in the
|
||||
// `deinterleaved` buffers (`num_channel` buffers with `samples_per_channel`
|
||||
// per buffer).
|
||||
template <typename T>
|
||||
void Deinterleave(const T* interleaved,
|
||||
@ -125,9 +125,9 @@ void Deinterleave(const T* interleaved,
|
||||
}
|
||||
}
|
||||
|
||||
// Interleave audio from the channel buffers pointed to by |deinterleaved| to
|
||||
// |interleaved|. There must be sufficient space allocated in |interleaved|
|
||||
// (|samples_per_channel| * |num_channels|).
|
||||
// Interleave audio from the channel buffers pointed to by `deinterleaved` to
|
||||
// `interleaved`. There must be sufficient space allocated in `interleaved`
|
||||
// (`samples_per_channel` * `num_channels`).
|
||||
template <typename T>
|
||||
void Interleave(const T* const* deinterleaved,
|
||||
size_t samples_per_channel,
|
||||
@ -143,9 +143,9 @@ void Interleave(const T* const* deinterleaved,
|
||||
}
|
||||
}
|
||||
|
||||
// Copies audio from a single channel buffer pointed to by |mono| to each
|
||||
// channel of |interleaved|. There must be sufficient space allocated in
|
||||
// |interleaved| (|samples_per_channel| * |num_channels|).
|
||||
// Copies audio from a single channel buffer pointed to by `mono` to each
|
||||
// channel of `interleaved`. There must be sufficient space allocated in
|
||||
// `interleaved` (`samples_per_channel` * `num_channels`).
|
||||
template <typename T>
|
||||
void UpmixMonoToInterleaved(const T* mono,
|
||||
int num_frames,
|
||||
|
@ -50,7 +50,7 @@ class RealFourier {
|
||||
// output (i.e. |2^order / 2 + 1|).
|
||||
static size_t ComplexLength(int order);
|
||||
|
||||
// Buffer allocation helpers. The buffers are large enough to hold |count|
|
||||
// Buffer allocation helpers. The buffers are large enough to hold `count`
|
||||
// floats/complexes and suitably aligned for use by the implementation.
|
||||
// The returned scopers are set up with proper deleters; the caller owns
|
||||
// the allocated memory.
|
||||
|
@ -20,42 +20,6 @@
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
// These checks were factored out into a non-templatized function
|
||||
// due to problems with clang on Windows in debug builds.
|
||||
// For some reason having the DCHECKs inline in the template code
|
||||
// caused the compiler to generate code that threw off the linker.
|
||||
// TODO(tommi): Re-enable when we've figured out what the problem is.
|
||||
// http://crbug.com/615050
|
||||
void CheckValidInitParams(int src_sample_rate_hz,
|
||||
int dst_sample_rate_hz,
|
||||
size_t num_channels) {
|
||||
// The below checks are temporarily disabled on WEBRTC_WIN due to problems
|
||||
// with clang debug builds.
|
||||
#if !defined(WEBRTC_WIN) && defined(__clang__)
|
||||
RTC_DCHECK_GT(src_sample_rate_hz, 0);
|
||||
RTC_DCHECK_GT(dst_sample_rate_hz, 0);
|
||||
RTC_DCHECK_GT(num_channels, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CheckExpectedBufferSizes(size_t src_length,
|
||||
size_t dst_capacity,
|
||||
size_t num_channels,
|
||||
int src_sample_rate,
|
||||
int dst_sample_rate) {
|
||||
// The below checks are temporarily disabled on WEBRTC_WIN due to problems
|
||||
// with clang debug builds.
|
||||
// TODO(tommi): Re-enable when we've figured out what the problem is.
|
||||
// http://crbug.com/615050
|
||||
#if !defined(WEBRTC_WIN) && defined(__clang__)
|
||||
const size_t src_size_10ms = src_sample_rate * num_channels / 100;
|
||||
const size_t dst_size_10ms = dst_sample_rate * num_channels / 100;
|
||||
RTC_DCHECK_EQ(src_length, src_size_10ms);
|
||||
RTC_DCHECK_GE(dst_capacity, dst_size_10ms);
|
||||
#endif
|
||||
}
|
||||
} // namespace
|
||||
|
||||
template <typename T>
|
||||
PushResampler<T>::PushResampler()
|
||||
@ -68,7 +32,11 @@ template <typename T>
|
||||
int PushResampler<T>::InitializeIfNeeded(int src_sample_rate_hz,
|
||||
int dst_sample_rate_hz,
|
||||
size_t num_channels) {
|
||||
CheckValidInitParams(src_sample_rate_hz, dst_sample_rate_hz, num_channels);
|
||||
// These checks used to be factored out of this template function due to
|
||||
// Windows debug build issues with clang. http://crbug.com/615050
|
||||
RTC_DCHECK_GT(src_sample_rate_hz, 0);
|
||||
RTC_DCHECK_GT(dst_sample_rate_hz, 0);
|
||||
RTC_DCHECK_GT(num_channels, 0);
|
||||
|
||||
if (src_sample_rate_hz == src_sample_rate_hz_ &&
|
||||
dst_sample_rate_hz == dst_sample_rate_hz_ &&
|
||||
@ -109,8 +77,12 @@ int PushResampler<T>::Resample(const T* src,
|
||||
size_t src_length,
|
||||
T* dst,
|
||||
size_t dst_capacity) {
|
||||
CheckExpectedBufferSizes(src_length, dst_capacity, num_channels_,
|
||||
src_sample_rate_hz_, dst_sample_rate_hz_);
|
||||
// These checks used to be factored out of this template function due to
|
||||
// Windows debug build issues with clang. http://crbug.com/615050
|
||||
const size_t src_size_10ms = (src_sample_rate_hz_ / 100) * num_channels_;
|
||||
const size_t dst_size_10ms = (dst_sample_rate_hz_ / 100) * num_channels_;
|
||||
RTC_DCHECK_EQ(src_length, src_size_10ms);
|
||||
RTC_DCHECK_GE(dst_capacity, dst_size_10ms);
|
||||
|
||||
if (src_sample_rate_hz_ == dst_sample_rate_hz_) {
|
||||
// The old resampler provides this memcpy facility in the case of matching
|
||||
|
@ -63,12 +63,12 @@ size_t PushSincResampler::Resample(const float* source,
|
||||
// request through Run().
|
||||
//
|
||||
// If this wasn't done, SincResampler would call Run() twice on the first
|
||||
// pass, and we'd have to introduce an entire |source_frames| of delay, rather
|
||||
// pass, and we'd have to introduce an entire `source_frames` of delay, rather
|
||||
// than the minimum half kernel.
|
||||
//
|
||||
// It works out that ChunkSize() is exactly the amount of output we need to
|
||||
// request in order to prime the buffer with a single Run() request for
|
||||
// |source_frames|.
|
||||
// `source_frames`.
|
||||
if (first_pass_)
|
||||
resampler_->Resample(resampler_->ChunkSize(), destination);
|
||||
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include <memory>
|
||||
|
||||
#include "common_audio/resampler/sinc_resampler.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -33,11 +32,14 @@ class PushSincResampler : public SincResamplerCallback {
|
||||
PushSincResampler(size_t source_frames, size_t destination_frames);
|
||||
~PushSincResampler() override;
|
||||
|
||||
// Perform the resampling. |source_frames| must always equal the
|
||||
// |source_frames| provided at construction. |destination_capacity| must be
|
||||
// at least as large as |destination_frames|. Returns the number of samples
|
||||
PushSincResampler(const PushSincResampler&) = delete;
|
||||
PushSincResampler& operator=(const PushSincResampler&) = delete;
|
||||
|
||||
// Perform the resampling. `source_frames` must always equal the
|
||||
// `source_frames` provided at construction. `destination_capacity` must be
|
||||
// at least as large as `destination_frames`. Returns the number of samples
|
||||
// provided in destination (for convenience, since this will always be equal
|
||||
// to |destination_frames|).
|
||||
// to `destination_frames`).
|
||||
size_t Resample(const int16_t* source,
|
||||
size_t source_frames,
|
||||
int16_t* destination,
|
||||
@ -72,8 +74,6 @@ class PushSincResampler : public SincResamplerCallback {
|
||||
|
||||
// Used to assert we are only requested for as much data as is available.
|
||||
size_t source_available_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(PushSincResampler);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -916,7 +916,6 @@ int Resampler::Push(const int16_t* samplesIn,
|
||||
outLen = (lengthIn * 8) / 11;
|
||||
free(tmp_mem);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -80,7 +80,7 @@
|
||||
// 8) Else, if we're not on the second load, goto (4).
|
||||
//
|
||||
// Note: we're glossing over how the sub-sample handling works with
|
||||
// |virtual_source_idx_|, etc.
|
||||
// `virtual_source_idx_`, etc.
|
||||
|
||||
// MSVC++ requires this to be set before any other includes to get M_PI.
|
||||
#define _USE_MATH_DEFINES
|
||||
@ -102,7 +102,7 @@ namespace webrtc {
|
||||
namespace {
|
||||
|
||||
double SincScaleFactor(double io_ratio) {
|
||||
// |sinc_scale_factor| is basically the normalized cutoff frequency of the
|
||||
// `sinc_scale_factor` is basically the normalized cutoff frequency of the
|
||||
// low-pass filter.
|
||||
double sinc_scale_factor = io_ratio > 1.0 ? 1.0 / io_ratio : 1.0;
|
||||
|
||||
@ -126,8 +126,8 @@ void SincResampler::InitializeCPUSpecificFeatures() {
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
convolve_proc_ = Convolve_NEON;
|
||||
#elif defined(WEBRTC_ARCH_X86_FAMILY)
|
||||
// Using AVX2 instead of SSE2 when AVX2 supported.
|
||||
if (GetCPUInfo(kAVX2))
|
||||
// Using AVX2 instead of SSE2 when AVX2/FMA3 supported.
|
||||
if (GetCPUInfo(kAVX2) && GetCPUInfo(kFMA3))
|
||||
convolve_proc_ = Convolve_AVX2;
|
||||
else if (GetCPUInfo(kSSE2))
|
||||
convolve_proc_ = Convolve_SSE;
|
||||
@ -238,7 +238,7 @@ void SincResampler::SetRatio(double io_sample_rate_ratio) {
|
||||
io_sample_rate_ratio_ = io_sample_rate_ratio;
|
||||
|
||||
// Optimize reinitialization by reusing values which are independent of
|
||||
// |sinc_scale_factor|. Provides a 3x speedup.
|
||||
// `sinc_scale_factor`. Provides a 3x speedup.
|
||||
const double sinc_scale_factor = SincScaleFactor(io_sample_rate_ratio_);
|
||||
for (size_t offset_idx = 0; offset_idx <= kKernelOffsetCount; ++offset_idx) {
|
||||
for (size_t i = 0; i < kKernelSize; ++i) {
|
||||
@ -268,8 +268,8 @@ void SincResampler::Resample(size_t frames, float* destination) {
|
||||
const double current_io_ratio = io_sample_rate_ratio_;
|
||||
const float* const kernel_ptr = kernel_storage_.get();
|
||||
while (remaining_frames) {
|
||||
// |i| may be negative if the last Resample() call ended on an iteration
|
||||
// that put |virtual_source_idx_| over the limit.
|
||||
// `i` may be negative if the last Resample() call ended on an iteration
|
||||
// that put `virtual_source_idx_` over the limit.
|
||||
//
|
||||
// Note: The loop construct here can severely impact performance on ARM
|
||||
// or when built with clang. See https://codereview.chromium.org/18566009/
|
||||
@ -278,7 +278,7 @@ void SincResampler::Resample(size_t frames, float* destination) {
|
||||
i > 0; --i) {
|
||||
RTC_DCHECK_LT(virtual_source_idx_, block_size_);
|
||||
|
||||
// |virtual_source_idx_| lies in between two kernel offsets so figure out
|
||||
// `virtual_source_idx_` lies in between two kernel offsets so figure out
|
||||
// what they are.
|
||||
const int source_idx = static_cast<int>(virtual_source_idx_);
|
||||
const double subsample_remainder = virtual_source_idx_ - source_idx;
|
||||
@ -288,16 +288,16 @@ void SincResampler::Resample(size_t frames, float* destination) {
|
||||
const int offset_idx = static_cast<int>(virtual_offset_idx);
|
||||
|
||||
// We'll compute "convolutions" for the two kernels which straddle
|
||||
// |virtual_source_idx_|.
|
||||
// `virtual_source_idx_`.
|
||||
const float* const k1 = kernel_ptr + offset_idx * kKernelSize;
|
||||
const float* const k2 = k1 + kKernelSize;
|
||||
|
||||
// Ensure |k1|, |k2| are 32-byte aligned for SIMD usage. Should always be
|
||||
// Ensure `k1`, `k2` are 32-byte aligned for SIMD usage. Should always be
|
||||
// true so long as kKernelSize is a multiple of 32.
|
||||
RTC_DCHECK_EQ(0, reinterpret_cast<uintptr_t>(k1) % 32);
|
||||
RTC_DCHECK_EQ(0, reinterpret_cast<uintptr_t>(k2) % 32);
|
||||
|
||||
// Initialize input pointer based on quantized |virtual_source_idx_|.
|
||||
// Initialize input pointer based on quantized `virtual_source_idx_`.
|
||||
const float* const input_ptr = r1_ + source_idx;
|
||||
|
||||
// Figure out how much to weight each kernel's "convolution".
|
||||
|
@ -18,15 +18,14 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
#include "rtc_base/gtest_prod_util.h"
|
||||
#include "rtc_base/memory/aligned_malloc.h"
|
||||
#include "rtc_base/system/arch.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Callback class for providing more data into the resampler. Expects |frames|
|
||||
// of data to be rendered into |destination|; zero padded if not enough frames
|
||||
// Callback class for providing more data into the resampler. Expects `frames`
|
||||
// of data to be rendered into `destination`; zero padded if not enough frames
|
||||
// are available to satisfy the request.
|
||||
class SincResamplerCallback {
|
||||
public:
|
||||
@ -53,10 +52,10 @@ class SincResampler {
|
||||
static const size_t kKernelStorageSize =
|
||||
kKernelSize * (kKernelOffsetCount + 1);
|
||||
|
||||
// Constructs a SincResampler with the specified |read_cb|, which is used to
|
||||
// acquire audio data for resampling. |io_sample_rate_ratio| is the ratio
|
||||
// of input / output sample rates. |request_frames| controls the size in
|
||||
// frames of the buffer requested by each |read_cb| call. The value must be
|
||||
// Constructs a SincResampler with the specified `read_cb`, which is used to
|
||||
// acquire audio data for resampling. `io_sample_rate_ratio` is the ratio
|
||||
// of input / output sample rates. `request_frames` controls the size in
|
||||
// frames of the buffer requested by each `read_cb` call. The value must be
|
||||
// greater than kKernelSize. Specify kDefaultRequestSize if there are no
|
||||
// request size constraints.
|
||||
SincResampler(double io_sample_rate_ratio,
|
||||
@ -64,11 +63,14 @@ class SincResampler {
|
||||
SincResamplerCallback* read_cb);
|
||||
virtual ~SincResampler();
|
||||
|
||||
// Resample |frames| of data from |read_cb_| into |destination|.
|
||||
SincResampler(const SincResampler&) = delete;
|
||||
SincResampler& operator=(const SincResampler&) = delete;
|
||||
|
||||
// Resample `frames` of data from `read_cb_` into `destination`.
|
||||
void Resample(size_t frames, float* destination);
|
||||
|
||||
// The maximum size in frames that guarantees Resample() will only make a
|
||||
// single call to |read_cb_| for more data.
|
||||
// single call to `read_cb_` for more data.
|
||||
size_t ChunkSize() const;
|
||||
|
||||
size_t request_frames() const { return request_frames_; }
|
||||
@ -77,12 +79,12 @@ class SincResampler {
|
||||
// not call while Resample() is in progress.
|
||||
void Flush();
|
||||
|
||||
// Update |io_sample_rate_ratio_|. SetRatio() will cause a reconstruction of
|
||||
// Update `io_sample_rate_ratio_`. SetRatio() will cause a reconstruction of
|
||||
// the kernels used for resampling. Not thread safe, do not call while
|
||||
// Resample() is in progress.
|
||||
//
|
||||
// TODO(ajm): Use this in PushSincResampler rather than reconstructing
|
||||
// SincResampler. We would also need a way to update |request_frames_|.
|
||||
// SincResampler. We would also need a way to update `request_frames_`.
|
||||
void SetRatio(double io_sample_rate_ratio);
|
||||
|
||||
float* get_kernel_for_testing() { return kernel_storage_.get(); }
|
||||
@ -97,11 +99,11 @@ class SincResampler {
|
||||
// Selects runtime specific CPU features like SSE. Must be called before
|
||||
// using SincResampler.
|
||||
// TODO(ajm): Currently managed by the class internally. See the note with
|
||||
// |convolve_proc_| below.
|
||||
// `convolve_proc_` below.
|
||||
void InitializeCPUSpecificFeatures();
|
||||
|
||||
// Compute convolution of |k1| and |k2| over |input_ptr|, resultant sums are
|
||||
// linearly interpolated using |kernel_interpolation_factor|. On x86 and ARM
|
||||
// Compute convolution of `k1` and `k2` over `input_ptr`, resultant sums are
|
||||
// linearly interpolated using `kernel_interpolation_factor`. On x86 and ARM
|
||||
// the underlying implementation is chosen at run time.
|
||||
static float Convolve_C(const float* input_ptr,
|
||||
const float* k1,
|
||||
@ -136,7 +138,7 @@ class SincResampler {
|
||||
// Source of data for resampling.
|
||||
SincResamplerCallback* read_cb_;
|
||||
|
||||
// The size (in samples) to request from each |read_cb_| execution.
|
||||
// The size (in samples) to request from each `read_cb_` execution.
|
||||
const size_t request_frames_;
|
||||
|
||||
// The number of source frames processed per pass.
|
||||
@ -155,25 +157,23 @@ class SincResampler {
|
||||
// Data from the source is copied into this buffer for each processing pass.
|
||||
std::unique_ptr<float[], AlignedFreeDeleter> input_buffer_;
|
||||
|
||||
// Stores the runtime selection of which Convolve function to use.
|
||||
// TODO(ajm): Move to using a global static which must only be initialized
|
||||
// once by the user. We're not doing this initially, because we don't have
|
||||
// e.g. a LazyInstance helper in webrtc.
|
||||
// Stores the runtime selection of which Convolve function to use.
|
||||
// TODO(ajm): Move to using a global static which must only be initialized
|
||||
// once by the user. We're not doing this initially, because we don't have
|
||||
// e.g. a LazyInstance helper in webrtc.
|
||||
typedef float (*ConvolveProc)(const float*,
|
||||
const float*,
|
||||
const float*,
|
||||
double);
|
||||
ConvolveProc convolve_proc_;
|
||||
|
||||
// Pointers to the various regions inside |input_buffer_|. See the diagram at
|
||||
// Pointers to the various regions inside `input_buffer_`. See the diagram at
|
||||
// the top of the .cc file for more information.
|
||||
float* r0_;
|
||||
float* const r1_;
|
||||
float* const r2_;
|
||||
float* r3_;
|
||||
float* r4_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(SincResampler);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -25,7 +25,7 @@ float SincResampler::Convolve_AVX2(const float* input_ptr,
|
||||
__m256 m_sums1 = _mm256_setzero_ps();
|
||||
__m256 m_sums2 = _mm256_setzero_ps();
|
||||
|
||||
// Based on |input_ptr| alignment, we need to use loadu or load. Unrolling
|
||||
// Based on `input_ptr` alignment, we need to use loadu or load. Unrolling
|
||||
// these loops has not been tested or benchmarked.
|
||||
bool aligned_input = (reinterpret_cast<uintptr_t>(input_ptr) & 0x1F) == 0;
|
||||
if (!aligned_input) {
|
||||
|
@ -27,7 +27,7 @@ float SincResampler::Convolve_SSE(const float* input_ptr,
|
||||
__m128 m_sums1 = _mm_setzero_ps();
|
||||
__m128 m_sums2 = _mm_setzero_ps();
|
||||
|
||||
// Based on |input_ptr| alignment, we need to use loadu or load. Unrolling
|
||||
// Based on `input_ptr` alignment, we need to use loadu or load. Unrolling
|
||||
// these loops hurt performance in local testing.
|
||||
if (reinterpret_cast<uintptr_t>(input_ptr) & 0x0F) {
|
||||
for (size_t i = 0; i < kKernelSize; i += 4) {
|
||||
|
@ -15,7 +15,6 @@
|
||||
#define COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_
|
||||
|
||||
#include "common_audio/resampler/sinc_resampler.h"
|
||||
#include "rtc_base/constructor_magic.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -24,7 +23,7 @@ namespace webrtc {
|
||||
// resampler for the specific sample rate conversion being used.
|
||||
class SinusoidalLinearChirpSource : public SincResamplerCallback {
|
||||
public:
|
||||
// |delay_samples| can be used to insert a fractional sample delay into the
|
||||
// `delay_samples` can be used to insert a fractional sample delay into the
|
||||
// source. It will produce zeros until non-negative time is reached.
|
||||
SinusoidalLinearChirpSource(int sample_rate,
|
||||
size_t samples,
|
||||
@ -33,12 +32,16 @@ class SinusoidalLinearChirpSource : public SincResamplerCallback {
|
||||
|
||||
~SinusoidalLinearChirpSource() override {}
|
||||
|
||||
SinusoidalLinearChirpSource(const SinusoidalLinearChirpSource&) = delete;
|
||||
SinusoidalLinearChirpSource& operator=(const SinusoidalLinearChirpSource&) =
|
||||
delete;
|
||||
|
||||
void Run(size_t frames, float* destination) override;
|
||||
|
||||
double Frequency(size_t position);
|
||||
|
||||
private:
|
||||
enum { kMinFrequency = 5 };
|
||||
static constexpr int kMinFrequency = 5;
|
||||
|
||||
int sample_rate_;
|
||||
size_t total_samples_;
|
||||
@ -46,8 +49,6 @@ class SinusoidalLinearChirpSource : public SincResamplerCallback {
|
||||
double k_;
|
||||
size_t current_index_;
|
||||
double delay_samples_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(SinusoidalLinearChirpSource);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
@ -18,9 +18,9 @@
|
||||
#include <string.h>
|
||||
|
||||
// Get address of region(s) from which we can read data.
|
||||
// If the region is contiguous, |data_ptr_bytes_2| will be zero.
|
||||
// If non-contiguous, |data_ptr_bytes_2| will be the size in bytes of the second
|
||||
// region. Returns room available to be read or |element_count|, whichever is
|
||||
// If the region is contiguous, `data_ptr_bytes_2` will be zero.
|
||||
// If non-contiguous, `data_ptr_bytes_2` will be the size in bytes of the second
|
||||
// region. Returns room available to be read or `element_count`, whichever is
|
||||
// smaller.
|
||||
static size_t GetBufferReadRegions(RingBuffer* buf,
|
||||
size_t element_count,
|
||||
@ -120,7 +120,7 @@ size_t WebRtc_ReadBuffer(RingBuffer* self,
|
||||
&buf_ptr_bytes_2);
|
||||
if (buf_ptr_bytes_2 > 0) {
|
||||
// We have a wrap around when reading the buffer. Copy the buffer data to
|
||||
// |data| and point to it.
|
||||
// `data` and point to it.
|
||||
memcpy(data, buf_ptr_1, buf_ptr_bytes_1);
|
||||
memcpy(((char*) data) + buf_ptr_bytes_1, buf_ptr_2, buf_ptr_bytes_2);
|
||||
buf_ptr_1 = data;
|
||||
@ -129,7 +129,7 @@ size_t WebRtc_ReadBuffer(RingBuffer* self,
|
||||
memcpy(data, buf_ptr_1, buf_ptr_bytes_1);
|
||||
}
|
||||
if (data_ptr) {
|
||||
// |buf_ptr_1| == |data| in the case of a wrap.
|
||||
// `buf_ptr_1` == `data` in the case of a wrap.
|
||||
*data_ptr = read_count == 0 ? NULL : buf_ptr_1;
|
||||
}
|
||||
|
||||
|
@ -39,14 +39,14 @@ void WebRtc_InitBuffer(RingBuffer* handle);
|
||||
void WebRtc_FreeBuffer(void* handle);
|
||||
|
||||
// Reads data from the buffer. Returns the number of elements that were read.
|
||||
// The |data_ptr| will point to the address where the read data is located.
|
||||
// If no data can be read, |data_ptr| is set to |NULL|. If all data can be read
|
||||
// without buffer wrap around then |data_ptr| will point to the location in the
|
||||
// buffer. Otherwise, the data will be copied to |data| (memory allocation done
|
||||
// by the user) and |data_ptr| points to the address of |data|. |data_ptr| is
|
||||
// The `data_ptr` will point to the address where the read data is located.
|
||||
// If no data can be read, `data_ptr` is set to `NULL`. If all data can be read
|
||||
// without buffer wrap around then `data_ptr` will point to the location in the
|
||||
// buffer. Otherwise, the data will be copied to `data` (memory allocation done
|
||||
// by the user) and `data_ptr` points to the address of `data`. `data_ptr` is
|
||||
// only guaranteed to be valid until the next call to WebRtc_WriteBuffer().
|
||||
//
|
||||
// To force a copying to |data|, pass a null |data_ptr|.
|
||||
// To force a copying to `data`, pass a null `data_ptr`.
|
||||
//
|
||||
// Returns number of elements read.
|
||||
size_t WebRtc_ReadBuffer(RingBuffer* handle,
|
||||
@ -54,14 +54,14 @@ size_t WebRtc_ReadBuffer(RingBuffer* handle,
|
||||
void* data,
|
||||
size_t element_count);
|
||||
|
||||
// Writes |data| to buffer and returns the number of elements written.
|
||||
// Writes `data` to buffer and returns the number of elements written.
|
||||
size_t WebRtc_WriteBuffer(RingBuffer* handle,
|
||||
const void* data,
|
||||
size_t element_count);
|
||||
|
||||
// Moves the buffer read position and returns the number of elements moved.
|
||||
// Positive |element_count| moves the read position towards the write position,
|
||||
// that is, flushing the buffer. Negative |element_count| moves the read
|
||||
// Positive `element_count` moves the read position towards the write position,
|
||||
// that is, flushing the buffer. Negative `element_count` moves the read
|
||||
// position away from the the write position, that is, stuffing the buffer.
|
||||
// Returns number of elements moved.
|
||||
int WebRtc_MoveReadPtr(RingBuffer* handle, int element_count);
|
||||
|
@ -72,9 +72,9 @@ void WebRtcSpl_CrossCorrelationNeon(int32_t* cross_correlation,
|
||||
size_t dim_cross_correlation,
|
||||
int right_shifts,
|
||||
int step_seq2) {
|
||||
size_t i = 0;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < dim_cross_correlation; i++) {
|
||||
for (i = 0; i < (int)dim_cross_correlation; i++) {
|
||||
const int16_t* seq1_ptr = seq1;
|
||||
const int16_t* seq2_ptr = seq2 + (step_seq2 * i);
|
||||
|
||||
|
@ -98,8 +98,7 @@ int32_t WebRtcSpl_DivResultInQ31(int32_t num, int32_t den)
|
||||
return div;
|
||||
}
|
||||
|
||||
int32_t RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/5486
|
||||
WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low)
|
||||
int32_t WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low)
|
||||
{
|
||||
int16_t approx, tmp_hi, tmp_low, num_hi, num_low;
|
||||
int32_t tmpW32;
|
||||
@ -111,8 +110,8 @@ WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low)
|
||||
tmpW32 = (den_hi * approx << 1) + ((den_low * approx >> 15) << 1);
|
||||
// tmpW32 = den * approx
|
||||
|
||||
tmpW32 = (int32_t)0x7fffffffL - tmpW32; // result in Q30 (tmpW32 = 2.0-(den*approx))
|
||||
// UBSan: 2147483647 - -2 cannot be represented in type 'int'
|
||||
// result in Q30 (tmpW32 = 2.0-(den*approx))
|
||||
tmpW32 = (int32_t)((int64_t)0x7fffffffL - tmpW32);
|
||||
|
||||
// Store tmpW32 in hi and low format
|
||||
tmp_hi = (int16_t)(tmpW32 >> 16);
|
||||
|
@ -26,7 +26,7 @@ extern "C" {
|
||||
// - vector_length : Number of samples used in the dot product
|
||||
// - scaling : The number of right bit shifts to apply on each term
|
||||
// during calculation to avoid overflow, i.e., the
|
||||
// output will be in Q(-|scaling|)
|
||||
// output will be in Q(-`scaling`)
|
||||
//
|
||||
// Return value : The dot product in Q(-scaling)
|
||||
int32_t WebRtcSpl_DotProductWithScale(const int16_t* vector1,
|
||||
|
@ -8,9 +8,11 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <arm_neon.h>
|
||||
|
||||
#include "common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
#include <arm_neon.h>
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
// NEON intrinsics version of WebRtcSpl_DownsampleFast()
|
||||
// for ARM 32-bit/64-bit platforms.
|
||||
@ -22,19 +24,24 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
|
||||
size_t coefficients_length,
|
||||
int factor,
|
||||
size_t delay) {
|
||||
size_t i = 0;
|
||||
size_t j = 0;
|
||||
// Using signed indexes to be able to compute negative i-j that
|
||||
// is used to index data_in.
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int32_t out_s32 = 0;
|
||||
size_t endpos = delay + factor * (data_out_length - 1) + 1;
|
||||
int endpos = delay + factor * (data_out_length - 1) + 1;
|
||||
size_t res = data_out_length & 0x7;
|
||||
size_t endpos1 = endpos - factor * res;
|
||||
int endpos1 = endpos - factor * res;
|
||||
|
||||
// Return error if any of the running conditions doesn't meet.
|
||||
if (data_out_length == 0 || coefficients_length == 0
|
||||
|| data_in_length < endpos) {
|
||||
|| (int)data_in_length < endpos) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
RTC_DCHECK_GE(endpos, 0);
|
||||
RTC_DCHECK_GE(endpos1, 0);
|
||||
|
||||
// First part, unroll the loop 8 times, with 3 subcases
|
||||
// (factor == 2, 4, others).
|
||||
switch (factor) {
|
||||
@ -46,7 +53,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
|
||||
|
||||
#if defined(WEBRTC_ARCH_ARM64)
|
||||
// Unroll the loop 2 times.
|
||||
for (j = 0; j < coefficients_length - 1; j += 2) {
|
||||
for (j = 0; j < (int)coefficients_length - 1; j += 2) {
|
||||
int32x2_t coeff32 = vld1_dup_s32((int32_t*)&coefficients[j]);
|
||||
int16x4_t coeff16x4 = vreinterpret_s16_s32(coeff32);
|
||||
int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j - 1]);
|
||||
@ -68,7 +75,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
|
||||
out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_3, coeff16x4, 0);
|
||||
}
|
||||
|
||||
for (; j < coefficients_length; j++) {
|
||||
for (; j < (int)coefficients_length; j++) {
|
||||
int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]);
|
||||
int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j]);
|
||||
|
||||
@ -87,7 +94,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
|
||||
#else
|
||||
// On ARMv7, the loop unrolling 2 times results in performance
|
||||
// regression.
|
||||
for (j = 0; j < coefficients_length; j++) {
|
||||
for (j = 0; j < (int)coefficients_length; j++) {
|
||||
int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]);
|
||||
int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j]);
|
||||
|
||||
@ -114,7 +121,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
|
||||
int32x4_t out32x4_1 = vdupq_n_s32(2048);
|
||||
|
||||
// Unroll the loop 4 times.
|
||||
for (j = 0; j < coefficients_length - 3; j += 4) {
|
||||
for (j = 0; j < (int)coefficients_length - 3; j += 4) {
|
||||
int16x4_t coeff16x4 = vld1_s16(&coefficients[j]);
|
||||
int16x8x4_t in16x8x4 = vld4q_s16(&data_in[i - j - 3]);
|
||||
|
||||
@ -143,7 +150,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
|
||||
out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_7, coeff16x4, 0);
|
||||
}
|
||||
|
||||
for (; j < coefficients_length; j++) {
|
||||
for (; j < (int)coefficients_length; j++) {
|
||||
int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]);
|
||||
int16x8x4_t in16x8x4 = vld4q_s16(&data_in[i - j]);
|
||||
|
||||
@ -174,7 +181,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
|
||||
int32x4_t out32x4_0 = vdupq_n_s32(2048);
|
||||
int32x4_t out32x4_1 = vdupq_n_s32(2048);
|
||||
|
||||
for (j = 0; j < coefficients_length; j++) {
|
||||
for (j = 0; j < (int)coefficients_length; j++) {
|
||||
int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]);
|
||||
int16x4_t in16x4_0 = vld1_dup_s16(&data_in[i - j]);
|
||||
in16x4_0 = vld1_lane_s16(&data_in[i + factor - j], in16x4_0, 1);
|
||||
@ -204,7 +211,7 @@ int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in,
|
||||
for (; i < endpos; i += factor) {
|
||||
out_s32 = 2048; // Round value, 0.5 in Q12.
|
||||
|
||||
for (j = 0; j < coefficients_length; j++) {
|
||||
for (j = 0; j < (int)coefficients_length; j++) {
|
||||
out_s32 = WebRtc_MulAccumW16(coefficients[j], data_in[i - j], out_s32);
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ int WebRtcSpl_RealForwardFFT(struct RealFFT* self,
|
||||
// boundary.
|
||||
//
|
||||
// Return Value:
|
||||
// 0 or a positive number - a value that the elements in the |real_data_out|
|
||||
// 0 or a positive number - a value that the elements in the `real_data_out`
|
||||
// should be shifted left with in order to get
|
||||
// correct physical values.
|
||||
// -1 - Error with bad arguments (null pointers).
|
||||
|
@ -166,7 +166,7 @@ int32_t WebRtcSpl_MaxAbsValueW32_mips(const int32_t* vector, size_t length);
|
||||
// - vector : 16-bit input vector.
|
||||
// - length : Number of samples in vector.
|
||||
//
|
||||
// Return value : Maximum sample value in |vector|.
|
||||
// Return value : Maximum sample value in `vector`.
|
||||
typedef int16_t (*MaxValueW16)(const int16_t* vector, size_t length);
|
||||
extern const MaxValueW16 WebRtcSpl_MaxValueW16;
|
||||
int16_t WebRtcSpl_MaxValueW16C(const int16_t* vector, size_t length);
|
||||
@ -183,7 +183,7 @@ int16_t WebRtcSpl_MaxValueW16_mips(const int16_t* vector, size_t length);
|
||||
// - vector : 32-bit input vector.
|
||||
// - length : Number of samples in vector.
|
||||
//
|
||||
// Return value : Maximum sample value in |vector|.
|
||||
// Return value : Maximum sample value in `vector`.
|
||||
typedef int32_t (*MaxValueW32)(const int32_t* vector, size_t length);
|
||||
extern const MaxValueW32 WebRtcSpl_MaxValueW32;
|
||||
int32_t WebRtcSpl_MaxValueW32C(const int32_t* vector, size_t length);
|
||||
@ -200,7 +200,7 @@ int32_t WebRtcSpl_MaxValueW32_mips(const int32_t* vector, size_t length);
|
||||
// - vector : 16-bit input vector.
|
||||
// - length : Number of samples in vector.
|
||||
//
|
||||
// Return value : Minimum sample value in |vector|.
|
||||
// Return value : Minimum sample value in `vector`.
|
||||
typedef int16_t (*MinValueW16)(const int16_t* vector, size_t length);
|
||||
extern const MinValueW16 WebRtcSpl_MinValueW16;
|
||||
int16_t WebRtcSpl_MinValueW16C(const int16_t* vector, size_t length);
|
||||
@ -217,7 +217,7 @@ int16_t WebRtcSpl_MinValueW16_mips(const int16_t* vector, size_t length);
|
||||
// - vector : 32-bit input vector.
|
||||
// - length : Number of samples in vector.
|
||||
//
|
||||
// Return value : Minimum sample value in |vector|.
|
||||
// Return value : Minimum sample value in `vector`.
|
||||
typedef int32_t (*MinValueW32)(const int32_t* vector, size_t length);
|
||||
extern const MinValueW32 WebRtcSpl_MinValueW32;
|
||||
int32_t WebRtcSpl_MinValueW32C(const int32_t* vector, size_t length);
|
||||
@ -228,6 +228,25 @@ int32_t WebRtcSpl_MinValueW32Neon(const int32_t* vector, size_t length);
|
||||
int32_t WebRtcSpl_MinValueW32_mips(const int32_t* vector, size_t length);
|
||||
#endif
|
||||
|
||||
// Returns both the minimum and maximum values of a 16-bit vector.
|
||||
//
|
||||
// Input:
|
||||
// - vector : 16-bit input vector.
|
||||
// - length : Number of samples in vector.
|
||||
// Ouput:
|
||||
// - max_val : Maximum sample value in `vector`.
|
||||
// - min_val : Minimum sample value in `vector`.
|
||||
void WebRtcSpl_MinMaxW16(const int16_t* vector,
|
||||
size_t length,
|
||||
int16_t* min_val,
|
||||
int16_t* max_val);
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
void WebRtcSpl_MinMaxW16Neon(const int16_t* vector,
|
||||
size_t length,
|
||||
int16_t* min_val,
|
||||
int16_t* max_val);
|
||||
#endif
|
||||
|
||||
// Returns the vector index to the largest absolute value of a 16-bit vector.
|
||||
//
|
||||
// Input:
|
||||
@ -240,6 +259,17 @@ int32_t WebRtcSpl_MinValueW32_mips(const int32_t* vector, size_t length);
|
||||
// -32768 presenting an int16 absolute value of 32767).
|
||||
size_t WebRtcSpl_MaxAbsIndexW16(const int16_t* vector, size_t length);
|
||||
|
||||
// Returns the element with the largest absolute value of a 16-bit vector. Note
|
||||
// that this function can return a negative value.
|
||||
//
|
||||
// Input:
|
||||
// - vector : 16-bit input vector.
|
||||
// - length : Number of samples in vector.
|
||||
//
|
||||
// Return value : The element with the largest absolute value. Note that this
|
||||
// may be a negative value.
|
||||
int16_t WebRtcSpl_MaxAbsElementW16(const int16_t* vector, size_t length);
|
||||
|
||||
// Returns the vector index to the maximum sample value of a 16-bit vector.
|
||||
//
|
||||
// Input:
|
||||
@ -396,7 +426,7 @@ void WebRtcSpl_AffineTransformVector(int16_t* out_vector,
|
||||
//
|
||||
// Input:
|
||||
// - in_vector : Vector to calculate autocorrelation upon
|
||||
// - in_vector_length : Length (in samples) of |vector|
|
||||
// - in_vector_length : Length (in samples) of `vector`
|
||||
// - order : The order up to which the autocorrelation should be
|
||||
// calculated
|
||||
//
|
||||
@ -408,7 +438,7 @@ void WebRtcSpl_AffineTransformVector(int16_t* out_vector,
|
||||
// - scale : The number of left shifts required to obtain the
|
||||
// auto-correlation in Q0
|
||||
//
|
||||
// Return value : Number of samples in |result|, i.e. (order+1)
|
||||
// Return value : Number of samples in `result`, i.e. (order+1)
|
||||
size_t WebRtcSpl_AutoCorrelation(const int16_t* in_vector,
|
||||
size_t in_vector_length,
|
||||
size_t order,
|
||||
@ -419,7 +449,7 @@ size_t WebRtcSpl_AutoCorrelation(const int16_t* in_vector,
|
||||
// does NOT use the 64 bit class
|
||||
//
|
||||
// Input:
|
||||
// - auto_corr : Vector with autocorrelation values of length >= |order|+1
|
||||
// - auto_corr : Vector with autocorrelation values of length >= `order`+1
|
||||
// - order : The LPC filter order (support up to order 20)
|
||||
//
|
||||
// Output:
|
||||
@ -432,7 +462,7 @@ int16_t WebRtcSpl_LevinsonDurbin(const int32_t* auto_corr,
|
||||
int16_t* refl_coef,
|
||||
size_t order);
|
||||
|
||||
// Converts reflection coefficients |refl_coef| to LPC coefficients |lpc_coef|.
|
||||
// Converts reflection coefficients `refl_coef` to LPC coefficients `lpc_coef`.
|
||||
// This version is a 16 bit operation.
|
||||
//
|
||||
// NOTE: The 16 bit refl_coef -> lpc_coef conversion might result in a
|
||||
@ -442,7 +472,7 @@ int16_t WebRtcSpl_LevinsonDurbin(const int32_t* auto_corr,
|
||||
// Input:
|
||||
// - refl_coef : Reflection coefficients in Q15 that should be converted
|
||||
// to LPC coefficients
|
||||
// - use_order : Number of coefficients in |refl_coef|
|
||||
// - use_order : Number of coefficients in `refl_coef`
|
||||
//
|
||||
// Output:
|
||||
// - lpc_coef : LPC coefficients in Q12
|
||||
@ -450,14 +480,14 @@ void WebRtcSpl_ReflCoefToLpc(const int16_t* refl_coef,
|
||||
int use_order,
|
||||
int16_t* lpc_coef);
|
||||
|
||||
// Converts LPC coefficients |lpc_coef| to reflection coefficients |refl_coef|.
|
||||
// Converts LPC coefficients `lpc_coef` to reflection coefficients `refl_coef`.
|
||||
// This version is a 16 bit operation.
|
||||
// The conversion is implemented by the step-down algorithm.
|
||||
//
|
||||
// Input:
|
||||
// - lpc_coef : LPC coefficients in Q12, that should be converted to
|
||||
// reflection coefficients
|
||||
// - use_order : Number of coefficients in |lpc_coef|
|
||||
// - use_order : Number of coefficients in `lpc_coef`
|
||||
//
|
||||
// Output:
|
||||
// - refl_coef : Reflection coefficients in Q15.
|
||||
@ -478,24 +508,24 @@ void WebRtcSpl_AutoCorrToReflCoef(const int32_t* auto_corr,
|
||||
int16_t* refl_coef);
|
||||
|
||||
// The functions (with related pointer) calculate the cross-correlation between
|
||||
// two sequences |seq1| and |seq2|.
|
||||
// |seq1| is fixed and |seq2| slides as the pointer is increased with the
|
||||
// amount |step_seq2|. Note the arguments should obey the relationship:
|
||||
// |dim_seq| - 1 + |step_seq2| * (|dim_cross_correlation| - 1) <
|
||||
// buffer size of |seq2|
|
||||
// two sequences `seq1` and `seq2`.
|
||||
// `seq1` is fixed and `seq2` slides as the pointer is increased with the
|
||||
// amount `step_seq2`. Note the arguments should obey the relationship:
|
||||
// `dim_seq` - 1 + `step_seq2` * (`dim_cross_correlation` - 1) <
|
||||
// buffer size of `seq2`
|
||||
//
|
||||
// Input:
|
||||
// - seq1 : First sequence (fixed throughout the correlation)
|
||||
// - seq2 : Second sequence (slides |step_vector2| for each
|
||||
// - seq2 : Second sequence (slides `step_vector2` for each
|
||||
// new correlation)
|
||||
// - dim_seq : Number of samples to use in the cross-correlation
|
||||
// - dim_cross_correlation : Number of cross-correlations to calculate (the
|
||||
// start position for |vector2| is updated for each
|
||||
// start position for `vector2` is updated for each
|
||||
// new one)
|
||||
// - right_shifts : Number of right bit shifts to use. This will
|
||||
// become the output Q-domain.
|
||||
// - step_seq2 : How many (positive or negative) steps the
|
||||
// |vector2| pointer should be updated for each new
|
||||
// `vector2` pointer should be updated for each new
|
||||
// cross-correlation value.
|
||||
//
|
||||
// Output:
|
||||
@ -545,11 +575,11 @@ void WebRtcSpl_CrossCorrelation_mips(int32_t* cross_correlation,
|
||||
void WebRtcSpl_GetHanningWindow(int16_t* window, size_t size);
|
||||
|
||||
// Calculates y[k] = sqrt(1 - x[k]^2) for each element of the input vector
|
||||
// |in_vector|. Input and output values are in Q15.
|
||||
// `in_vector`. Input and output values are in Q15.
|
||||
//
|
||||
// Inputs:
|
||||
// - in_vector : Values to calculate sqrt(1 - x^2) of
|
||||
// - vector_length : Length of vector |in_vector|
|
||||
// - vector_length : Length of vector `in_vector`
|
||||
//
|
||||
// Output:
|
||||
// - out_vector : Output values in Q15
|
||||
@ -637,9 +667,9 @@ void WebRtcSpl_FilterARFastQ12(const int16_t* data_in,
|
||||
// Input:
|
||||
// - data_in : Input samples (state in positions
|
||||
// data_in[-order] .. data_in[-1])
|
||||
// - data_in_length : Number of samples in |data_in| to be filtered.
|
||||
// - data_in_length : Number of samples in `data_in` to be filtered.
|
||||
// This must be at least
|
||||
// |delay| + |factor|*(|out_vector_length|-1) + 1)
|
||||
// `delay` + `factor`*(`out_vector_length`-1) + 1)
|
||||
// - data_out_length : Number of down sampled samples desired
|
||||
// - coefficients : Filter coefficients (in Q12)
|
||||
// - coefficients_length: Number of coefficients (order+1)
|
||||
@ -647,7 +677,7 @@ void WebRtcSpl_FilterARFastQ12(const int16_t* data_in,
|
||||
// - delay : Delay of filter (compensated for in out_vector)
|
||||
// Output:
|
||||
// - data_out : Filtered samples
|
||||
// Return value : 0 if OK, -1 if |in_vector| is too short
|
||||
// Return value : 0 if OK, -1 if `in_vector` is too short
|
||||
typedef int (*DownsampleFast)(const int16_t* data_in,
|
||||
size_t data_in_length,
|
||||
int16_t* data_out,
|
||||
@ -693,12 +723,12 @@ int WebRtcSpl_DownsampleFast_mips(const int16_t* data_in,
|
||||
int WebRtcSpl_ComplexFFT(int16_t vector[], int stages, int mode);
|
||||
int WebRtcSpl_ComplexIFFT(int16_t vector[], int stages, int mode);
|
||||
|
||||
// Treat a 16-bit complex data buffer |complex_data| as an array of 32-bit
|
||||
// Treat a 16-bit complex data buffer `complex_data` as an array of 32-bit
|
||||
// values, and swap elements whose indexes are bit-reverses of each other.
|
||||
//
|
||||
// Input:
|
||||
// - complex_data : Complex data buffer containing 2^|stages| real
|
||||
// elements interleaved with 2^|stages| imaginary
|
||||
// - complex_data : Complex data buffer containing 2^`stages` real
|
||||
// elements interleaved with 2^`stages` imaginary
|
||||
// elements: [Re Im Re Im Re Im....]
|
||||
// - stages : Number of FFT stages. Must be at least 3 and at most
|
||||
// 10, since the table WebRtcSpl_kSinTable1024[] is 1024
|
||||
@ -908,7 +938,7 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// WebRtcSpl_AddSatW32(...)
|
||||
//
|
||||
// Returns the result of a saturated 16-bit, respectively 32-bit, addition of
|
||||
// the numbers specified by the |var1| and |var2| parameters.
|
||||
// the numbers specified by the `var1` and `var2` parameters.
|
||||
//
|
||||
// Input:
|
||||
// - var1 : Input variable 1
|
||||
@ -922,7 +952,7 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// WebRtcSpl_SubSatW32(...)
|
||||
//
|
||||
// Returns the result of a saturated 16-bit, respectively 32-bit, subtraction
|
||||
// of the numbers specified by the |var1| and |var2| parameters.
|
||||
// of the numbers specified by the `var1` and `var2` parameters.
|
||||
//
|
||||
// Input:
|
||||
// - var1 : Input variable 1
|
||||
@ -935,61 +965,61 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// WebRtcSpl_GetSizeInBits(...)
|
||||
//
|
||||
// Returns the # of bits that are needed at the most to represent the number
|
||||
// specified by the |value| parameter.
|
||||
// specified by the `value` parameter.
|
||||
//
|
||||
// Input:
|
||||
// - value : Input value
|
||||
//
|
||||
// Return value : Number of bits needed to represent |value|
|
||||
// Return value : Number of bits needed to represent `value`
|
||||
//
|
||||
|
||||
//
|
||||
// WebRtcSpl_NormW32(...)
|
||||
//
|
||||
// Norm returns the # of left shifts required to 32-bit normalize the 32-bit
|
||||
// signed number specified by the |value| parameter.
|
||||
// signed number specified by the `value` parameter.
|
||||
//
|
||||
// Input:
|
||||
// - value : Input value
|
||||
//
|
||||
// Return value : Number of bit shifts needed to 32-bit normalize |value|
|
||||
// Return value : Number of bit shifts needed to 32-bit normalize `value`
|
||||
//
|
||||
|
||||
//
|
||||
// WebRtcSpl_NormW16(...)
|
||||
//
|
||||
// Norm returns the # of left shifts required to 16-bit normalize the 16-bit
|
||||
// signed number specified by the |value| parameter.
|
||||
// signed number specified by the `value` parameter.
|
||||
//
|
||||
// Input:
|
||||
// - value : Input value
|
||||
//
|
||||
// Return value : Number of bit shifts needed to 32-bit normalize |value|
|
||||
// Return value : Number of bit shifts needed to 32-bit normalize `value`
|
||||
//
|
||||
|
||||
//
|
||||
// WebRtcSpl_NormU32(...)
|
||||
//
|
||||
// Norm returns the # of left shifts required to 32-bit normalize the unsigned
|
||||
// 32-bit number specified by the |value| parameter.
|
||||
// 32-bit number specified by the `value` parameter.
|
||||
//
|
||||
// Input:
|
||||
// - value : Input value
|
||||
//
|
||||
// Return value : Number of bit shifts needed to 32-bit normalize |value|
|
||||
// Return value : Number of bit shifts needed to 32-bit normalize `value`
|
||||
//
|
||||
|
||||
//
|
||||
// WebRtcSpl_GetScalingSquare(...)
|
||||
//
|
||||
// Returns the # of bits required to scale the samples specified in the
|
||||
// |in_vector| parameter so that, if the squares of the samples are added the
|
||||
// # of times specified by the |times| parameter, the 32-bit addition will not
|
||||
// `in_vector` parameter so that, if the squares of the samples are added the
|
||||
// # of times specified by the `times` parameter, the 32-bit addition will not
|
||||
// overflow (result in int32_t).
|
||||
//
|
||||
// Input:
|
||||
// - in_vector : Input vector to check scaling on
|
||||
// - in_vector_length : Samples in |in_vector|
|
||||
// - in_vector_length : Samples in `in_vector`
|
||||
// - times : Number of additions to be performed
|
||||
//
|
||||
// Return value : Number of right bit shifts needed to avoid
|
||||
@ -999,8 +1029,8 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
//
|
||||
// WebRtcSpl_MemSetW16(...)
|
||||
//
|
||||
// Sets all the values in the int16_t vector |vector| of length
|
||||
// |vector_length| to the specified value |set_value|
|
||||
// Sets all the values in the int16_t vector `vector` of length
|
||||
// `vector_length` to the specified value `set_value`
|
||||
//
|
||||
// Input:
|
||||
// - vector : Pointer to the int16_t vector
|
||||
@ -1011,8 +1041,8 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
//
|
||||
// WebRtcSpl_MemSetW32(...)
|
||||
//
|
||||
// Sets all the values in the int32_t vector |vector| of length
|
||||
// |vector_length| to the specified value |set_value|
|
||||
// Sets all the values in the int32_t vector `vector` of length
|
||||
// `vector_length` to the specified value `set_value`
|
||||
//
|
||||
// Input:
|
||||
// - vector : Pointer to the int16_t vector
|
||||
@ -1023,34 +1053,34 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
//
|
||||
// WebRtcSpl_MemCpyReversedOrder(...)
|
||||
//
|
||||
// Copies all the values from the source int16_t vector |in_vector| to a
|
||||
// destination int16_t vector |out_vector|. It is done in reversed order,
|
||||
// meaning that the first sample of |in_vector| is copied to the last sample of
|
||||
// the |out_vector|. The procedure continues until the last sample of
|
||||
// |in_vector| has been copied to the first sample of |out_vector|. This
|
||||
// Copies all the values from the source int16_t vector `in_vector` to a
|
||||
// destination int16_t vector `out_vector`. It is done in reversed order,
|
||||
// meaning that the first sample of `in_vector` is copied to the last sample of
|
||||
// the `out_vector`. The procedure continues until the last sample of
|
||||
// `in_vector` has been copied to the first sample of `out_vector`. This
|
||||
// creates a reversed vector. Used in e.g. prediction in iLBC.
|
||||
//
|
||||
// Input:
|
||||
// - in_vector : Pointer to the first sample in a int16_t vector
|
||||
// of length |length|
|
||||
// of length `length`
|
||||
// - vector_length : Number of elements to copy
|
||||
//
|
||||
// Output:
|
||||
// - out_vector : Pointer to the last sample in a int16_t vector
|
||||
// of length |length|
|
||||
// of length `length`
|
||||
//
|
||||
|
||||
//
|
||||
// WebRtcSpl_CopyFromEndW16(...)
|
||||
//
|
||||
// Copies the rightmost |samples| of |in_vector| (of length |in_vector_length|)
|
||||
// to the vector |out_vector|.
|
||||
// Copies the rightmost `samples` of `in_vector` (of length `in_vector_length`)
|
||||
// to the vector `out_vector`.
|
||||
//
|
||||
// Input:
|
||||
// - in_vector : Input vector
|
||||
// - in_vector_length : Number of samples in |in_vector|
|
||||
// - in_vector_length : Number of samples in `in_vector`
|
||||
// - samples : Number of samples to extract (from right side)
|
||||
// from |in_vector|
|
||||
// from `in_vector`
|
||||
//
|
||||
// Output:
|
||||
// - out_vector : Vector with the requested samples
|
||||
@ -1085,7 +1115,7 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
//
|
||||
// Output:
|
||||
// - out_vector : Pointer to the result vector (can be the same as
|
||||
// |in_vector|)
|
||||
// `in_vector`)
|
||||
//
|
||||
|
||||
//
|
||||
@ -1103,7 +1133,7 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
//
|
||||
// Output:
|
||||
// - out_vector : Pointer to the result vector (can be the same as
|
||||
// |in_vector|)
|
||||
// `in_vector`)
|
||||
//
|
||||
|
||||
//
|
||||
@ -1115,11 +1145,11 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// Input:
|
||||
// - in_vector : Input vector
|
||||
// - gain : Scaling gain
|
||||
// - vector_length : Elements in the |in_vector|
|
||||
// - vector_length : Elements in the `in_vector`
|
||||
// - right_shifts : Number of right bit shifts applied
|
||||
//
|
||||
// Output:
|
||||
// - out_vector : Output vector (can be the same as |in_vector|)
|
||||
// - out_vector : Output vector (can be the same as `in_vector`)
|
||||
//
|
||||
|
||||
//
|
||||
@ -1131,11 +1161,11 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// Input:
|
||||
// - in_vector : Input vector
|
||||
// - gain : Scaling gain
|
||||
// - vector_length : Elements in the |in_vector|
|
||||
// - vector_length : Elements in the `in_vector`
|
||||
// - right_shifts : Number of right bit shifts applied
|
||||
//
|
||||
// Output:
|
||||
// - out_vector : Output vector (can be the same as |in_vector|)
|
||||
// - out_vector : Output vector (can be the same as `in_vector`)
|
||||
//
|
||||
|
||||
//
|
||||
@ -1170,10 +1200,10 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// should be set to the last value in the vector
|
||||
// - right_shifts : Number of right bit shift to be applied after the
|
||||
// multiplication
|
||||
// - vector_length : Number of elements in |in_vector|
|
||||
// - vector_length : Number of elements in `in_vector`
|
||||
//
|
||||
// Output:
|
||||
// - out_vector : Output vector (can be same as |in_vector|)
|
||||
// - out_vector : Output vector (can be same as `in_vector`)
|
||||
//
|
||||
|
||||
//
|
||||
@ -1187,10 +1217,10 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// - window : Window vector.
|
||||
// - right_shifts : Number of right bit shift to be applied after the
|
||||
// multiplication
|
||||
// - vector_length : Number of elements in |in_vector|
|
||||
// - vector_length : Number of elements in `in_vector`
|
||||
//
|
||||
// Output:
|
||||
// - out_vector : Output vector (can be same as |in_vector|)
|
||||
// - out_vector : Output vector (can be same as `in_vector`)
|
||||
//
|
||||
|
||||
//
|
||||
@ -1204,16 +1234,16 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// - in_vector2 : Input vector 2
|
||||
// - right_shifts : Number of right bit shift to be applied after the
|
||||
// multiplication
|
||||
// - vector_length : Number of elements in |in_vector1| and |in_vector2|
|
||||
// - vector_length : Number of elements in `in_vector1` and `in_vector2`
|
||||
//
|
||||
// Output:
|
||||
// - out_vector : Output vector (can be same as |in_vector1|)
|
||||
// - out_vector : Output vector (can be same as `in_vector1`)
|
||||
//
|
||||
|
||||
//
|
||||
// WebRtcSpl_AddAffineVectorToVector(...)
|
||||
//
|
||||
// Adds an affine transformed vector to another vector |out_vector|, i.e,
|
||||
// Adds an affine transformed vector to another vector `out_vector`, i.e,
|
||||
// performs
|
||||
// out_vector[k] += (in_vector[k]*gain+add_constant)>>right_shifts
|
||||
//
|
||||
@ -1223,7 +1253,7 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// - add_constant : Constant value to add (usually 1<<(right_shifts-1),
|
||||
// but others can be used as well
|
||||
// - right_shifts : Number of right bit shifts (0-16)
|
||||
// - vector_length : Number of samples in |in_vector| and |out_vector|
|
||||
// - vector_length : Number of samples in `in_vector` and `out_vector`
|
||||
//
|
||||
// Output:
|
||||
// - out_vector : Vector with the output
|
||||
@ -1241,7 +1271,7 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// - add_constant : Constant value to add (usually 1<<(right_shifts-1),
|
||||
// but others can be used as well
|
||||
// - right_shifts : Number of right bit shifts (0-16)
|
||||
// - vector_length : Number of samples in |in_vector| and |out_vector|
|
||||
// - vector_length : Number of samples in `in_vector` and `out_vector`
|
||||
//
|
||||
// Output:
|
||||
// - out_vector : Vector with the output
|
||||
@ -1304,15 +1334,15 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// - vector : Vector with the uniform values
|
||||
// - seed : Updated seed value
|
||||
//
|
||||
// Return value : Number of samples in vector, i.e., |vector_length|
|
||||
// Return value : Number of samples in vector, i.e., `vector_length`
|
||||
//
|
||||
|
||||
//
|
||||
// WebRtcSpl_Sqrt(...)
|
||||
//
|
||||
// Returns the square root of the input value |value|. The precision of this
|
||||
// Returns the square root of the input value `value`. The precision of this
|
||||
// function is integer precision, i.e., sqrt(8) gives 2 as answer.
|
||||
// If |value| is a negative number then 0 is returned.
|
||||
// If `value` is a negative number then 0 is returned.
|
||||
//
|
||||
// Algorithm:
|
||||
//
|
||||
@ -1332,9 +1362,9 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
//
|
||||
// WebRtcSpl_DivU32U16(...)
|
||||
//
|
||||
// Divides a uint32_t |num| by a uint16_t |den|.
|
||||
// Divides a uint32_t `num` by a uint16_t `den`.
|
||||
//
|
||||
// If |den|==0, (uint32_t)0xFFFFFFFF is returned.
|
||||
// If `den`==0, (uint32_t)0xFFFFFFFF is returned.
|
||||
//
|
||||
// Input:
|
||||
// - num : Numerator
|
||||
@ -1347,9 +1377,9 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
//
|
||||
// WebRtcSpl_DivW32W16(...)
|
||||
//
|
||||
// Divides a int32_t |num| by a int16_t |den|.
|
||||
// Divides a int32_t `num` by a int16_t `den`.
|
||||
//
|
||||
// If |den|==0, (int32_t)0x7FFFFFFF is returned.
|
||||
// If `den`==0, (int32_t)0x7FFFFFFF is returned.
|
||||
//
|
||||
// Input:
|
||||
// - num : Numerator
|
||||
@ -1362,10 +1392,10 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
//
|
||||
// WebRtcSpl_DivW32W16ResW16(...)
|
||||
//
|
||||
// Divides a int32_t |num| by a int16_t |den|, assuming that the
|
||||
// Divides a int32_t `num` by a int16_t `den`, assuming that the
|
||||
// result is less than 32768, otherwise an unpredictable result will occur.
|
||||
//
|
||||
// If |den|==0, (int16_t)0x7FFF is returned.
|
||||
// If `den`==0, (int16_t)0x7FFF is returned.
|
||||
//
|
||||
// Input:
|
||||
// - num : Numerator
|
||||
@ -1378,7 +1408,7 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
//
|
||||
// WebRtcSpl_DivResultInQ31(...)
|
||||
//
|
||||
// Divides a int32_t |num| by a int16_t |den|, assuming that the
|
||||
// Divides a int32_t `num` by a int16_t `den`, assuming that the
|
||||
// absolute value of the denominator is larger than the numerator, otherwise
|
||||
// an unpredictable result will occur.
|
||||
//
|
||||
@ -1392,7 +1422,7 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
//
|
||||
// WebRtcSpl_DivW32HiLow(...)
|
||||
//
|
||||
// Divides a int32_t |num| by a denominator in hi, low format. The
|
||||
// Divides a int32_t `num` by a denominator in hi, low format. The
|
||||
// absolute value of the denominator has to be larger (or equal to) the
|
||||
// numerator.
|
||||
//
|
||||
@ -1417,7 +1447,7 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// - scale_factor : Number of left bit shifts needed to get the physical
|
||||
// energy value, i.e, to get the Q0 value
|
||||
//
|
||||
// Return value : Energy value in Q(-|scale_factor|)
|
||||
// Return value : Energy value in Q(-`scale_factor`)
|
||||
//
|
||||
|
||||
//
|
||||
@ -1428,15 +1458,15 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// Input:
|
||||
// - ar_coef : AR-coefficient vector (values in Q12),
|
||||
// ar_coef[0] must be 4096.
|
||||
// - ar_coef_length : Number of coefficients in |ar_coef|.
|
||||
// - ar_coef_length : Number of coefficients in `ar_coef`.
|
||||
// - in_vector : Vector to be filtered.
|
||||
// - in_vector_length : Number of samples in |in_vector|.
|
||||
// - in_vector_length : Number of samples in `in_vector`.
|
||||
// - filter_state : Current state (higher part) of the filter.
|
||||
// - filter_state_length : Length (in samples) of |filter_state|.
|
||||
// - filter_state_length : Length (in samples) of `filter_state`.
|
||||
// - filter_state_low : Current state (lower part) of the filter.
|
||||
// - filter_state_low_length : Length (in samples) of |filter_state_low|.
|
||||
// - filter_state_low_length : Length (in samples) of `filter_state_low`.
|
||||
// - out_vector_low_length : Maximum length (in samples) of
|
||||
// |out_vector_low|.
|
||||
// `out_vector_low`.
|
||||
//
|
||||
// Output:
|
||||
// - filter_state : Updated state (upper part) vector.
|
||||
@ -1446,7 +1476,7 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// - out_vector_low : Vector containing the lower part of the
|
||||
// filtered values.
|
||||
//
|
||||
// Return value : Number of samples in the |out_vector|.
|
||||
// Return value : Number of samples in the `out_vector`.
|
||||
//
|
||||
|
||||
//
|
||||
@ -1454,11 +1484,11 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
//
|
||||
// Complex Inverse FFT
|
||||
//
|
||||
// Computes an inverse complex 2^|stages|-point FFT on the input vector, which
|
||||
// Computes an inverse complex 2^`stages`-point FFT on the input vector, which
|
||||
// is in bit-reversed order. The original content of the vector is destroyed in
|
||||
// the process, since the input is overwritten by the output, normal-ordered,
|
||||
// FFT vector. With X as the input complex vector, y as the output complex
|
||||
// vector and with M = 2^|stages|, the following is computed:
|
||||
// vector and with M = 2^`stages`, the following is computed:
|
||||
//
|
||||
// M-1
|
||||
// y(k) = sum[X(i)*[cos(2*pi*i*k/M) + j*sin(2*pi*i*k/M)]]
|
||||
@ -1468,8 +1498,8 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// decimation-in-time algorithm with radix-2 butterfly technique.
|
||||
//
|
||||
// Input:
|
||||
// - vector : In pointer to complex vector containing 2^|stages|
|
||||
// real elements interleaved with 2^|stages| imaginary
|
||||
// - vector : In pointer to complex vector containing 2^`stages`
|
||||
// real elements interleaved with 2^`stages` imaginary
|
||||
// elements.
|
||||
// [ReImReImReIm....]
|
||||
// The elements are in Q(-scale) domain, see more on Return
|
||||
@ -1488,10 +1518,10 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// - vector : Out pointer to the FFT vector (the same as input).
|
||||
//
|
||||
// Return Value : The scale value that tells the number of left bit shifts
|
||||
// that the elements in the |vector| should be shifted with
|
||||
// that the elements in the `vector` should be shifted with
|
||||
// in order to get Q0 values, i.e. the physically correct
|
||||
// values. The scale parameter is always 0 or positive,
|
||||
// except if N>1024 (|stages|>10), which returns a scale
|
||||
// except if N>1024 (`stages`>10), which returns a scale
|
||||
// value of -1, indicating error.
|
||||
//
|
||||
|
||||
@ -1500,11 +1530,11 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
//
|
||||
// Complex FFT
|
||||
//
|
||||
// Computes a complex 2^|stages|-point FFT on the input vector, which is in
|
||||
// Computes a complex 2^`stages`-point FFT on the input vector, which is in
|
||||
// bit-reversed order. The original content of the vector is destroyed in
|
||||
// the process, since the input is overwritten by the output, normal-ordered,
|
||||
// FFT vector. With x as the input complex vector, Y as the output complex
|
||||
// vector and with M = 2^|stages|, the following is computed:
|
||||
// vector and with M = 2^`stages`, the following is computed:
|
||||
//
|
||||
// M-1
|
||||
// Y(k) = 1/M * sum[x(i)*[cos(2*pi*i*k/M) + j*sin(2*pi*i*k/M)]]
|
||||
@ -1519,8 +1549,8 @@ void WebRtcSpl_SynthesisQMF(const int16_t* low_band,
|
||||
// accuracy.
|
||||
//
|
||||
// Input:
|
||||
// - vector : In pointer to complex vector containing 2^|stages| real
|
||||
// elements interleaved with 2^|stages| imaginary elements.
|
||||
// - vector : In pointer to complex vector containing 2^`stages` real
|
||||
// elements interleaved with 2^`stages` imaginary elements.
|
||||
// [ReImReImReIm....]
|
||||
// The output is in the Q0 domain.
|
||||
//
|
||||
|
@ -14,6 +14,8 @@
|
||||
#ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_
|
||||
#define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rtc_base/compile_assert_c.h"
|
||||
|
||||
extern const int8_t kWebRtcSpl_CountLeadingZeros32_Table[64];
|
||||
|
@ -15,6 +15,8 @@
|
||||
#ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_ARMV7_H_
|
||||
#define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_ARMV7_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* TODO(kma): Replace some assembly code with GCC intrinsics
|
||||
* (e.g. __builtin_clz).
|
||||
*/
|
||||
|
@ -25,6 +25,7 @@
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "common_audio/signal_processing/include/signal_processing_library.h"
|
||||
@ -67,7 +68,8 @@ int32_t WebRtcSpl_MaxAbsValueW32C(const int32_t* vector, size_t length) {
|
||||
RTC_DCHECK_GT(length, 0);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
absolute = abs((int)vector[i]);
|
||||
absolute =
|
||||
(vector[i] != INT_MIN) ? abs((int)vector[i]) : INT_MAX + (uint32_t)1;
|
||||
if (absolute > maximum) {
|
||||
maximum = absolute;
|
||||
}
|
||||
@ -155,6 +157,15 @@ size_t WebRtcSpl_MaxAbsIndexW16(const int16_t* vector, size_t length) {
|
||||
return index;
|
||||
}
|
||||
|
||||
int16_t WebRtcSpl_MaxAbsElementW16(const int16_t* vector, size_t length) {
|
||||
int16_t min_val, max_val;
|
||||
WebRtcSpl_MinMaxW16(vector, length, &min_val, &max_val);
|
||||
if (min_val == max_val || min_val < -max_val) {
|
||||
return min_val;
|
||||
}
|
||||
return max_val;
|
||||
}
|
||||
|
||||
// Index of maximum value in a word16 vector.
|
||||
size_t WebRtcSpl_MaxIndexW16(const int16_t* vector, size_t length) {
|
||||
size_t i = 0, index = 0;
|
||||
@ -222,3 +233,26 @@ size_t WebRtcSpl_MinIndexW32(const int32_t* vector, size_t length) {
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Finds both the minimum and maximum elements in an array of 16-bit integers.
|
||||
void WebRtcSpl_MinMaxW16(const int16_t* vector, size_t length,
|
||||
int16_t* min_val, int16_t* max_val) {
|
||||
#if defined(WEBRTC_HAS_NEON)
|
||||
return WebRtcSpl_MinMaxW16Neon(vector, length, min_val, max_val);
|
||||
#else
|
||||
int16_t minimum = WEBRTC_SPL_WORD16_MAX;
|
||||
int16_t maximum = WEBRTC_SPL_WORD16_MIN;
|
||||
size_t i = 0;
|
||||
|
||||
RTC_DCHECK_GT(length, 0);
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
if (vector[i] < minimum)
|
||||
minimum = vector[i];
|
||||
if (vector[i] > maximum)
|
||||
maximum = vector[i];
|
||||
}
|
||||
*min_val = minimum;
|
||||
*max_val = maximum;
|
||||
#endif
|
||||
}
|
||||
|
@ -281,3 +281,53 @@ int32_t WebRtcSpl_MinValueW32Neon(const int32_t* vector, size_t length) {
|
||||
return minimum;
|
||||
}
|
||||
|
||||
// Finds both the minimum and maximum elements in an array of 16-bit integers.
|
||||
void WebRtcSpl_MinMaxW16Neon(const int16_t* vector, size_t length,
|
||||
int16_t* min_val, int16_t* max_val) {
|
||||
int16_t minimum = WEBRTC_SPL_WORD16_MAX;
|
||||
int16_t maximum = WEBRTC_SPL_WORD16_MIN;
|
||||
size_t i = 0;
|
||||
size_t residual = length & 0x7;
|
||||
|
||||
RTC_DCHECK_GT(length, 0);
|
||||
|
||||
const int16_t* p_start = vector;
|
||||
int16x8_t min16x8 = vdupq_n_s16(WEBRTC_SPL_WORD16_MAX);
|
||||
int16x8_t max16x8 = vdupq_n_s16(WEBRTC_SPL_WORD16_MIN);
|
||||
|
||||
// First part, unroll the loop 8 times.
|
||||
for (i = 0; i < length - residual; i += 8) {
|
||||
int16x8_t in16x8 = vld1q_s16(p_start);
|
||||
min16x8 = vminq_s16(min16x8, in16x8);
|
||||
max16x8 = vmaxq_s16(max16x8, in16x8);
|
||||
p_start += 8;
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_ARCH_ARM64)
|
||||
minimum = vminvq_s16(min16x8);
|
||||
maximum = vmaxvq_s16(max16x8);
|
||||
#else
|
||||
int16x4_t min16x4 = vmin_s16(vget_low_s16(min16x8), vget_high_s16(min16x8));
|
||||
min16x4 = vpmin_s16(min16x4, min16x4);
|
||||
min16x4 = vpmin_s16(min16x4, min16x4);
|
||||
|
||||
minimum = vget_lane_s16(min16x4, 0);
|
||||
|
||||
int16x4_t max16x4 = vmax_s16(vget_low_s16(max16x8), vget_high_s16(max16x8));
|
||||
max16x4 = vpmax_s16(max16x4, max16x4);
|
||||
max16x4 = vpmax_s16(max16x4, max16x4);
|
||||
|
||||
maximum = vget_lane_s16(max16x4, 0);
|
||||
#endif
|
||||
|
||||
// Second part, do the remaining iterations (if any).
|
||||
for (i = residual; i > 0; i--) {
|
||||
if (*p_start < minimum)
|
||||
minimum = *p_start;
|
||||
if (*p_start > maximum)
|
||||
maximum = *p_start;
|
||||
p_start++;
|
||||
}
|
||||
*min_val = minimum;
|
||||
*max_val = maximum;
|
||||
}
|
||||
|
@ -41,35 +41,39 @@ static const uint16_t WebRtcSpl_kAllPassFilter2[3] = {21333, 49062, 63010};
|
||||
//
|
||||
// Output:
|
||||
// - out_data : Output data sequence (Q10), length equal to
|
||||
// |data_length|
|
||||
// `data_length`
|
||||
//
|
||||
|
||||
void WebRtcSpl_AllPassQMF(int32_t* in_data, size_t data_length,
|
||||
int32_t* out_data, const uint16_t* filter_coefficients,
|
||||
int32_t* filter_state)
|
||||
static void WebRtcSpl_AllPassQMF(int32_t* in_data,
|
||||
size_t data_length,
|
||||
int32_t* out_data,
|
||||
const uint16_t* filter_coefficients,
|
||||
int32_t* filter_state)
|
||||
{
|
||||
// The procedure is to filter the input with three first order all pass filters
|
||||
// (cascade operations).
|
||||
// The procedure is to filter the input with three first order all pass
|
||||
// filters (cascade operations).
|
||||
//
|
||||
// a_3 + q^-1 a_2 + q^-1 a_1 + q^-1
|
||||
// y[n] = ----------- ----------- ----------- x[n]
|
||||
// 1 + a_3q^-1 1 + a_2q^-1 1 + a_1q^-1
|
||||
//
|
||||
// The input vector |filter_coefficients| includes these three filter coefficients.
|
||||
// The filter state contains the in_data state, in_data[-1], followed by
|
||||
// the out_data state, out_data[-1]. This is repeated for each cascade.
|
||||
// The first cascade filter will filter the |in_data| and store the output in
|
||||
// |out_data|. The second will the take the |out_data| as input and make an
|
||||
// intermediate storage in |in_data|, to save memory. The third, and final, cascade
|
||||
// filter operation takes the |in_data| (which is the output from the previous cascade
|
||||
// filter) and store the output in |out_data|.
|
||||
// Note that the input vector values are changed during the process.
|
||||
// The input vector `filter_coefficients` includes these three filter
|
||||
// coefficients. The filter state contains the in_data state, in_data[-1],
|
||||
// followed by the out_data state, out_data[-1]. This is repeated for each
|
||||
// cascade. The first cascade filter will filter the `in_data` and store
|
||||
// the output in `out_data`. The second will the take the `out_data` as
|
||||
// input and make an intermediate storage in `in_data`, to save memory. The
|
||||
// third, and final, cascade filter operation takes the `in_data` (which is
|
||||
// the output from the previous cascade filter) and store the output in
|
||||
// `out_data`. Note that the input vector values are changed during the
|
||||
// process.
|
||||
size_t k;
|
||||
int32_t diff;
|
||||
// First all-pass cascade; filter from in_data to out_data.
|
||||
|
||||
// Let y_i[n] indicate the output of cascade filter i (with filter coefficient a_i) at
|
||||
// vector position n. Then the final output will be y[n] = y_3[n]
|
||||
// Let y_i[n] indicate the output of cascade filter i (with filter
|
||||
// coefficient a_i) at vector position n. Then the final output will be
|
||||
// y[n] = y_3[n]
|
||||
|
||||
// First loop, use the states stored in memory.
|
||||
// "diff" should be safe from wrap around since max values are 2^25
|
||||
|
@ -23,12 +23,12 @@ SmoothingFilterImpl::SmoothingFilterImpl(int init_time_ms)
|
||||
: init_time_ms_(init_time_ms),
|
||||
// Duing the initalization time, we use an increasing alpha. Specifically,
|
||||
// alpha(n) = exp(-powf(init_factor_, n)),
|
||||
// where |init_factor_| is chosen such that
|
||||
// where `init_factor_` is chosen such that
|
||||
// alpha(init_time_ms_) = exp(-1.0f / init_time_ms_),
|
||||
init_factor_(init_time_ms_ == 0
|
||||
? 0.0f
|
||||
: powf(init_time_ms_, -1.0f / init_time_ms_)),
|
||||
// |init_const_| is to a factor to help the calculation during
|
||||
// `init_const_` is to a factor to help the calculation during
|
||||
// initialization phase.
|
||||
init_const_(init_time_ms_ == 0
|
||||
? 0.0f
|
||||
@ -57,7 +57,7 @@ void SmoothingFilterImpl::AddSample(float sample) {
|
||||
|
||||
absl::optional<float> SmoothingFilterImpl::GetAverage() {
|
||||
if (!init_end_time_ms_) {
|
||||
// |init_end_time_ms_| undefined since we have not received any sample.
|
||||
// `init_end_time_ms_` undefined since we have not received any sample.
|
||||
return absl::nullopt;
|
||||
}
|
||||
ExtrapolateLastSample(rtc::TimeMillis());
|
||||
@ -84,17 +84,17 @@ void SmoothingFilterImpl::ExtrapolateLastSample(int64_t time_ms) {
|
||||
|
||||
if (time_ms <= *init_end_time_ms_) {
|
||||
// Current update is to be made during initialization phase.
|
||||
// We update the state as if the |alpha| has been increased according
|
||||
// We update the state as if the `alpha` has been increased according
|
||||
// alpha(n) = exp(-powf(init_factor_, n)),
|
||||
// where n is the time (in millisecond) since the first sample received.
|
||||
// With algebraic derivation as shown in the Appendix, we can find that the
|
||||
// state can be updated in a similar manner as if alpha is a constant,
|
||||
// except for a different multiplier.
|
||||
if (init_time_ms_ == 0) {
|
||||
// This means |init_factor_| = 0.
|
||||
// This means `init_factor_` = 0.
|
||||
multiplier = 0.0f;
|
||||
} else if (init_time_ms_ == 1) {
|
||||
// This means |init_factor_| = 1.
|
||||
// This means `init_factor_` = 1.
|
||||
multiplier = std::exp(last_state_time_ms_ - time_ms);
|
||||
} else {
|
||||
multiplier = std::exp(
|
||||
|
@ -33,13 +33,13 @@ class SmoothingFilter {
|
||||
// assumed to equal the last received sample.
|
||||
class SmoothingFilterImpl final : public SmoothingFilter {
|
||||
public:
|
||||
// |init_time_ms| is initialization time. It defines a period starting from
|
||||
// `init_time_ms` is initialization time. It defines a period starting from
|
||||
// the arriving time of the first sample. During this period, the exponential
|
||||
// filter uses a varying time constant so that a smaller time constant will be
|
||||
// applied to the earlier samples. This is to allow the the filter to adapt to
|
||||
// earlier samples quickly. After the initialization period, the time constant
|
||||
// will be set to |init_time_ms| first and can be changed through
|
||||
// |SetTimeConstantMs|.
|
||||
// will be set to `init_time_ms` first and can be changed through
|
||||
// `SetTimeConstantMs`.
|
||||
explicit SmoothingFilterImpl(int init_time_ms);
|
||||
|
||||
SmoothingFilterImpl() = delete;
|
||||
|
@ -286,11 +286,11 @@ Appendix :
|
||||
w[] and ip[] are compatible with all routines.
|
||||
*/
|
||||
|
||||
#include "common_audio/third_party/ooura/fft_size_256/fft4g.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "common_audio/third_party/ooura/fft_size_256/fft4g.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
|
@ -11,6 +11,8 @@
|
||||
#ifndef COMMON_AUDIO_THIRD_PARTY_OOURA_FFT_SIZE_256_FFT4G_H_
|
||||
#define COMMON_AUDIO_THIRD_PARTY_OOURA_FFT_SIZE_256_FFT4G_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
// Refer to fft4g.c for documentation.
|
||||
|
@ -13,9 +13,9 @@
|
||||
//
|
||||
// WebRtcSpl_SqrtFloor(...)
|
||||
//
|
||||
// Returns the square root of the input value |value|. The precision of this
|
||||
// Returns the square root of the input value `value`. The precision of this
|
||||
// function is rounding down integer precision, i.e., sqrt(8) gives 2 as answer.
|
||||
// If |value| is a negative number then 0 is returned.
|
||||
// If `value` is a negative number then 0 is returned.
|
||||
//
|
||||
// Algorithm:
|
||||
//
|
||||
|
@ -54,7 +54,7 @@ int WebRtcVad_Init(VadInst* handle);
|
||||
// has not been initialized).
|
||||
int WebRtcVad_set_mode(VadInst* handle, int mode);
|
||||
|
||||
// Calculates a VAD decision for the |audio_frame|. For valid sampling rates
|
||||
// Calculates a VAD decision for the `audio_frame`. For valid sampling rates
|
||||
// frame lengths, see the description of WebRtcVad_ValidRatesAndFrameLengths().
|
||||
//
|
||||
// - handle [i/o] : VAD Instance. Needs to be initialized by
|
||||
@ -71,7 +71,7 @@ int WebRtcVad_Process(VadInst* handle,
|
||||
const int16_t* audio_frame,
|
||||
size_t frame_length);
|
||||
|
||||
// Checks for valid combinations of |rate| and |frame_length|. We support 10,
|
||||
// Checks for valid combinations of `rate` and `frame_length`. We support 10,
|
||||
// 20 and 30 ms frames and the rates 8000, 16000 and 32000 Hz.
|
||||
//
|
||||
// - rate [i] : Sampling frequency (Hz).
|
||||
|
@ -38,7 +38,7 @@ class VadImpl final : public Vad {
|
||||
case 1:
|
||||
return kActive;
|
||||
default:
|
||||
RTC_NOTREACHED() << "WebRtcVad_Process returned an error.";
|
||||
RTC_DCHECK_NOTREACHED() << "WebRtcVad_Process returned an error.";
|
||||
return kError;
|
||||
}
|
||||
}
|
||||
|
@ -90,11 +90,11 @@ static const int16_t kOverHangMax2VAG[3] = { 9, 5, 3 };
|
||||
static const int16_t kLocalThresholdVAG[3] = { 94, 94, 94 };
|
||||
static const int16_t kGlobalThresholdVAG[3] = { 1100, 1050, 1100 };
|
||||
|
||||
// Calculates the weighted average w.r.t. number of Gaussians. The |data| are
|
||||
// updated with an |offset| before averaging.
|
||||
// Calculates the weighted average w.r.t. number of Gaussians. The `data` are
|
||||
// updated with an `offset` before averaging.
|
||||
//
|
||||
// - data [i/o] : Data to average.
|
||||
// - offset [i] : An offset added to |data|.
|
||||
// - offset [i] : An offset added to `data`.
|
||||
// - weights [i] : Weights used for averaging.
|
||||
//
|
||||
// returns : The weighted average.
|
||||
@ -124,7 +124,7 @@ static inline int32_t RTC_NO_SANITIZE("signed-integer-overflow")
|
||||
// type of signal is most probable.
|
||||
//
|
||||
// - self [i/o] : Pointer to VAD instance
|
||||
// - features [i] : Feature vector of length |kNumChannels|
|
||||
// - features [i] : Feature vector of length `kNumChannels`
|
||||
// = log10(energy in frequency band)
|
||||
// - total_power [i] : Total power in audio frame.
|
||||
// - frame_length [i] : Number of input samples
|
||||
@ -183,10 +183,10 @@ static int16_t GmmProbability(VadInstT* self, int16_t* features,
|
||||
// H1: Speech
|
||||
//
|
||||
// We combine a global LRT with local tests, for each frequency sub-band,
|
||||
// here defined as |channel|.
|
||||
// here defined as `channel`.
|
||||
for (channel = 0; channel < kNumChannels; channel++) {
|
||||
// For each channel we model the probability with a GMM consisting of
|
||||
// |kNumGaussians|, with different means and standard deviations depending
|
||||
// `kNumGaussians`, with different means and standard deviations depending
|
||||
// on H0 or H1.
|
||||
h0_test = 0;
|
||||
h1_test = 0;
|
||||
@ -234,7 +234,7 @@ static int16_t GmmProbability(VadInstT* self, int16_t* features,
|
||||
}
|
||||
log_likelihood_ratio = shifts_h0 - shifts_h1;
|
||||
|
||||
// Update |sum_log_likelihood_ratios| with spectrum weighting. This is
|
||||
// Update `sum_log_likelihood_ratios` with spectrum weighting. This is
|
||||
// used for the global VAD decision.
|
||||
sum_log_likelihood_ratios +=
|
||||
(int32_t) (log_likelihood_ratio * kSpectrumWeight[channel]);
|
||||
@ -298,8 +298,8 @@ static int16_t GmmProbability(VadInstT* self, int16_t* features,
|
||||
nmk2 = nmk;
|
||||
if (!vadflag) {
|
||||
// deltaN = (x-mu)/sigma^2
|
||||
// ngprvec[k] = |noise_probability[k]| /
|
||||
// (|noise_probability[0]| + |noise_probability[1]|)
|
||||
// ngprvec[k] = `noise_probability[k]` /
|
||||
// (`noise_probability[0]` + `noise_probability[1]`)
|
||||
|
||||
// (Q14 * Q11 >> 11) = Q14.
|
||||
delt = (int16_t)((ngprvec[gaussian] * deltaN[gaussian]) >> 11);
|
||||
@ -326,9 +326,9 @@ static int16_t GmmProbability(VadInstT* self, int16_t* features,
|
||||
|
||||
if (vadflag) {
|
||||
// Update speech mean vector:
|
||||
// |deltaS| = (x-mu)/sigma^2
|
||||
// sgprvec[k] = |speech_probability[k]| /
|
||||
// (|speech_probability[0]| + |speech_probability[1]|)
|
||||
// `deltaS` = (x-mu)/sigma^2
|
||||
// sgprvec[k] = `speech_probability[k]` /
|
||||
// (`speech_probability[0]` + `speech_probability[1]`)
|
||||
|
||||
// (Q14 * Q11) >> 11 = Q14.
|
||||
delt = (int16_t)((sgprvec[gaussian] * deltaS[gaussian]) >> 11);
|
||||
@ -409,35 +409,35 @@ static int16_t GmmProbability(VadInstT* self, int16_t* features,
|
||||
}
|
||||
|
||||
// Separate models if they are too close.
|
||||
// |noise_global_mean| in Q14 (= Q7 * Q7).
|
||||
// `noise_global_mean` in Q14 (= Q7 * Q7).
|
||||
noise_global_mean = WeightedAverage(&self->noise_means[channel], 0,
|
||||
&kNoiseDataWeights[channel]);
|
||||
|
||||
// |speech_global_mean| in Q14 (= Q7 * Q7).
|
||||
// `speech_global_mean` in Q14 (= Q7 * Q7).
|
||||
speech_global_mean = WeightedAverage(&self->speech_means[channel], 0,
|
||||
&kSpeechDataWeights[channel]);
|
||||
|
||||
// |diff| = "global" speech mean - "global" noise mean.
|
||||
// `diff` = "global" speech mean - "global" noise mean.
|
||||
// (Q14 >> 9) - (Q14 >> 9) = Q5.
|
||||
diff = (int16_t) (speech_global_mean >> 9) -
|
||||
(int16_t) (noise_global_mean >> 9);
|
||||
if (diff < kMinimumDifference[channel]) {
|
||||
tmp_s16 = kMinimumDifference[channel] - diff;
|
||||
|
||||
// |tmp1_s16| = ~0.8 * (kMinimumDifference - diff) in Q7.
|
||||
// |tmp2_s16| = ~0.2 * (kMinimumDifference - diff) in Q7.
|
||||
// `tmp1_s16` = ~0.8 * (kMinimumDifference - diff) in Q7.
|
||||
// `tmp2_s16` = ~0.2 * (kMinimumDifference - diff) in Q7.
|
||||
tmp1_s16 = (int16_t)((13 * tmp_s16) >> 2);
|
||||
tmp2_s16 = (int16_t)((3 * tmp_s16) >> 2);
|
||||
|
||||
// Move Gaussian means for speech model by |tmp1_s16| and update
|
||||
// |speech_global_mean|. Note that |self->speech_means[channel]| is
|
||||
// Move Gaussian means for speech model by `tmp1_s16` and update
|
||||
// `speech_global_mean`. Note that `self->speech_means[channel]` is
|
||||
// changed after the call.
|
||||
speech_global_mean = WeightedAverage(&self->speech_means[channel],
|
||||
tmp1_s16,
|
||||
&kSpeechDataWeights[channel]);
|
||||
|
||||
// Move Gaussian means for noise model by -|tmp2_s16| and update
|
||||
// |noise_global_mean|. Note that |self->noise_means[channel]| is
|
||||
// Move Gaussian means for noise model by -`tmp2_s16` and update
|
||||
// `noise_global_mean`. Note that `self->noise_means[channel]` is
|
||||
// changed after the call.
|
||||
noise_global_mean = WeightedAverage(&self->noise_means[channel],
|
||||
-tmp2_s16,
|
||||
@ -534,7 +534,7 @@ int WebRtcVad_InitCore(VadInstT* self) {
|
||||
self->mean_value[i] = 1600;
|
||||
}
|
||||
|
||||
// Set aggressiveness mode to default (=|kDefaultMode|).
|
||||
// Set aggressiveness mode to default (=`kDefaultMode`).
|
||||
if (WebRtcVad_set_mode_core(self, kDefaultMode) != 0) {
|
||||
return -1;
|
||||
}
|
||||
@ -609,7 +609,7 @@ int WebRtcVad_CalcVad48khz(VadInstT* inst, const int16_t* speech_frame,
|
||||
int vad;
|
||||
size_t i;
|
||||
int16_t speech_nb[240]; // 30 ms in 8 kHz.
|
||||
// |tmp_mem| is a temporary memory used by resample function, length is
|
||||
// `tmp_mem` is a temporary memory used by resample function, length is
|
||||
// frame length in 10 ms (480 samples) + 256 extra.
|
||||
int32_t tmp_mem[480 + 256] = { 0 };
|
||||
const size_t kFrameLen10ms48khz = 480;
|
||||
|
@ -17,10 +17,19 @@
|
||||
|
||||
#include "common_audio/signal_processing/include/signal_processing_library.h"
|
||||
|
||||
enum { kNumChannels = 6 }; // Number of frequency bands (named channels).
|
||||
enum { kNumGaussians = 2 }; // Number of Gaussians per channel in the GMM.
|
||||
enum { kTableSize = kNumChannels * kNumGaussians };
|
||||
enum { kMinEnergy = 10 }; // Minimum energy required to trigger audio signal.
|
||||
// TODO(https://bugs.webrtc.org/14476): When converted to C++, remove the macro.
|
||||
#if defined(__cplusplus)
|
||||
#define CONSTEXPR_INT(x) constexpr int x
|
||||
#else
|
||||
#define CONSTEXPR_INT(x) enum { x }
|
||||
#endif
|
||||
|
||||
CONSTEXPR_INT(kNumChannels = 6); // Number of frequency bands (named channels).
|
||||
CONSTEXPR_INT(
|
||||
kNumGaussians = 2); // Number of Gaussians per channel in the GMM.
|
||||
CONSTEXPR_INT(kTableSize = kNumChannels * kNumGaussians);
|
||||
CONSTEXPR_INT(
|
||||
kMinEnergy = 10); // Minimum energy required to trigger audio signal.
|
||||
|
||||
typedef struct VadInstT_ {
|
||||
int vad;
|
||||
@ -30,14 +39,14 @@ typedef struct VadInstT_ {
|
||||
int16_t speech_means[kTableSize];
|
||||
int16_t noise_stds[kTableSize];
|
||||
int16_t speech_stds[kTableSize];
|
||||
// TODO(bjornv): Change to |frame_count|.
|
||||
// TODO(bjornv): Change to `frame_count`.
|
||||
int32_t frame_counter;
|
||||
int16_t over_hang; // Over Hang
|
||||
int16_t num_of_speech;
|
||||
// TODO(bjornv): Change to |age_vector|.
|
||||
// TODO(bjornv): Change to `age_vector`.
|
||||
int16_t index_vector[16 * kNumChannels];
|
||||
int16_t low_value_vector[16 * kNumChannels];
|
||||
// TODO(bjornv): Change to |median|.
|
||||
// TODO(bjornv): Change to `median`.
|
||||
int16_t mean_value[kNumChannels];
|
||||
int16_t upper_state[5];
|
||||
int16_t lower_state[5];
|
||||
@ -51,7 +60,7 @@ typedef struct VadInstT_ {
|
||||
} VadInstT;
|
||||
|
||||
// Initializes the core VAD component. The default aggressiveness mode is
|
||||
// controlled by |kDefaultMode| in vad_core.c.
|
||||
// controlled by `kDefaultMode` in vad_core.c.
|
||||
//
|
||||
// - self [i/o] : Instance that should be initialized
|
||||
//
|
||||
|
@ -28,7 +28,7 @@ static const int16_t kAllPassCoefsQ15[2] = { 20972, 5571 };
|
||||
// Adjustment for division with two in SplitFilter.
|
||||
static const int16_t kOffsetVector[6] = { 368, 368, 272, 176, 176, 176 };
|
||||
|
||||
// High pass filtering, with a cut-off frequency at 80 Hz, if the |data_in| is
|
||||
// High pass filtering, with a cut-off frequency at 80 Hz, if the `data_in` is
|
||||
// sampled at 500 Hz.
|
||||
//
|
||||
// - data_in [i] : Input audio data sampled at 500 Hz.
|
||||
@ -69,9 +69,9 @@ static void HighPassFilter(const int16_t* data_in, size_t data_length,
|
||||
}
|
||||
}
|
||||
|
||||
// All pass filtering of |data_in|, used before splitting the signal into two
|
||||
// All pass filtering of `data_in`, used before splitting the signal into two
|
||||
// frequency bands (low pass vs high pass).
|
||||
// Note that |data_in| and |data_out| can NOT correspond to the same address.
|
||||
// Note that `data_in` and `data_out` can NOT correspond to the same address.
|
||||
//
|
||||
// - data_in [i] : Input audio signal given in Q0.
|
||||
// - data_length [i] : Length of input and output data.
|
||||
@ -104,17 +104,17 @@ static void AllPassFilter(const int16_t* data_in, size_t data_length,
|
||||
*filter_state = (int16_t) (state32 >> 16); // Q(-1)
|
||||
}
|
||||
|
||||
// Splits |data_in| into |hp_data_out| and |lp_data_out| corresponding to
|
||||
// Splits `data_in` into `hp_data_out` and `lp_data_out` corresponding to
|
||||
// an upper (high pass) part and a lower (low pass) part respectively.
|
||||
//
|
||||
// - data_in [i] : Input audio data to be split into two frequency bands.
|
||||
// - data_length [i] : Length of |data_in|.
|
||||
// - data_length [i] : Length of `data_in`.
|
||||
// - upper_state [i/o] : State of the upper filter, given in Q(-1).
|
||||
// - lower_state [i/o] : State of the lower filter, given in Q(-1).
|
||||
// - hp_data_out [o] : Output audio data of the upper half of the spectrum.
|
||||
// The length is |data_length| / 2.
|
||||
// The length is `data_length` / 2.
|
||||
// - lp_data_out [o] : Output audio data of the lower half of the spectrum.
|
||||
// The length is |data_length| / 2.
|
||||
// The length is `data_length` / 2.
|
||||
static void SplitFilter(const int16_t* data_in, size_t data_length,
|
||||
int16_t* upper_state, int16_t* lower_state,
|
||||
int16_t* hp_data_out, int16_t* lp_data_out) {
|
||||
@ -138,23 +138,23 @@ static void SplitFilter(const int16_t* data_in, size_t data_length,
|
||||
}
|
||||
}
|
||||
|
||||
// Calculates the energy of |data_in| in dB, and also updates an overall
|
||||
// |total_energy| if necessary.
|
||||
// Calculates the energy of `data_in` in dB, and also updates an overall
|
||||
// `total_energy` if necessary.
|
||||
//
|
||||
// - data_in [i] : Input audio data for energy calculation.
|
||||
// - data_length [i] : Length of input data.
|
||||
// - offset [i] : Offset value added to |log_energy|.
|
||||
// - offset [i] : Offset value added to `log_energy`.
|
||||
// - total_energy [i/o] : An external energy updated with the energy of
|
||||
// |data_in|.
|
||||
// NOTE: |total_energy| is only updated if
|
||||
// |total_energy| <= |kMinEnergy|.
|
||||
// - log_energy [o] : 10 * log10("energy of |data_in|") given in Q4.
|
||||
// `data_in`.
|
||||
// NOTE: `total_energy` is only updated if
|
||||
// `total_energy` <= `kMinEnergy`.
|
||||
// - log_energy [o] : 10 * log10("energy of `data_in`") given in Q4.
|
||||
static void LogOfEnergy(const int16_t* data_in, size_t data_length,
|
||||
int16_t offset, int16_t* total_energy,
|
||||
int16_t* log_energy) {
|
||||
// |tot_rshifts| accumulates the number of right shifts performed on |energy|.
|
||||
// `tot_rshifts` accumulates the number of right shifts performed on `energy`.
|
||||
int tot_rshifts = 0;
|
||||
// The |energy| will be normalized to 15 bits. We use unsigned integer because
|
||||
// The `energy` will be normalized to 15 bits. We use unsigned integer because
|
||||
// we eventually will mask out the fractional part.
|
||||
uint32_t energy = 0;
|
||||
|
||||
@ -169,14 +169,14 @@ static void LogOfEnergy(const int16_t* data_in, size_t data_length,
|
||||
// zeros of an unsigned 32 bit value.
|
||||
int normalizing_rshifts = 17 - WebRtcSpl_NormU32(energy);
|
||||
// In a 15 bit representation the leading bit is 2^14. log2(2^14) in Q10 is
|
||||
// (14 << 10), which is what we initialize |log2_energy| with. For a more
|
||||
// (14 << 10), which is what we initialize `log2_energy` with. For a more
|
||||
// detailed derivations, see below.
|
||||
int16_t log2_energy = kLogEnergyIntPart;
|
||||
|
||||
tot_rshifts += normalizing_rshifts;
|
||||
// Normalize |energy| to 15 bits.
|
||||
// |tot_rshifts| is now the total number of right shifts performed on
|
||||
// |energy| after normalization. This means that |energy| is in
|
||||
// Normalize `energy` to 15 bits.
|
||||
// `tot_rshifts` is now the total number of right shifts performed on
|
||||
// `energy` after normalization. This means that `energy` is in
|
||||
// Q(-tot_rshifts).
|
||||
if (normalizing_rshifts < 0) {
|
||||
energy <<= -normalizing_rshifts;
|
||||
@ -184,30 +184,30 @@ static void LogOfEnergy(const int16_t* data_in, size_t data_length,
|
||||
energy >>= normalizing_rshifts;
|
||||
}
|
||||
|
||||
// Calculate the energy of |data_in| in dB, in Q4.
|
||||
// Calculate the energy of `data_in` in dB, in Q4.
|
||||
//
|
||||
// 10 * log10("true energy") in Q4 = 2^4 * 10 * log10("true energy") =
|
||||
// 160 * log10(|energy| * 2^|tot_rshifts|) =
|
||||
// 160 * log10(2) * log2(|energy| * 2^|tot_rshifts|) =
|
||||
// 160 * log10(2) * (log2(|energy|) + log2(2^|tot_rshifts|)) =
|
||||
// (160 * log10(2)) * (log2(|energy|) + |tot_rshifts|) =
|
||||
// |kLogConst| * (|log2_energy| + |tot_rshifts|)
|
||||
// 160 * log10(`energy` * 2^`tot_rshifts`) =
|
||||
// 160 * log10(2) * log2(`energy` * 2^`tot_rshifts`) =
|
||||
// 160 * log10(2) * (log2(`energy`) + log2(2^`tot_rshifts`)) =
|
||||
// (160 * log10(2)) * (log2(`energy`) + `tot_rshifts`) =
|
||||
// `kLogConst` * (`log2_energy` + `tot_rshifts`)
|
||||
//
|
||||
// We know by construction that |energy| is normalized to 15 bits. Hence,
|
||||
// |energy| = 2^14 + frac_Q15, where frac_Q15 is a fractional part in Q15.
|
||||
// Further, we'd like |log2_energy| in Q10
|
||||
// log2(|energy|) in Q10 = 2^10 * log2(2^14 + frac_Q15) =
|
||||
// We know by construction that `energy` is normalized to 15 bits. Hence,
|
||||
// `energy` = 2^14 + frac_Q15, where frac_Q15 is a fractional part in Q15.
|
||||
// Further, we'd like `log2_energy` in Q10
|
||||
// log2(`energy`) in Q10 = 2^10 * log2(2^14 + frac_Q15) =
|
||||
// 2^10 * log2(2^14 * (1 + frac_Q15 * 2^-14)) =
|
||||
// 2^10 * (14 + log2(1 + frac_Q15 * 2^-14)) ~=
|
||||
// (14 << 10) + 2^10 * (frac_Q15 * 2^-14) =
|
||||
// (14 << 10) + (frac_Q15 * 2^-4) = (14 << 10) + (frac_Q15 >> 4)
|
||||
//
|
||||
// Note that frac_Q15 = (|energy| & 0x00003FFF)
|
||||
// Note that frac_Q15 = (`energy` & 0x00003FFF)
|
||||
|
||||
// Calculate and add the fractional part to |log2_energy|.
|
||||
// Calculate and add the fractional part to `log2_energy`.
|
||||
log2_energy += (int16_t) ((energy & 0x00003FFF) >> 4);
|
||||
|
||||
// |kLogConst| is in Q9, |log2_energy| in Q10 and |tot_rshifts| in Q0.
|
||||
// `kLogConst` is in Q9, `log2_energy` in Q10 and `tot_rshifts` in Q0.
|
||||
// Note that we in our derivation above have accounted for an output in Q4.
|
||||
*log_energy = (int16_t)(((kLogConst * log2_energy) >> 19) +
|
||||
((tot_rshifts * kLogConst) >> 9));
|
||||
@ -222,19 +222,19 @@ static void LogOfEnergy(const int16_t* data_in, size_t data_length,
|
||||
|
||||
*log_energy += offset;
|
||||
|
||||
// Update the approximate |total_energy| with the energy of |data_in|, if
|
||||
// |total_energy| has not exceeded |kMinEnergy|. |total_energy| is used as an
|
||||
// Update the approximate `total_energy` with the energy of `data_in`, if
|
||||
// `total_energy` has not exceeded `kMinEnergy`. `total_energy` is used as an
|
||||
// energy indicator in WebRtcVad_GmmProbability() in vad_core.c.
|
||||
if (*total_energy <= kMinEnergy) {
|
||||
if (tot_rshifts >= 0) {
|
||||
// We know by construction that the |energy| > |kMinEnergy| in Q0, so add
|
||||
// an arbitrary value such that |total_energy| exceeds |kMinEnergy|.
|
||||
// We know by construction that the `energy` > `kMinEnergy` in Q0, so add
|
||||
// an arbitrary value such that `total_energy` exceeds `kMinEnergy`.
|
||||
*total_energy += kMinEnergy + 1;
|
||||
} else {
|
||||
// By construction |energy| is represented by 15 bits, hence any number of
|
||||
// right shifted |energy| will fit in an int16_t. In addition, adding the
|
||||
// value to |total_energy| is wrap around safe as long as
|
||||
// |kMinEnergy| < 8192.
|
||||
// By construction `energy` is represented by 15 bits, hence any number of
|
||||
// right shifted `energy` will fit in an int16_t. In addition, adding the
|
||||
// value to `total_energy` is wrap around safe as long as
|
||||
// `kMinEnergy` < 8192.
|
||||
*total_energy += (int16_t) (energy >> -tot_rshifts); // Q0.
|
||||
}
|
||||
}
|
||||
@ -243,14 +243,14 @@ static void LogOfEnergy(const int16_t* data_in, size_t data_length,
|
||||
int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in,
|
||||
size_t data_length, int16_t* features) {
|
||||
int16_t total_energy = 0;
|
||||
// We expect |data_length| to be 80, 160 or 240 samples, which corresponds to
|
||||
// We expect `data_length` to be 80, 160 or 240 samples, which corresponds to
|
||||
// 10, 20 or 30 ms in 8 kHz. Therefore, the intermediate downsampled data will
|
||||
// have at most 120 samples after the first split and at most 60 samples after
|
||||
// the second split.
|
||||
int16_t hp_120[120], lp_120[120];
|
||||
int16_t hp_60[60], lp_60[60];
|
||||
const size_t half_data_length = data_length >> 1;
|
||||
size_t length = half_data_length; // |data_length| / 2, corresponds to
|
||||
size_t length = half_data_length; // `data_length` / 2, corresponds to
|
||||
// bandwidth = 2000 Hz after downsampling.
|
||||
|
||||
// Initialize variables for the first SplitFilter().
|
||||
@ -260,7 +260,7 @@ int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in,
|
||||
int16_t* lp_out_ptr = lp_120; // [0 - 2000] Hz.
|
||||
|
||||
RTC_DCHECK_LE(data_length, 240);
|
||||
RTC_DCHECK_LT(4, kNumChannels - 1); // Checking maximum |frequency_band|.
|
||||
RTC_DCHECK_LT(4, kNumChannels - 1); // Checking maximum `frequency_band`.
|
||||
|
||||
// Split at 2000 Hz and downsample.
|
||||
SplitFilter(in_ptr, data_length, &self->upper_state[frequency_band],
|
||||
@ -275,7 +275,7 @@ int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in,
|
||||
&self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr);
|
||||
|
||||
// Energy in 3000 Hz - 4000 Hz.
|
||||
length >>= 1; // |data_length| / 4 <=> bandwidth = 1000 Hz.
|
||||
length >>= 1; // `data_length` / 4 <=> bandwidth = 1000 Hz.
|
||||
|
||||
LogOfEnergy(hp_60, length, kOffsetVector[5], &total_energy, &features[5]);
|
||||
|
||||
@ -287,12 +287,12 @@ int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in,
|
||||
in_ptr = lp_120; // [0 - 2000] Hz.
|
||||
hp_out_ptr = hp_60; // [1000 - 2000] Hz.
|
||||
lp_out_ptr = lp_60; // [0 - 1000] Hz.
|
||||
length = half_data_length; // |data_length| / 2 <=> bandwidth = 2000 Hz.
|
||||
length = half_data_length; // `data_length` / 2 <=> bandwidth = 2000 Hz.
|
||||
SplitFilter(in_ptr, length, &self->upper_state[frequency_band],
|
||||
&self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr);
|
||||
|
||||
// Energy in 1000 Hz - 2000 Hz.
|
||||
length >>= 1; // |data_length| / 4 <=> bandwidth = 1000 Hz.
|
||||
length >>= 1; // `data_length` / 4 <=> bandwidth = 1000 Hz.
|
||||
LogOfEnergy(hp_60, length, kOffsetVector[3], &total_energy, &features[3]);
|
||||
|
||||
// For the lower band (0 Hz - 1000 Hz) split at 500 Hz and downsample.
|
||||
@ -304,7 +304,7 @@ int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in,
|
||||
&self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr);
|
||||
|
||||
// Energy in 500 Hz - 1000 Hz.
|
||||
length >>= 1; // |data_length| / 8 <=> bandwidth = 500 Hz.
|
||||
length >>= 1; // `data_length` / 8 <=> bandwidth = 500 Hz.
|
||||
LogOfEnergy(hp_120, length, kOffsetVector[2], &total_energy, &features[2]);
|
||||
|
||||
// For the lower band (0 Hz - 500 Hz) split at 250 Hz and downsample.
|
||||
@ -316,7 +316,7 @@ int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in,
|
||||
&self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr);
|
||||
|
||||
// Energy in 250 Hz - 500 Hz.
|
||||
length >>= 1; // |data_length| / 16 <=> bandwidth = 250 Hz.
|
||||
length >>= 1; // `data_length` / 16 <=> bandwidth = 250 Hz.
|
||||
LogOfEnergy(hp_60, length, kOffsetVector[1], &total_energy, &features[1]);
|
||||
|
||||
// Remove 0 Hz - 80 Hz, by high pass filtering the lower band.
|
||||
|
@ -17,8 +17,8 @@
|
||||
|
||||
#include "common_audio/vad/vad_core.h"
|
||||
|
||||
// Takes |data_length| samples of |data_in| and calculates the logarithm of the
|
||||
// energy of each of the |kNumChannels| = 6 frequency bands used by the VAD:
|
||||
// Takes `data_length` samples of `data_in` and calculates the logarithm of the
|
||||
// energy of each of the `kNumChannels` = 6 frequency bands used by the VAD:
|
||||
// 80 Hz - 250 Hz
|
||||
// 250 Hz - 500 Hz
|
||||
// 500 Hz - 1000 Hz
|
||||
@ -26,10 +26,10 @@
|
||||
// 2000 Hz - 3000 Hz
|
||||
// 3000 Hz - 4000 Hz
|
||||
//
|
||||
// The values are given in Q4 and written to |features|. Further, an approximate
|
||||
// The values are given in Q4 and written to `features`. Further, an approximate
|
||||
// overall energy is returned. The return value is used in
|
||||
// WebRtcVad_GmmProbability() as a signal indicator, hence it is arbitrary above
|
||||
// the threshold |kMinEnergy|.
|
||||
// the threshold `kMinEnergy`.
|
||||
//
|
||||
// - self [i/o] : State information of the VAD.
|
||||
// - data_in [i] : Input audio data, for feature extraction.
|
||||
|
@ -15,16 +15,16 @@
|
||||
static const int32_t kCompVar = 22005;
|
||||
static const int16_t kLog2Exp = 5909; // log2(exp(1)) in Q12.
|
||||
|
||||
// For a normal distribution, the probability of |input| is calculated and
|
||||
// For a normal distribution, the probability of `input` is calculated and
|
||||
// returned (in Q20). The formula for normal distributed probability is
|
||||
//
|
||||
// 1 / s * exp(-(x - m)^2 / (2 * s^2))
|
||||
//
|
||||
// where the parameters are given in the following Q domains:
|
||||
// m = |mean| (Q7)
|
||||
// s = |std| (Q7)
|
||||
// x = |input| (Q4)
|
||||
// in addition to the probability we output |delta| (in Q11) used when updating
|
||||
// m = `mean` (Q7)
|
||||
// s = `std` (Q7)
|
||||
// x = `input` (Q4)
|
||||
// in addition to the probability we output `delta` (in Q11) used when updating
|
||||
// the noise/speech model.
|
||||
int32_t WebRtcVad_GaussianProbability(int16_t input,
|
||||
int16_t mean,
|
||||
@ -33,13 +33,13 @@ int32_t WebRtcVad_GaussianProbability(int16_t input,
|
||||
int16_t tmp16, inv_std, inv_std2, exp_value = 0;
|
||||
int32_t tmp32;
|
||||
|
||||
// Calculate |inv_std| = 1 / s, in Q10.
|
||||
// 131072 = 1 in Q17, and (|std| >> 1) is for rounding instead of truncation.
|
||||
// Calculate `inv_std` = 1 / s, in Q10.
|
||||
// 131072 = 1 in Q17, and (`std` >> 1) is for rounding instead of truncation.
|
||||
// Q-domain: Q17 / Q7 = Q10.
|
||||
tmp32 = (int32_t) 131072 + (int32_t) (std >> 1);
|
||||
inv_std = (int16_t) WebRtcSpl_DivW32W16(tmp32, std);
|
||||
|
||||
// Calculate |inv_std2| = 1 / s^2, in Q14.
|
||||
// Calculate `inv_std2` = 1 / s^2, in Q14.
|
||||
tmp16 = (inv_std >> 2); // Q10 -> Q8.
|
||||
// Q-domain: (Q8 * Q8) >> 2 = Q14.
|
||||
inv_std2 = (int16_t)((tmp16 * tmp16) >> 2);
|
||||
@ -51,20 +51,20 @@ int32_t WebRtcVad_GaussianProbability(int16_t input,
|
||||
tmp16 = tmp16 - mean; // Q7 - Q7 = Q7
|
||||
|
||||
// To be used later, when updating noise/speech model.
|
||||
// |delta| = (x - m) / s^2, in Q11.
|
||||
// `delta` = (x - m) / s^2, in Q11.
|
||||
// Q-domain: (Q14 * Q7) >> 10 = Q11.
|
||||
*delta = (int16_t)((inv_std2 * tmp16) >> 10);
|
||||
|
||||
// Calculate the exponent |tmp32| = (x - m)^2 / (2 * s^2), in Q10. Replacing
|
||||
// Calculate the exponent `tmp32` = (x - m)^2 / (2 * s^2), in Q10. Replacing
|
||||
// division by two with one shift.
|
||||
// Q-domain: (Q11 * Q7) >> 8 = Q10.
|
||||
tmp32 = (*delta * tmp16) >> 9;
|
||||
|
||||
// If the exponent is small enough to give a non-zero probability we calculate
|
||||
// |exp_value| ~= exp(-(x - m)^2 / (2 * s^2))
|
||||
// ~= exp2(-log2(exp(1)) * |tmp32|).
|
||||
// `exp_value` ~= exp(-(x - m)^2 / (2 * s^2))
|
||||
// ~= exp2(-log2(exp(1)) * `tmp32`).
|
||||
if (tmp32 < kCompVar) {
|
||||
// Calculate |tmp16| = log2(exp(1)) * |tmp32|, in Q10.
|
||||
// Calculate `tmp16` = log2(exp(1)) * `tmp32`, in Q10.
|
||||
// Q-domain: (Q12 * Q10) >> 12 = Q10.
|
||||
tmp16 = (int16_t)((kLog2Exp * tmp32) >> 12);
|
||||
tmp16 = -tmp16;
|
||||
@ -72,7 +72,7 @@ int32_t WebRtcVad_GaussianProbability(int16_t input,
|
||||
tmp16 ^= 0xFFFF;
|
||||
tmp16 >>= 10;
|
||||
tmp16 += 1;
|
||||
// Get |exp_value| = exp(-|tmp32|) in Q10.
|
||||
// Get `exp_value` = exp(-`tmp32`) in Q10.
|
||||
exp_value >>= tmp16;
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,8 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// Calculates the probability for |input|, given that |input| comes from a
|
||||
// normal distribution with mean and standard deviation (|mean|, |std|).
|
||||
// Calculates the probability for `input`, given that `input` comes from a
|
||||
// normal distribution with mean and standard deviation (`mean`, `std`).
|
||||
//
|
||||
// Inputs:
|
||||
// - input : input sample in Q4.
|
||||
@ -26,11 +26,11 @@
|
||||
// Output:
|
||||
//
|
||||
// - delta : input used when updating the model, Q11.
|
||||
// |delta| = (|input| - |mean|) / |std|^2.
|
||||
// `delta` = (`input` - `mean`) / `std`^2.
|
||||
//
|
||||
// Return:
|
||||
// (probability for |input|) =
|
||||
// 1 / |std| * exp(-(|input| - |mean|)^2 / (2 * |std|^2));
|
||||
// (probability for `input`) =
|
||||
// 1 / `std` * exp(-(`input` - `mean`)^2 / (2 * `std`^2));
|
||||
int32_t WebRtcVad_GaussianProbability(int16_t input,
|
||||
int16_t mean,
|
||||
int16_t std,
|
||||
|
@ -52,7 +52,7 @@ void WebRtcVad_Downsampling(const int16_t* signal_in,
|
||||
filter_state[1] = tmp32_2;
|
||||
}
|
||||
|
||||
// Inserts |feature_value| into |low_value_vector|, if it is one of the 16
|
||||
// Inserts `feature_value` into `low_value_vector`, if it is one of the 16
|
||||
// smallest values the last 100 frames. Then calculates and returns the median
|
||||
// of the five smallest values.
|
||||
int16_t WebRtcVad_FindMinimum(VadInstT* self,
|
||||
@ -66,13 +66,13 @@ int16_t WebRtcVad_FindMinimum(VadInstT* self,
|
||||
int16_t alpha = 0;
|
||||
int32_t tmp32 = 0;
|
||||
// Pointer to memory for the 16 minimum values and the age of each value of
|
||||
// the |channel|.
|
||||
// the `channel`.
|
||||
int16_t* age = &self->index_vector[offset];
|
||||
int16_t* smallest_values = &self->low_value_vector[offset];
|
||||
|
||||
RTC_DCHECK_LT(channel, kNumChannels);
|
||||
|
||||
// Each value in |smallest_values| is getting 1 loop older. Update |age|, and
|
||||
// Each value in `smallest_values` is getting 1 loop older. Update `age`, and
|
||||
// remove old values.
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (age[i] != 100) {
|
||||
@ -88,9 +88,9 @@ int16_t WebRtcVad_FindMinimum(VadInstT* self,
|
||||
}
|
||||
}
|
||||
|
||||
// Check if |feature_value| is smaller than any of the values in
|
||||
// |smallest_values|. If so, find the |position| where to insert the new value
|
||||
// (|feature_value|).
|
||||
// Check if `feature_value` is smaller than any of the values in
|
||||
// `smallest_values`. If so, find the `position` where to insert the new value
|
||||
// (`feature_value`).
|
||||
if (feature_value < smallest_values[7]) {
|
||||
if (feature_value < smallest_values[3]) {
|
||||
if (feature_value < smallest_values[1]) {
|
||||
@ -152,7 +152,7 @@ int16_t WebRtcVad_FindMinimum(VadInstT* self,
|
||||
age[position] = 1;
|
||||
}
|
||||
|
||||
// Get |current_median|.
|
||||
// Get `current_median`.
|
||||
if (self->frame_counter > 2) {
|
||||
current_median = smallest_values[2];
|
||||
} else if (self->frame_counter > 0) {
|
||||
|
@ -23,11 +23,11 @@
|
||||
//
|
||||
// Input & Output:
|
||||
// - filter_state : Current filter states of the two all-pass filters. The
|
||||
// |filter_state| is updated after all samples have been
|
||||
// `filter_state` is updated after all samples have been
|
||||
// processed.
|
||||
//
|
||||
// Output:
|
||||
// - signal_out : Downsampled signal (of length |in_length| / 2).
|
||||
// - signal_out : Downsampled signal (of length `in_length` / 2).
|
||||
void WebRtcVad_Downsampling(const int16_t* signal_in,
|
||||
int16_t* signal_out,
|
||||
int32_t* filter_state,
|
||||
@ -35,7 +35,7 @@ void WebRtcVad_Downsampling(const int16_t* signal_in,
|
||||
|
||||
// Updates and returns the smoothed feature minimum. As minimum we use the
|
||||
// median of the five smallest feature values in a 100 frames long window.
|
||||
// As long as |handle->frame_counter| is zero, that is, we haven't received any
|
||||
// As long as `handle->frame_counter` is zero, that is, we haven't received any
|
||||
// "valid" data, FindMinimum() outputs the default value of 1600.
|
||||
//
|
||||
// Inputs:
|
||||
|
@ -21,7 +21,7 @@ static const int kValidRates[] = { 8000, 16000, 32000, 48000 };
|
||||
static const size_t kRatesSize = sizeof(kValidRates) / sizeof(*kValidRates);
|
||||
static const int kMaxFrameLengthMs = 30;
|
||||
|
||||
VadInst* WebRtcVad_Create() {
|
||||
VadInst* WebRtcVad_Create(void) {
|
||||
VadInstT* self = (VadInstT*)malloc(sizeof(VadInstT));
|
||||
|
||||
self->init_flag = 0;
|
||||
|
@ -65,7 +65,7 @@ constexpr size_t kMaxChunksize = 4096;
|
||||
|
||||
} // namespace
|
||||
|
||||
WavReader::WavReader(const std::string& filename)
|
||||
WavReader::WavReader(absl::string_view filename)
|
||||
: WavReader(FileWrapper::OpenReadOnly(filename)) {}
|
||||
|
||||
WavReader::WavReader(FileWrapper file) : file_(std::move(file)) {
|
||||
@ -178,7 +178,7 @@ void WavReader::Close() {
|
||||
file_.Close();
|
||||
}
|
||||
|
||||
WavWriter::WavWriter(const std::string& filename,
|
||||
WavWriter::WavWriter(absl::string_view filename,
|
||||
int sample_rate,
|
||||
size_t num_channels,
|
||||
SampleFormat sample_format)
|
||||
|
@ -39,7 +39,7 @@ class WavFile {
|
||||
class WavWriter final : public WavFile {
|
||||
public:
|
||||
// Opens a new WAV file for writing.
|
||||
WavWriter(const std::string& filename,
|
||||
WavWriter(absl::string_view filename,
|
||||
int sample_rate,
|
||||
size_t num_channels,
|
||||
SampleFormat sample_format = SampleFormat::kInt16);
|
||||
@ -77,7 +77,7 @@ class WavWriter final : public WavFile {
|
||||
class WavReader final : public WavFile {
|
||||
public:
|
||||
// Opens an existing WAV file for reading.
|
||||
explicit WavReader(const std::string& filename);
|
||||
explicit WavReader(absl::string_view filename);
|
||||
explicit WavReader(FileWrapper file);
|
||||
|
||||
// Close the WAV file.
|
||||
|
@ -80,8 +80,6 @@ const uint32_t kFmtIeeeFloatSubchunkSize =
|
||||
// read audio samples.
|
||||
#pragma pack(2)
|
||||
struct WavHeaderPcm {
|
||||
WavHeaderPcm(const WavHeaderPcm&) = default;
|
||||
WavHeaderPcm& operator=(const WavHeaderPcm&) = default;
|
||||
RiffHeader riff;
|
||||
FmtPcmSubchunk fmt;
|
||||
struct {
|
||||
@ -95,8 +93,6 @@ static_assert(sizeof(WavHeaderPcm) == kPcmWavHeaderSize,
|
||||
// WAV implementation.
|
||||
#pragma pack(2)
|
||||
struct WavHeaderIeeeFloat {
|
||||
WavHeaderIeeeFloat(const WavHeaderIeeeFloat&) = default;
|
||||
WavHeaderIeeeFloat& operator=(const WavHeaderIeeeFloat&) = default;
|
||||
RiffHeader riff;
|
||||
FmtIeeeFloatSubchunk fmt;
|
||||
struct {
|
||||
@ -132,7 +128,7 @@ uint16_t MapWavFormatToHeaderField(WavFormat format) {
|
||||
case WavFormat::kWavFormatMuLaw:
|
||||
return 7;
|
||||
}
|
||||
RTC_CHECK(false);
|
||||
RTC_CHECK_NOTREACHED();
|
||||
}
|
||||
|
||||
WavFormat MapHeaderFieldToWavFormat(uint16_t format_header_value) {
|
||||
@ -161,7 +157,7 @@ uint16_t BlockAlign(size_t num_channels, size_t bytes_per_sample) {
|
||||
return static_cast<uint16_t>(num_channels * bytes_per_sample);
|
||||
}
|
||||
|
||||
// Finds a chunk having the sought ID. If found, then |readable| points to the
|
||||
// Finds a chunk having the sought ID. If found, then `readable` points to the
|
||||
// first byte of the sought chunk data. If not found, the end of the file is
|
||||
// reached.
|
||||
bool FindWaveChunk(ChunkHeader* chunk_header,
|
||||
@ -278,10 +274,8 @@ size_t GetFormatBytesPerSample(WavFormat format) {
|
||||
return 1;
|
||||
case WavFormat::kWavFormatIeeeFloat:
|
||||
return 4;
|
||||
default:
|
||||
RTC_CHECK(false);
|
||||
return 2;
|
||||
}
|
||||
RTC_CHECK_NOTREACHED();
|
||||
}
|
||||
|
||||
bool CheckWavParameters(size_t num_channels,
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
|
Reference in New Issue
Block a user