chromium/third_party/webrtc/modules/audio_processing/three_band_filter_bank.cc

/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

// An implementation of a 3-band FIR filter-bank with DCT modulation, similar to
// the proposed in "Multirate Signal Processing for Communication Systems" by
// Fredric J Harris.
//
// The idea is to take a heterodyne system and change the order of the
// components to get something which is efficient to implement digitally.
//
// It is possible to separate the filter using the noble identity as follows:
//
// H(z) = H0(z^3) + z^-1 * H1(z^3) + z^-2 * H2(z^3)
//
// This is used in the analysis stage to first downsample serial to parallel
// and then filter each branch with one of these polyphase decompositions of the
// lowpass prototype. Because each filter is only a modulation of the prototype,
// it is enough to multiply each coefficient by the respective cosine value to
// shift it to the desired band. But because the cosine period is 12 samples,
// it requires separating the prototype even further using the noble identity.
// After filtering and modulating for each band, the output of all filters is
// accumulated to get the downsampled bands.
//
// A similar logic can be applied to the synthesis stage.

#include "modules/audio_processing/three_band_filter_bank.h"

#include <array>

#include "rtc_base/checks.h"

namespace webrtc {
namespace {

// Factors to take into account when choosing `kFilterSize`:
//   1. Higher `kFilterSize`, means faster transition, which ensures less
//      aliasing. This is especially important when there is non-linear
//      processing between the splitting and merging.
//   2. The delay that this filter bank introduces is
//      `kNumBands` * `kSparsity` * `kFilterSize` / 2, so it increases linearly
//      with `kFilterSize`.
//   3. The computation complexity also increases linearly with `kFilterSize`.

// The Matlab code to generate these `kFilterCoeffs` is:
//
// N = kNumBands * kSparsity * kFilterSize - 1;
// h = fir1(N, 1 / (2 * kNumBands), kaiser(N + 1, 3.5));
// reshape(h, kNumBands * kSparsity, kFilterSize);
//
// The code below uses the values of kFilterSize, kNumBands and kSparsity
// specified in the header.

// Because the total bandwidth of the lower and higher band is double the middle
// one (because of the spectrum parity), the low-pass prototype is half the
// bandwidth of 1 / (2 * `kNumBands`) and is then shifted with cosine modulation
// to the right places.
// A Kaiser window is used because of its flexibility and the alpha is set to
// 3.5, since that sets a stop band attenuation of 40dB ensuring a fast
// transition.

constexpr int kSubSampling =;
constexpr int kDctSize =;
static_assert;

const float
    kFilterCoeffs[ThreeBandFilterBank::kNumNonZeroFilters][kFilterSize] =;

constexpr int kZeroFilterIndex1 =;
constexpr int kZeroFilterIndex2 =;

const float kDctModulation[ThreeBandFilterBank::kNumNonZeroFilters][kDctSize] =;

// Filters the input signal `in` with the filter `filter` using a shift by
// `in_shift`, taking into account the previous state.
void FilterCore(
    rtc::ArrayView<const float, kFilterSize> filter,
    rtc::ArrayView<const float, ThreeBandFilterBank::kSplitBandSize> in,
    const int in_shift,
    rtc::ArrayView<float, ThreeBandFilterBank::kSplitBandSize> out,
    rtc::ArrayView<float, kMemorySize> state) {}

}  // namespace

// Because the low-pass filter prototype has half bandwidth it is possible to
// use a DCT to shift it in both directions at the same time, to the center
// frequencies [1 / 12, 3 / 12, 5 / 12].
ThreeBandFilterBank::ThreeBandFilterBank() {}

ThreeBandFilterBank::~ThreeBandFilterBank() = default;

// The analysis can be separated in these steps:
//   1. Serial to parallel downsampling by a factor of `kNumBands`.
//   2. Filtering of `kSparsity` different delayed signals with polyphase
//      decomposition of the low-pass prototype filter and upsampled by a factor
//      of `kSparsity`.
//   3. Modulating with cosines and accumulating to get the desired band.
void ThreeBandFilterBank::Analysis(
    rtc::ArrayView<const float, kFullBandSize> in,
    rtc::ArrayView<const rtc::ArrayView<float>, ThreeBandFilterBank::kNumBands>
        out) {}

// The synthesis can be separated in these steps:
//   1. Modulating with cosines.
//   2. Filtering each one with a polyphase decomposition of the low-pass
//      prototype filter upsampled by a factor of `kSparsity` and accumulating
//      `kSparsity` signals with different delays.
//   3. Parallel to serial upsampling by a factor of `kNumBands`.
void ThreeBandFilterBank::Synthesis(
    rtc::ArrayView<const rtc::ArrayView<float>, ThreeBandFilterBank::kNumBands>
        in,
    rtc::ArrayView<float, kFullBandSize> out) {}

}  // namespace webrtc