Wayverb
fitted_boundary.h
1 #pragma once
2 
3 #include "waveguide/arbitrary_magnitude_filter.h"
4 #include "waveguide/cl/filter_structs.h"
5 #include "waveguide/filters.h"
6 #include "waveguide/stable.h"
7 
8 #include "core/cosine_interp.h"
9 #include "core/filter_coefficients.h"
10 #include "core/surfaces.h"
11 
12 #include "hrtf/multiband.h"
13 
14 #include "utilities/for_each.h"
15 #include "utilities/map.h"
16 
17 namespace wayverb {
18 namespace waveguide {
19 namespace detail {
20 template <size_t... Ix>
21 constexpr auto to_raw_impedance_coefficients(
22  const coefficients<sizeof...(Ix) - 1>& c, std::index_sequence<Ix...>) {
23  return coefficients_canonical{{c.a[Ix] + c.b[Ix]...},
24  {c.a[Ix] - c.b[Ix]...}};
25 }
26 
27 template <size_t order>
28 constexpr auto to_raw_impedance_coefficients(const coefficients<order>& c) {
29  return to_raw_impedance_coefficients(c,
30  std::make_index_sequence<order + 1>{});
31 }
32 } // namespace detail
33 
34 template <size_t order>
35 auto to_impedance_coefficients(const coefficients<order>& c) {
36  auto ret = detail::to_raw_impedance_coefficients(c);
37 
38  if (ret.a[0]) {
39  const auto norm = 1.0 / ret.a[0];
40  const auto do_normalize = [&](auto& i) {
41  util::for_each([&](auto& i) { i *= norm; }, i);
42  };
43  do_normalize(ret.b);
44  do_normalize(ret.a);
45  }
46 
47  return ret;
48 }
49 
51 
52 template <size_t... Ix>
53 constexpr auto make_coefficients_canonical(
54  const core::filter_coefficients<sizeof...(Ix) - 1, sizeof...(Ix) - 1>&
55  coeffs,
56  std::index_sequence<Ix...>) {
57  return coefficients_canonical{{std::get<Ix>(coeffs.b)...},
58  {std::get<Ix>(coeffs.a)...}};
59 }
60 
61 constexpr auto make_coefficients_canonical(
62  const core::filter_coefficients<coefficients_canonical::order,
63  coefficients_canonical::order>&
64  coeffs) {
65  return make_coefficients_canonical(
66  coeffs,
67  std::make_index_sequence<coefficients_canonical::order + 1>{});
68 }
69 
71 
72 inline auto to_flat_coefficients(double absorption) {
73  return to_impedance_coefficients(coefficients_canonical{
74  {core::absorption_to_pressure_reflectance(absorption)}, {1}});
75 }
76 
78 
79 template <typename T>
80 auto compute_reflectance_filter_coefficients(T&& absorption,
81  double sample_rate) {
82  const auto band_centres =
83  util::map([](auto i) { return i * 2; },
84  hrtf_data::hrtf_band_centres(sample_rate));
85  const auto reflectance = util::map(
86  [](double i) {
87  return core::absorption_to_pressure_reflectance(i);
88  },
89  absorption);
90 
91  constexpr auto lim = 1000;
92  for (auto delay = 0; delay != lim; ++delay) {
93  const auto reflectance_coeffs = make_coefficients_canonical(
94  arbitrary_magnitude_filter<coefficients_canonical::order>(
95  make_frequency_domain_envelope(band_centres,
96  reflectance)));
97 
98  if (is_stable(reflectance_coeffs.a)) {
99  return reflectance_coeffs;
100  }
101  }
102 
103  throw std::runtime_error{"Unable to generate stable boundary filter."};
104 }
105 
106 } // namespace waveguide
107 } // namespace wayverb
Definition: traits.h:46
Definition: capsule_base.h:9