Wayverb
postprocessing.h
1 #pragma once
2 
3 #include "core/attenuator/null.h"
4 #include "core/cl/iterator.h"
5 #include "core/cl/scene_structs.h"
6 #include "core/mixdown.h"
7 #include "core/vector_look_up_table.h"
8 
9 #include "hrtf/multiband.h"
10 
11 #include "utilities/aligned/vector.h"
12 
13 #include <array>
14 #include <cmath>
15 #include <random>
16 
17 namespace wayverb {
18 namespace raytracer {
19 namespace stochastic {
20 
21 template <typename T, size_t... Ix>
22 constexpr auto array_to_bands_type(const std::array<T, 8>& t,
23  std::index_sequence<Ix...>) {
24  return core::bands_type{{static_cast<float>(t[Ix])...}};
25 }
26 
27 template <typename T>
28 constexpr auto array_to_bands_type(const std::array<T, 8>& t) {
29  return array_to_bands_type(t, std::make_index_sequence<8>{});
30 }
31 
33 
34 double constant_mean_event_occurrence(double speed_of_sound,
35  double room_volume);
36 double mean_event_occurrence(double constant, double t);
37 
38 template <typename Engine>
39 auto interval_size(Engine& engine, double mean_occurrence) {
40  // Parameters are this way round to preserve the half-open range in the
41  // correct direction.
42  std::uniform_real_distribution<double> distribution{1.0, 0.0};
43  return std::log(1.0 / distribution(engine)) / mean_occurrence;
44 }
45 
46 double t0(double constant);
47 
48 struct dirac_sequence final {
49  util::aligned::vector<float> sequence;
50  double sample_rate;
51 };
52 
53 dirac_sequence generate_dirac_sequence(double speed_of_sound,
54  double room_volume,
55  double sample_rate,
56  double max_time);
57 
58 struct energy_histogram final {
59  double sample_rate;
60  util::aligned::vector<core::bands_type> histogram;
61 };
62 
63 template <typename T>
64 void sum_vectors(T& a, const T& b) {
65  a.resize(std::max(a.size(), b.size()));
66  auto i = begin(a);
67  for (auto j = begin(b), e = end(b); j != e; ++i, ++j) {
68  *i += *j;
69  }
70 }
71 
72 void sum_histograms(energy_histogram& a, const energy_histogram& b);
73 
74 template <size_t Az, size_t El>
76  double sample_rate;
78  histogram;
79 };
80 
81 template <size_t Az, size_t El>
82 void sum_histograms(directional_energy_histogram<Az, El>& a,
84  for (auto i = 0; i != Az; ++i) {
85  for (auto j = 0; j != El; ++j) {
86  sum_vectors(a.histogram.table[i][j], b.histogram.table[i][j]);
87  }
88  }
89  a.sample_rate = b.sample_rate;
90 }
91 
92 template <size_t Az, size_t El>
93 auto max_size(const core::vector_look_up_table<
94  util::aligned::vector<core::bands_type>,
95  Az,
96  El>& hist) {
97  size_t ret = 0;
98 
99  for (size_t a = 0; a != Az; ++a) {
100  for (size_t e = 0; e != El; ++e) {
101  ret = std::max(ret, hist.table[a][e].size());
102  }
103  }
104 
105  return ret;
106 }
107 
108 template <size_t Az, size_t El>
109 auto max_time(const directional_energy_histogram<Az, El>& hist) {
110  return max_size(hist.histogram) / hist.sample_rate;
111 }
112 
113 template <size_t Az, size_t El>
114 auto sum_directional_histogram(
115  const directional_energy_histogram<Az, El>& histogram) {
116  util::aligned::vector<core::bands_type> ret;
117  for (auto azimuth_index = 0ul; azimuth_index != Az; ++azimuth_index) {
118  for (auto elevation_index = 0ul; elevation_index != El;
119  ++elevation_index) {
120  const auto& segment =
121  histogram.histogram.table[azimuth_index][elevation_index];
122  ret.resize(std::max(ret.size(), segment.size()));
123  for (auto i = 0ul, end = segment.size(); i != end; ++i) {
124  ret[i] += segment[i];
125  }
126  }
127  }
128 
129  return energy_histogram{histogram.sample_rate, ret};
130 }
131 
132 template <typename Method>
133 auto compute_summed_histogram(const energy_histogram& histogram,
134  const Method&) {
135  return histogram;
136 }
137 
138 // Special case for the null attenuator.
139 template <size_t Az, size_t El>
140 auto compute_summed_histogram(
141  const directional_energy_histogram<Az, El>& histogram,
142  const core::attenuator::null& method) {
143  return sum_directional_histogram(histogram);
144 }
145 
146 template <size_t Az, size_t El, typename Method>
147 auto compute_summed_histogram(
148  const directional_energy_histogram<Az, El>& histogram,
149  const Method& method) {
150  using hist = std::decay_t<decltype(histogram.histogram)>;
151 
152  util::aligned::vector<core::bands_type> ret;
153 
154  for (auto azimuth_index = 0ul; azimuth_index != Az; ++azimuth_index) {
155  for (auto elevation_index = 0ul; elevation_index != El;
156  ++elevation_index) {
157  // This is the direction that the histogram segment is pointing,
158  // in world space.
159  const auto pointing = hist::pointing(
160  typename hist::index_pair{azimuth_index, elevation_index});
161 
162  // This is the attenuation of the receiver in that direction.
163  // We're dealing in energies, so we square the directional
164  // response.
165  const auto att = attenuation(method, pointing);
166  const auto factor = att * att;
167 
168  const auto& segment =
169  histogram.histogram.table[azimuth_index][elevation_index];
170 
171  // Ensure that the return vector is large enough.
172  ret.resize(std::max(ret.size(), segment.size()));
173 
174  // For each histogram bin in this segment, attenuate it
175  // appropriately and add it to the return vector.
176  for (auto i = 0ul, end = segment.size(); i != end; ++i) {
177  ret[i] += segment[i] * factor;
178  }
179  }
180  }
181 
182  return energy_histogram{histogram.sample_rate, ret};
183 }
184 
185 util::aligned::vector<core::bands_type> weight_sequence(
186  const energy_histogram& histogram,
187  const dirac_sequence& sequence,
188  double acoustic_impedance);
189 
190 util::aligned::vector<float> postprocessing(const energy_histogram& histogram,
191  const dirac_sequence& sequence,
192  double acoustic_impedance);
193 
194 template <size_t Az, size_t El, typename Method>
195 util::aligned::vector<float> postprocessing(
196  const directional_energy_histogram<Az, El>& histogram,
197  const Method& method,
198  const dirac_sequence& sequence,
199  double acoustic_impedance) {
200  const auto summed = compute_summed_histogram(histogram, method);
201  return postprocessing(summed, sequence, acoustic_impedance);
202 }
203 
204 } // namespace stochastic
205 } // namespace raytracer
206 } // namespace wayverb
Definition: postprocessing.h:48
Definition: pressure.h:22
Definition: capsule_base.h:9
Definition: vector_look_up_table.h:26