Optimizations and refactoring of the APM 3-band split filter
This CL refactors and optimizes the 3-band split-filter in APM, which
is a very computationally complex component.
Beyond optimizing the code, the filter coefficients are also quantized
to avoid denormals.
The changes reduces the complexity of the split filter by about 30-50%.
The CL has been tested for bitexactness on a number of aecdump
recordings.
(the CL also removes the now unused code for the sparse_fir_filter)
Bug: webrtc:6181
Change-Id: If45f8d1f189c6812ccb03721156c77eb68181211
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/168189
Reviewed-by: Sam Zackrisson <saza@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Commit-Queue: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30592}
diff --git a/common_audio/channel_buffer.h b/common_audio/channel_buffer.h
index dc44369..f027080 100644
--- a/common_audio/channel_buffer.h
+++ b/common_audio/channel_buffer.h
@@ -14,7 +14,9 @@
#include <string.h>
#include <memory>
+#include <vector>
+#include "api/array_view.h"
#include "common_audio/include/audio_util.h"
#include "rtc_base/checks.h"
#include "rtc_base/gtest_prod_util.h"
@@ -48,40 +50,60 @@
num_frames_per_band_(num_frames / num_bands),
num_allocated_channels_(num_channels),
num_channels_(num_channels),
- num_bands_(num_bands) {
- for (size_t i = 0; i < num_allocated_channels_; ++i) {
- for (size_t j = 0; j < num_bands_; ++j) {
- channels_[j * num_allocated_channels_ + i] =
- &data_[i * num_frames_ + j * num_frames_per_band_];
- bands_[i * num_bands_ + j] = channels_[j * num_allocated_channels_ + i];
+ num_bands_(num_bands),
+ bands_view_(num_allocated_channels_,
+ std::vector<rtc::ArrayView<T>>(num_bands_)),
+ channels_view_(
+ num_bands_,
+ std::vector<rtc::ArrayView<T>>(num_allocated_channels_)) {
+ // Temporarily cast away const_ness to allow populating the array views.
+ auto* bands_view =
+ const_cast<std::vector<std::vector<rtc::ArrayView<T>>>*>(&bands_view_);
+ auto* channels_view =
+ const_cast<std::vector<std::vector<rtc::ArrayView<T>>>*>(
+ &channels_view_);
+
+ for (size_t ch = 0; ch < num_allocated_channels_; ++ch) {
+ for (size_t band = 0; band < num_bands_; ++band) {
+ (*channels_view)[band][ch] = rtc::ArrayView<T>(
+ &data_[ch * num_frames_ + band * num_frames_per_band_],
+ num_frames_per_band_);
+ (*bands_view)[ch][band] = channels_view_[band][ch];
+ channels_[band * num_allocated_channels_ + ch] =
+ channels_view_[band][ch].data();
+ bands_[ch * num_bands_ + band] =
+ channels_[band * num_allocated_channels_ + ch];
}
}
}
- // Returns a pointer array to the full-band channels (or lower band channels).
- // Usage:
- // channels()[channel][sample].
- // Where:
- // 0 <= channel < |num_allocated_channels_|
- // 0 <= sample < |num_frames_|
- T* const* channels() { return channels(0); }
- const T* const* channels() const { return channels(0); }
-
- // Returns a pointer array to the channels for a specific band.
- // Usage:
- // channels(band)[channel][sample].
+ // Returns a pointer array to the channels.
+ // 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_|
- const T* const* channels(size_t band) const {
+
+ // 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_|
+ const T* const* channels(size_t band = 0) const {
RTC_DCHECK_LT(band, num_bands_);
return &channels_[band * num_allocated_channels_];
}
- T* const* channels(size_t band) {
+ T* const* channels(size_t band = 0) {
const ChannelBuffer<T>* t = this;
return const_cast<T* const*>(t->channels(band));
}
+ rtc::ArrayView<const rtc::ArrayView<T>> channels_view(size_t band = 0) {
+ return channels_view_[band];
+ }
+ rtc::ArrayView<const rtc::ArrayView<T>> channels_view(size_t band = 0) const {
+ return channels_view_[band];
+ }
// Returns a pointer array to the bands for a specific channel.
// Usage:
@@ -100,6 +122,13 @@
return const_cast<T* const*>(t->bands(channel));
}
+ rtc::ArrayView<const rtc::ArrayView<T>> bands_view(size_t channel) {
+ return bands_view_[channel];
+ }
+ rtc::ArrayView<const rtc::ArrayView<T>> bands_view(size_t channel) const {
+ return bands_view_[channel];
+ }
+
// 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 {
@@ -140,6 +169,8 @@
// Number of channels the user sees.
size_t num_channels_;
const size_t num_bands_;
+ const std::vector<std::vector<rtc::ArrayView<T>>> bands_view_;
+ const std::vector<std::vector<rtc::ArrayView<T>>> channels_view_;
};
// One int16_t and one float ChannelBuffer that are kept in sync. The sync is