Wayverb
filters_common.h
1 #pragma once
2 
3 #include "frequency_domain/convolver.h"
4 #include "frequency_domain/filter.h"
5 
6 #include "utilities/aligned/vector.h"
7 
8 #include <algorithm>
9 #include <array>
10 #include <cmath>
11 #include <cstring>
12 #include <memory>
13 #include <vector>
14 
15 namespace wayverb {
16 namespace core {
17 namespace filter {
18 
19 using convolver = frequency_domain::convolver;
20 
21 class lopass_windowed_sinc final {
22 public:
23  explicit lopass_windowed_sinc(int inputLength);
24 
26  template <typename It>
27  util::aligned::vector<float> filter(It begin, It end) {
28  return convolver_.convolve(
29  std::begin(kernel_), std::end(kernel_), begin, end);
30  }
31 
32  void set_params(double co, double s);
33 
34 private:
35  static constexpr size_t KERNEL_LENGTH{99};
36  convolver convolver_;
37  std::array<float, KERNEL_LENGTH> kernel_;
38 };
39 
41 class hipass_windowed_sinc final {
42 public:
43  explicit hipass_windowed_sinc(int inputLength);
44 
46  template <typename It>
47  util::aligned::vector<float> filter(It begin, It end) {
48  return convolver_.convolve(
49  std::begin(kernel_), std::end(kernel_), begin, end);
50  }
51 
52  void set_params(double co, double s);
53 
54 private:
55  static constexpr size_t KERNEL_LENGTH{99};
56  convolver convolver_;
57  std::array<float, KERNEL_LENGTH> kernel_;
58 };
59 
62 public:
63  explicit bandpass_windowed_sinc(int inputLength);
64 
66  template <typename It>
67  util::aligned::vector<float> filter(It begin, It end) {
68  return convolver_.convolve(
69  std::begin(kernel_), std::end(kernel_), begin, end);
70  }
71 
72  void set_params(double l, double h, double s);
73 
74 private:
75  static constexpr size_t KERNEL_LENGTH{99};
76  convolver convolver_;
77  std::array<float, KERNEL_LENGTH> kernel_;
78 };
79 
81 
88 
91 
92 class biquad final {
93 public:
94  struct coefficients final {
95  double b0{0}, b1{0}, b2{0}, a1{0}, a2{0};
96  };
97 
98  constexpr biquad(const coefficients& coefficients)
99  : coefficients_{coefficients} {}
100 
102  constexpr double filter(double i) {
103  const auto out = i * coefficients_.b0 + z1_;
104  z1_ = i * coefficients_.b1 - coefficients_.a1 * out + z2_;
105  z2_ = i * coefficients_.b2 - coefficients_.a2 * out;
106  return out;
107  }
108 
110  constexpr void clear() { z1_ = z2_ = 0; }
111 
112 private:
113  coefficients coefficients_;
114  double z1_{0}, z2_{0};
115 };
116 
118 
119 biquad::coefficients compute_bandpass_biquad_coefficients(double lo,
120  double hi,
121  double sr);
122 biquad::coefficients compute_linkwitz_riley_lopass_coefficients(double cutoff,
123  double sr);
124 biquad::coefficients compute_linkwitz_riley_hipass_coefficients(double cutoff,
125  double sr);
126 biquad::coefficients compute_dc_blocker_coefficients(double a = 0.995);
127 
129 
130 template <typename Filter, typename It>
131 void run_one_pass(Filter& filter, It begin, It end) {
132  filter.clear();
133  for (; begin != end; ++begin) {
134  *begin = filter.filter(*begin);
135  }
136 }
137 
140 template <typename Filter, typename It>
141 void run_two_pass(Filter& filter, It begin, It end) {
142  run_one_pass(filter, begin, end);
143  run_one_pass(filter,
144  std::make_reverse_iterator(end),
145  std::make_reverse_iterator(begin));
146 }
147 
149 
150 template <typename It>
151 void linkwitz_riley_bandpass(double lo, double hi, double s, It begin, It end) {
152  biquad lopass{compute_linkwitz_riley_lopass_coefficients(hi, s)};
153  run_two_pass(lopass, begin, end);
154  biquad hipass{compute_linkwitz_riley_hipass_coefficients(lo, s)};
155  run_two_pass(hipass, begin, end);
156 }
157 
159 
160 template <size_t... i>
161 constexpr auto make_biquads(
162  const std::array<biquad::coefficients, sizeof...(i)>& coefficients,
163  std::index_sequence<i...>) {
164  return std::array<biquad, sizeof...(i)>{{biquad{coefficients[i]}...}};
165 }
166 
167 template <size_t num>
168 constexpr auto make_biquads(
169  const std::array<biquad::coefficients, num>& coefficients) {
170  return make_biquads(coefficients, std::make_index_sequence<num>{});
171 }
172 
174 template <size_t num>
175 class series_biquads final {
176 public:
177  static constexpr auto num_biquads = num;
178  static constexpr auto order = num_biquads * 2;
179 
180  constexpr series_biquads(
181  const std::array<biquad::coefficients, num_biquads>& coefficients)
182  : biquads_{make_biquads(coefficients)} {}
183 
184  constexpr double filter(double i) {
185  for (auto& biquad : biquads_) {
186  i = biquad.filter(i);
187  }
188  return i;
189  }
190 
191  constexpr void clear() {
192  for (auto& biquad : biquads_) {
193  biquad.clear();
194  }
195  }
196 
197 private:
198  std::array<biquad, num_biquads> biquads_;
199 };
200 
201 template <size_t num>
202 constexpr auto make_series_biquads(
203  const std::array<biquad::coefficients, num>& coefficients) {
204  return series_biquads<num>{coefficients};
205 }
206 
208 
209 biquad::coefficients compute_lopass_butterworth_segment(double cf,
210  size_t order,
211  size_t segment);
212 
213 biquad::coefficients compute_hipass_butterworth_segment(double cf,
214  size_t order,
215  size_t segment);
216 
217 template <typename Callback, size_t... i>
218 auto compute_butterworth_segments(double cf,
219  Callback callback,
220  std::index_sequence<i...>) {
221  const auto order = sizeof...(i) * 2;
222  return std::array<biquad::coefficients, sizeof...(i)>{
223  {callback(cf, order, i)...}};
224 }
225 
226 template <size_t num, typename Callback>
227 auto compute_butterworth_coefficients(double cutoff,
228  double sr,
229  Callback callback) {
230  return compute_butterworth_segments(std::tan(M_PI * cutoff / sr),
231  callback,
232  std::make_index_sequence<num>{});
233 }
234 
235 template <size_t num>
236 auto compute_hipass_butterworth_coefficients(double cutoff, double sr) {
237  return compute_butterworth_coefficients<num>(
238  cutoff, sr, compute_hipass_butterworth_segment);
239 }
240 
241 template <size_t num>
242 auto compute_lopass_butterworth_coefficients(double cutoff, double sr) {
243  return compute_butterworth_coefficients<num>(
244  cutoff, sr, compute_lopass_butterworth_segment);
245 }
246 
247 template <typename IIR>
248 util::aligned::vector<float> impulse_response(IIR& filt, size_t steps) {
249  util::aligned::vector<float> ret(steps, 0.0f);
250  ret.front() = 1;
251  run_one_pass(filt, ret.begin(), ret.end());
252  return ret;
253 }
254 
255 } // namespace filter
256 } // namespace core
257 } // namespace wayverb
constexpr void clear()
Resets delay lines, does not affect filter coefficients.
Definition: filters_common.h:110
Definition: convolver.h:11
Definition: traits.cpp:2
util::aligned::vector< float > filter(It begin, It end)
Filter a vector of data.
Definition: filters_common.h:67
An interesting windowed-sinc bandpass filter.
Definition: filters_common.h:61
Definition: filters_common.h:94
util::aligned::vector< float > filter(It begin, It end)
Filter a vector of data.
Definition: filters_common.h:27
constexpr double filter(double i)
Run the filter for one step.
Definition: filters_common.h:102
Definition: filters_common.h:92
Adheres to the IIR filter concept.
Definition: filters_common.h:175
Definition: capsule_base.h:9
util::aligned::vector< float > filter(It begin, It end)
Filter a vector of data.
Definition: filters_common.h:47
Definition: filters_common.h:21
An interesting windowed-sinc hipass filter.
Definition: filters_common.h:41