Wayverb
canonical.h
1 #pragma once
2 
3 #include "waveguide/bandpass_band.h"
4 #include "waveguide/calibration.h"
5 #include "waveguide/fitted_boundary.h"
6 #include "waveguide/postprocessor/directional_receiver.h"
7 #include "waveguide/preprocessor/hard_source.h"
8 #include "waveguide/simulation_parameters.h"
9 #include "waveguide/waveguide.h"
10 
11 #include "core/callback_accumulator.h"
12 #include "core/environment.h"
13 #include "core/reverb_time.h"
14 
15 #include "hrtf/multiband.h"
16 
17 #include <cmath>
18 
24 
25 namespace wayverb {
26 namespace waveguide {
27 namespace detail {
28 
29 template <typename Callback>
30 std::experimental::optional<band> canonical_impl(
31  const core::compute_context& cc,
32  const mesh& mesh,
33  double simulation_time,
34  const glm::vec3& source,
35  const glm::vec3& receiver,
36  const core::environment& environment,
37  const std::atomic_bool& keep_going,
38  Callback&& callback) {
39  const auto sample_rate = compute_sample_rate(mesh.get_descriptor(),
40  environment.speed_of_sound);
41 
42  const auto compute_mesh_index = [&](const auto& pt) {
43  const auto ret = compute_index(mesh.get_descriptor(), pt);
44  if (!waveguide::is_inside(
45  mesh.get_structure().get_condensed_nodes()[ret])) {
46  throw std::runtime_error{
47  "Source/receiver node position appears to be outside "
48  "mesh."};
49  }
50  return ret;
51  };
52 
53  const auto ideal_steps = std::ceil(sample_rate * simulation_time);
54 
55  const auto input = [&] {
56  auto raw = util::aligned::vector<float>(ideal_steps, 0.0f);
57  if (!raw.empty()) {
58  raw.front() = rectilinear_calibration_factor(
59  mesh.get_descriptor().spacing,
60  environment.acoustic_impedance);
61  }
62  return raw;
63  }();
64 
65  auto output_accumulator =
66  core::callback_accumulator<postprocessor::directional_receiver>{
67  mesh.get_descriptor(),
68  sample_rate,
69  get_ambient_density(environment),
70  compute_mesh_index(receiver)};
71 
72  const auto steps =
73  run(cc,
74  mesh,
75  preprocessor::make_hard_source(
76  compute_mesh_index(source), begin(input), end(input)),
77  [&](auto& queue, const auto& buffer, auto step) {
78  output_accumulator(queue, buffer, step);
79  callback(queue, buffer, step, ideal_steps);
80  },
81  keep_going);
82 
83  if (steps != ideal_steps) {
84  return std::experimental::nullopt;
85  }
86 
87  return band{std::move(output_accumulator.get_output()), sample_rate};
88 }
89 
90 } // namespace detail
91 
93 
100 template <typename PressureCallback>
101 std::experimental::optional<util::aligned::vector<bandpass_band>> canonical(
102  const core::compute_context& cc,
103  voxels_and_mesh voxelised,
104  const glm::vec3& source,
105  const glm::vec3& receiver,
106  const core::environment& environment,
107  const single_band_parameters& sim_params,
108  double simulation_time,
109  const std::atomic_bool& keep_going,
110  PressureCallback&& pressure_callback) {
111  if (auto ret = detail::canonical_impl(cc,
112  voxelised.mesh,
113  simulation_time,
114  source,
115  receiver,
116  environment,
117  keep_going,
118  pressure_callback)) {
119  return util::aligned::vector<bandpass_band>{bandpass_band{
120  std::move(*ret), util::make_range(0.0, sim_params.cutoff)}};
121  }
122 
123  return std::experimental::nullopt;
124 }
125 
127 
128 inline auto set_flat_coefficients_for_band(voxels_and_mesh& voxels_and_mesh,
129  size_t band) {
130  voxels_and_mesh.mesh.set_coefficients(util::map_to_vector(
131  begin(voxels_and_mesh.voxels.get_scene_data().get_surfaces()),
132  end(voxels_and_mesh.voxels.get_scene_data().get_surfaces()),
133  [&](const auto& surface) {
134  return to_flat_coefficients(surface.absorption.s[band]);
135  }));
136 }
137 
140 template <typename PressureCallback>
141 std::experimental::optional<util::aligned::vector<bandpass_band>> canonical(
142  const core::compute_context& cc,
143  voxels_and_mesh voxelised,
144  const glm::vec3& source,
145  const glm::vec3& receiver,
146  const core::environment& environment,
147  const multiple_band_constant_spacing_parameters& sim_params,
148  double simulation_time,
149  const std::atomic_bool& keep_going,
150  PressureCallback&& pressure_callback) {
151  const auto band_params = hrtf_data::hrtf_band_params_hz();
152 
153  util::aligned::vector<bandpass_band> ret{};
154 
155  // For each band, up to the maximum band specified.
156  for (auto band = 0; band != sim_params.bands; ++band) {
157  set_flat_coefficients_for_band(voxelised, band);
158 
159  if (auto rendered_band = detail::canonical_impl(cc,
160  voxelised.mesh,
161  simulation_time,
162  source,
163  receiver,
164  environment,
165  keep_going,
166  pressure_callback)) {
167  ret.emplace_back(bandpass_band{
168  std::move(*rendered_band),
169  util::make_range(band_params.edges[band],
170  band_params.edges[band + 1])});
171  } else {
172  return std::experimental::nullopt;
173  }
174  }
175 
176  return ret;
177 }
178 
179 } // namespace waveguide
180 } // namespace wayverb
Definition: traits.h:46
Definition: capsule_base.h:9