1 /*
2  *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 #include "modules/audio_processing/utility/cascaded_biquad_filter.h"
11 
12 #include <algorithm>
13 
14 #include "rtc_base/checks.h"
15 
16 namespace webrtc {
17 
BiQuadParam(std::complex<float> zero,std::complex<float> pole,float gain,bool mirror_zero_along_i_axis)18 CascadedBiQuadFilter::BiQuadParam::BiQuadParam(std::complex<float> zero,
19                                                std::complex<float> pole,
20                                                float gain,
21                                                bool mirror_zero_along_i_axis)
22     : zero(zero),
23       pole(pole),
24       gain(gain),
25       mirror_zero_along_i_axis(mirror_zero_along_i_axis) {}
26 
27 CascadedBiQuadFilter::BiQuadParam::BiQuadParam(const BiQuadParam&) = default;
28 
BiQuad(const CascadedBiQuadFilter::BiQuadParam & param)29 CascadedBiQuadFilter::BiQuad::BiQuad(
30     const CascadedBiQuadFilter::BiQuadParam& param)
31     : x(), y() {
32   float z_r = std::real(param.zero);
33   float z_i = std::imag(param.zero);
34   float p_r = std::real(param.pole);
35   float p_i = std::imag(param.pole);
36   float gain = param.gain;
37 
38   if (param.mirror_zero_along_i_axis) {
39     // Assuming zeroes at z_r and -z_r.
40     RTC_DCHECK(z_i == 0.f);
41     coefficients.b[0] = gain * 1.f;
42     coefficients.b[1] = 0.f;
43     coefficients.b[2] = gain * -(z_r * z_r);
44   } else {
45     // Assuming zeros at (z_r + z_i*i) and (z_r - z_i*i).
46     coefficients.b[0] = gain * 1.f;
47     coefficients.b[1] = gain * -2.f * z_r;
48     coefficients.b[2] = gain * (z_r * z_r + z_i * z_i);
49   }
50 
51   // Assuming poles at (p_r + p_i*i) and (p_r - p_i*i).
52   coefficients.a[0] = -2.f * p_r;
53   coefficients.a[1] = p_r * p_r + p_i * p_i;
54 }
55 
Reset()56 void CascadedBiQuadFilter::BiQuad::BiQuad::Reset() {
57   x[0] = x[1] = y[0] = y[1] = 0.f;
58 }
59 
CascadedBiQuadFilter(const CascadedBiQuadFilter::BiQuadCoefficients & coefficients,size_t num_biquads)60 CascadedBiQuadFilter::CascadedBiQuadFilter(
61     const CascadedBiQuadFilter::BiQuadCoefficients& coefficients,
62     size_t num_biquads)
63     : biquads_(num_biquads, BiQuad(coefficients)) {}
64 
CascadedBiQuadFilter(const std::vector<CascadedBiQuadFilter::BiQuadParam> & biquad_params)65 CascadedBiQuadFilter::CascadedBiQuadFilter(
66     const std::vector<CascadedBiQuadFilter::BiQuadParam>& biquad_params) {
67   for (const auto& param : biquad_params) {
68     biquads_.push_back(BiQuad(param));
69   }
70 }
71 
72 CascadedBiQuadFilter::~CascadedBiQuadFilter() = default;
73 
Process(rtc::ArrayView<const float> x,rtc::ArrayView<float> y)74 void CascadedBiQuadFilter::Process(rtc::ArrayView<const float> x,
75                                    rtc::ArrayView<float> y) {
76   if (biquads_.size() > 0) {
77     ApplyBiQuad(x, y, &biquads_[0]);
78     for (size_t k = 1; k < biquads_.size(); ++k) {
79       ApplyBiQuad(y, y, &biquads_[k]);
80     }
81   } else {
82     std::copy(x.begin(), x.end(), y.begin());
83   }
84 }
85 
Process(rtc::ArrayView<float> y)86 void CascadedBiQuadFilter::Process(rtc::ArrayView<float> y) {
87   for (auto& biquad : biquads_) {
88     ApplyBiQuad(y, y, &biquad);
89   }
90 }
91 
Reset()92 void CascadedBiQuadFilter::Reset() {
93   for (auto& biquad : biquads_) {
94     biquad.Reset();
95   }
96 }
97 
ApplyBiQuad(rtc::ArrayView<const float> x,rtc::ArrayView<float> y,CascadedBiQuadFilter::BiQuad * biquad)98 void CascadedBiQuadFilter::ApplyBiQuad(rtc::ArrayView<const float> x,
99                                        rtc::ArrayView<float> y,
100                                        CascadedBiQuadFilter::BiQuad* biquad) {
101   RTC_DCHECK_EQ(x.size(), y.size());
102   const auto* c_b = biquad->coefficients.b;
103   const auto* c_a = biquad->coefficients.a;
104   auto* m_x = biquad->x;
105   auto* m_y = biquad->y;
106   for (size_t k = 0; k < x.size(); ++k) {
107     const float tmp = x[k];
108     y[k] = c_b[0] * tmp + c_b[1] * m_x[0] + c_b[2] * m_x[1] - c_a[0] * m_y[0] -
109            c_a[1] * m_y[1];
110     m_x[1] = m_x[0];
111     m_x[0] = tmp;
112     m_y[1] = m_y[0];
113     m_y[0] = y[k];
114   }
115 }
116 
117 }  // namespace webrtc
118