1 | /* |
2 | Copyright 2018 Google Inc. All Rights Reserved. |
3 | |
4 | Licensed under the Apache License, Version 2.0 (the "License"); |
5 | you may not use this file except in compliance with the License. |
6 | You may obtain a copy of the License at |
7 | |
8 | http://www.apache.org/licenses/LICENSE-2.0 |
9 | |
10 | Unless required by applicable law or agreed to in writing, software |
11 | distributed under the License is distributed on an "AS-IS" BASIS, |
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | See the License for the specific language governing permissions and |
14 | limitations under the License. |
15 | */ |
16 | |
17 | #include "graph/reflections_node.h" |
18 | |
19 | #include "base/constants_and_types.h" |
20 | #include "base/logging.h" |
21 | #include "base/misc_math.h" |
22 | |
23 | |
24 | namespace vraudio { |
25 | |
26 | ReflectionsNode::ReflectionsNode(const SystemSettings& system_settings) |
27 | : system_settings_(system_settings), |
28 | reflections_processor_(system_settings_.GetSampleRateHz(), |
29 | system_settings_.GetFramesPerBuffer()), |
30 | num_frames_processed_on_empty_input_( |
31 | system_settings_.GetFramesPerBuffer()), |
32 | output_buffer_(kNumFirstOrderAmbisonicChannels, |
33 | system_settings_.GetFramesPerBuffer()), |
34 | silence_mono_buffer_(kNumMonoChannels, |
35 | system_settings_.GetFramesPerBuffer()) { |
36 | silence_mono_buffer_.Clear(); |
37 | EnableProcessOnEmptyInput(enable: true); |
38 | } |
39 | |
40 | void ReflectionsNode::Update() { |
41 | |
42 | const auto& current_reflection_properties = reflection_properties_; |
43 | const auto& new_reflection_properties = |
44 | system_settings_.GetReflectionProperties(); |
45 | const bool room_position_changed = |
46 | !EqualSafe(lhs_begin: std::begin(arr: current_reflection_properties.room_position), |
47 | lhs_end: std::end(arr: current_reflection_properties.room_position), |
48 | rhs_begin: std::begin(arr: new_reflection_properties.room_position), |
49 | rhs_end: std::end(arr: new_reflection_properties.room_position)); |
50 | const bool room_rotation_changed = |
51 | !EqualSafe(lhs_begin: std::begin(arr: current_reflection_properties.room_rotation), |
52 | lhs_end: std::end(arr: current_reflection_properties.room_rotation), |
53 | rhs_begin: std::begin(arr: new_reflection_properties.room_rotation), |
54 | rhs_end: std::end(arr: new_reflection_properties.room_rotation)); |
55 | const bool room_dimensions_changed = |
56 | !EqualSafe(lhs_begin: std::begin(arr: current_reflection_properties.room_dimensions), |
57 | lhs_end: std::end(arr: current_reflection_properties.room_dimensions), |
58 | rhs_begin: std::begin(arr: new_reflection_properties.room_dimensions), |
59 | rhs_end: std::end(arr: new_reflection_properties.room_dimensions)); |
60 | const bool cutoff_frequency_changed = |
61 | current_reflection_properties.cutoff_frequency != |
62 | new_reflection_properties.cutoff_frequency; |
63 | const bool coefficients_changed = |
64 | !EqualSafe(lhs_begin: std::begin(arr: current_reflection_properties.coefficients), |
65 | lhs_end: std::end(arr: current_reflection_properties.coefficients), |
66 | rhs_begin: std::begin(arr: new_reflection_properties.coefficients), |
67 | rhs_end: std::end(arr: new_reflection_properties.coefficients)); |
68 | const auto& current_listener_position = listener_position_; |
69 | const auto& new_listener_position = system_settings_.GetHeadPosition(); |
70 | const bool listener_position_changed = |
71 | current_listener_position != new_listener_position; |
72 | if (room_position_changed || room_rotation_changed || |
73 | room_dimensions_changed || cutoff_frequency_changed || |
74 | coefficients_changed || listener_position_changed) { |
75 | // Update reflections processor if necessary. |
76 | reflection_properties_ = new_reflection_properties; |
77 | listener_position_ = new_listener_position; |
78 | reflections_processor_.Update(reflection_properties: reflection_properties_, listener_position: listener_position_); |
79 | } |
80 | } |
81 | |
82 | const AudioBuffer* ReflectionsNode::AudioProcess(const NodeInput& input) { |
83 | |
84 | const AudioBuffer* input_buffer = input.GetSingleInput(); |
85 | const size_t num_frames = system_settings_.GetFramesPerBuffer(); |
86 | if (input_buffer == nullptr) { |
87 | // If we have no input, generate a silent input buffer until the node states |
88 | // are cleared. |
89 | if (num_frames_processed_on_empty_input_ < |
90 | reflections_processor_.num_frames_to_process_on_empty_input()) { |
91 | num_frames_processed_on_empty_input_ += num_frames; |
92 | input_buffer = &silence_mono_buffer_; |
93 | } else { |
94 | // Skip processing entirely when the states are fully cleared. |
95 | return nullptr; |
96 | } |
97 | } else { |
98 | num_frames_processed_on_empty_input_ = 0; |
99 | DCHECK_EQ(input_buffer->num_channels(), kNumMonoChannels); |
100 | } |
101 | output_buffer_.Clear(); |
102 | reflections_processor_.Process(input: *input_buffer, output: &output_buffer_); |
103 | |
104 | // Rotate the reflections with respect to listener's orientation. |
105 | const WorldRotation inverse_head_rotation = |
106 | system_settings_.GetHeadRotation().conjugate(); |
107 | foa_rotator_.Process(target_rotation: inverse_head_rotation, input: output_buffer_, output: &output_buffer_); |
108 | |
109 | // Copy buffer parameters. |
110 | return &output_buffer_; |
111 | } |
112 | |
113 | } // namespace vraudio |
114 | |