Wayverb
postprocess.h
1 #pragma once
2 
3 #include "raytracer/postprocess.h"
4 
5 #include "waveguide/canonical.h"
6 #include "waveguide/config.h"
7 #include "waveguide/postprocess.h"
8 
9 #include "core/sinc.h"
10 #include "core/sum_ranges.h"
11 
12 #include "audio_file/audio_file.h"
13 
14 namespace wayverb {
15 namespace combined {
16 
17 template <typename Histogram>
18 struct combined_results final {
20  util::aligned::vector<waveguide::bandpass_band> waveguide;
21 };
22 
23 template <typename Histogram>
24 auto make_combined_results(
26  util::aligned::vector<waveguide::bandpass_band> waveguide) {
27  return combined_results<Histogram>{std::move(raytracer),
28  std::move(waveguide)};
29 }
30 
32 
33 template <typename LoIt, typename HiIt>
34 auto crossover_filter(LoIt b_lo,
35  LoIt e_lo,
36  HiIt b_hi,
37  HiIt e_hi,
38  double cutoff,
39  double width) {
41  frequency_domain::best_fft_length(std::max(
42  std::distance(b_lo, e_lo), std::distance(b_hi, e_hi)))
43  << 2};
44 
45  constexpr auto l = 0;
46 
47  const auto run_filter = [&](auto b, auto e, auto mag_func) {
48  auto ret = std::vector<float>(std::distance(b, e));
49  filt.run(b, e, begin(ret), [&](auto cplx, auto freq) {
50  return cplx * static_cast<float>(mag_func(freq, cutoff, width, l));
51  });
52  return ret;
53  };
54 
55  const auto lo =
56  run_filter(b_lo, e_lo, frequency_domain::compute_lopass_magnitude);
57  const auto hi =
58  run_filter(b_hi, e_hi, frequency_domain::compute_hipass_magnitude);
59 
60  return core::sum_vectors(lo, hi);
61 }
62 
64 
65 struct max_frequency_functor final {
66  template <typename T>
67  auto operator()(T&& t) const {
68  return t.valid_hz.get_max();
69  }
70 };
71 
72 template <typename Histogram, typename Method>
73 auto postprocess(const combined_results<Histogram>& input,
74  const Method& method,
75  const glm::vec3& source_position,
76  const glm::vec3& receiver_position,
77  double room_volume,
78  const core::environment& environment,
79  double output_sample_rate) {
80  // Individual processing.
81  const auto waveguide_processed =
82  waveguide::postprocess(input.waveguide,
83  method,
84  environment.acoustic_impedance,
85  output_sample_rate);
86 
87  const auto raytracer_processed = raytracer::postprocess(input.raytracer,
88  method,
89  receiver_position,
90  room_volume,
91  environment,
92  output_sample_rate);
93 
94  const auto make_iterator = [](auto it) {
95  return util::make_mapping_iterator_adapter(std::move(it),
97  };
98 
99  if (input.waveguide.empty()) {
100  return raytracer_processed;
101  }
102 
103  const auto cutoff = *std::max_element(make_iterator(begin(input.waveguide)),
104  make_iterator(end(input.waveguide))) /
105  output_sample_rate;
106  const auto width = 0.2; // Wider = more natural-sounding
107  auto filtered = crossover_filter(begin(waveguide_processed),
108  end(waveguide_processed),
109  begin(raytracer_processed),
110  end(raytracer_processed),
111  cutoff,
112  width);
113 
114  // Just in case the start has a bit of a dc offset, we do a sneaky window.
115  const auto window_length =
116  std::min(filtered.size(),
117  static_cast<size_t>(std::floor(
118  distance(source_position, receiver_position) *
119  output_sample_rate / environment.speed_of_sound)));
120 
121  if (window_length == 0) {
122  return filtered;
123  }
124 
125  const auto window = core::left_hanning(std::floor(window_length));
126 
127  // Multiply together the window and filtered signal.
128  std::transform(
129  begin(window),
130  end(window),
131  begin(filtered),
132  begin(filtered),
133  [](auto envelope, auto signal) { return envelope * signal; });
134 
135  return filtered;
136 }
137 
138 } // namespace combined
139 } // namespace wayverb
Structured this way so that I can keep all fftw linkage internal.
Definition: filter.h:12
Definition: postprocess.h:18
Definition: pressure.h:22
Definition: canonical.h:18
Definition: environment.h:6
Definition: capsule_base.h:9
Definition: postprocess.h:65