Wayverb
reverb_time.h
1 #pragma once
2 
3 #include "core/geo/triangle_vec.h"
4 #include "core/scene_data.h"
5 
6 #include "utilities/aligned/set.h"
7 
8 namespace wayverb {
9 namespace core {
10 
20 
22 template <typename Vertex, typename Surface>
23 double area(const generic_scene_data<Vertex, Surface>& scene,
24  size_t surface_index) {
25  // TODO this is dumb because of the linear search.
26  // If this becomes a bottleneck, maybe scene_data could store surfaces
27  // pre-sorted by material.
28  return std::accumulate(
29  begin(scene.get_triangles()),
30  end(scene.get_triangles()),
31  0.0,
32  [&](auto running_total, auto tri) {
33  return running_total +
34  (tri.surface == surface_index
35  ? geo::area(geo::get_triangle_vec3(
36  tri, scene.get_vertices().data()))
37  : 0.0);
38  });
39 }
40 
42 template <typename Vertex, typename Surface>
43 double area(const generic_scene_data<Vertex, Surface>& scene) {
44  // This is OK - we have to look at every triangle anyway.
45  return std::accumulate(
46  begin(scene.get_triangles()),
47  end(scene.get_triangles()),
48  0.0,
49  [&](auto running_total, auto tri) {
50  return running_total +
51  geo::area(geo::get_triangle_vec3(
52  tri, scene.get_vertices().data()));
53  });
54 }
55 
58 template <typename Vertex, typename Surface>
59 auto absorption_area(const generic_scene_data<Vertex, Surface>& scene,
60  size_t surface_index) {
61  return scene.get_surfaces()[surface_index].absorption *
62  area(scene, surface_index);
63 }
64 
66 template <typename Vertex, typename Surface>
67 auto equivalent_absorption_area(
68  const generic_scene_data<Vertex, Surface>& scene) {
69  const auto num_surfaces = scene.get_surfaces().size();
70  decltype(absorption_area(scene, 0)) running_total{};
71  for (auto i = 0u; i != num_surfaces; ++i) {
72  running_total += absorption_area(scene, i);
73  }
74  return running_total;
75 }
76 
78 
79 std::array<std::pair<cl_uint, cl_uint>, 3> get_index_pairs(const triangle& t);
80 
82 template <typename It>
83 bool triangles_are_oriented(It begin, It end) {
84  // The scene is consistently oriented if no triangles in the scene share
85  // an edge with the same winding direction.
86  util::aligned::set<std::pair<cl_uint, cl_uint>> table;
87 
88  // For each triangle.
89  for (; begin != end; ++begin) {
90  // For each pair of vertices.
91  for (const auto& pair : get_index_pairs(*begin)) {
92  // See whether this pair of vertices has already been found.
93  if (!table.insert(pair).second) {
94  // The pair already existed.
95  return false;
96  }
97  }
98  }
99  // No triangles share a pair of vertices.
100  return true;
101 }
102 
103 float six_times_tetrahedron_volume(const geo::triangle_vec3& t);
104 
106 template <typename Vertex, typename Surface>
107 float estimate_room_volume(const generic_scene_data<Vertex, Surface>& scene) {
108  return std::abs(std::accumulate(
109  begin(scene.get_triangles()),
110  end(scene.get_triangles()),
111  0.0f,
112  [&](auto running_total, auto tri) {
113  return running_total +
114  six_times_tetrahedron_volume(
115  geo::get_triangle_vec3(
116  tri,
117  scene.get_vertices().data()));
118  })) /
119  6;
120 }
121 
123 
125 float estimate_air_intensity_absorption(float frequency, float humidity);
126 
127 template <size_t... Ix>
128 auto estimate_air_intensity_absorption(
129  const std::array<float, sizeof...(Ix)>& band_centres,
130  float humidity,
131  std::index_sequence<Ix...>) {
132  return std::array<float, sizeof...(Ix)>{{estimate_air_intensity_absorption(
133  std::get<Ix>(band_centres), humidity)...}};
134 }
135 
136 template <size_t Bands>
137 auto estimate_air_intensity_absorption(
138  const std::array<float, Bands>& band_centres, float humidity) {
139  return estimate_air_intensity_absorption(
140  band_centres, humidity, std::make_index_sequence<Bands>{});
141 }
142 
144 
145 // USE THESE ONES
146 
147 template <typename Absorption, typename Coeff>
148 auto sabine_reverb_time(double room_volume,
149  Absorption absorption_area,
150  Coeff air_coefficient) {
151  if (room_volume <= 0) {
152  throw std::runtime_error{"Room volume is non-positive"};
153  }
154  if (any(absorption_area <= 0)) {
155  throw std::runtime_error{"Absorption area is non-positive"};
156  }
157 
158  const auto numerator = 0.161f * room_volume;
159  const auto denominator =
160  absorption_area + (4 * room_volume * air_coefficient);
161  return numerator / denominator;
162 }
163 
166 template <typename Vertex, typename Surface, typename Coeff>
167 auto sabine_reverb_time(const generic_scene_data<Vertex, Surface>& scene,
168  Coeff air_coefficient) {
169  return sabine_reverb_time(estimate_room_volume(scene),
170  equivalent_absorption_area(scene),
171  air_coefficient);
172 }
173 
174 template <typename Absorption, typename Coeff>
175 auto eyring_reverb_time(double room_volume,
176  Absorption absorption_area,
177  double full_area,
178  Coeff air_coefficient) {
179  if (room_volume <= 0) {
180  throw std::runtime_error{"Room volume is non-positive"};
181  }
182  if (any(absorption_area <= 0)) {
183  throw std::runtime_error{"Absorption area is non-positive"};
184  }
185 
186  const auto numerator = 0.161f * room_volume;
187  const auto denominator =
188  -full_area * log(1 - (absorption_area / full_area)) +
189  (4 * room_volume * air_coefficient);
190  return numerator / denominator;
191 }
192 
194 template <typename Vertex, typename Surface, typename Coeff>
195 auto eyring_reverb_time(const generic_scene_data<Vertex, Surface>& scene,
196  Coeff air_coefficient) {
197  return eyring_reverb_time(estimate_room_volume(scene),
198  equivalent_absorption_area(scene),
199  area(scene),
200  air_coefficient);
201 }
202 
203 } // namespace core
204 } // namespace wayverb
Definition: traits.cpp:2
Definition: capsule_base.h:9