| 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/reverb_node.h" | 
| 18 |  | 
| 19 | #include <algorithm> | 
| 20 | #include <cmath> | 
| 21 |  | 
| 22 | #include "base/constants_and_types.h" | 
| 23 | #include "base/logging.h" | 
| 24 |  | 
| 25 |  | 
| 26 | namespace vraudio { | 
| 27 |  | 
| 28 | namespace { | 
| 29 |  | 
| 30 | // Default time in seconds to update the rt60s over. | 
| 31 | const float kUpdateTimeSeconds = 1.0f; | 
| 32 |  | 
| 33 | // Interpolates between the current and target values in steps of |update_step|, | 
| 34 | // will set |current| to |target| when the diff between them is less than | 
| 35 | // |update_step|. | 
| 36 | inline void InterpolateFloatParam(float update_step, float target, | 
| 37 |                                   float* current) { | 
| 38 |   if (std::abs(x: target - *current) <= std::abs(x: update_step)) { | 
| 39 |     *current = target; | 
| 40 |   } else { | 
| 41 |     *current += update_step; | 
| 42 |   } | 
| 43 | } | 
| 44 |  | 
| 45 | }  // namespace | 
| 46 |  | 
| 47 | ReverbNode::ReverbNode(const SystemSettings& system_settings, | 
| 48 |                        FftManager* fft_manager) | 
| 49 |     : system_settings_(system_settings), | 
| 50 |       rt60_band_update_steps_(kNumReverbOctaveBands, 0.0f), | 
| 51 |       gain_update_step_(0.0f), | 
| 52 |       rt60_updating_(false), | 
| 53 |       gain_updating_(false), | 
| 54 |       buffers_to_update_( | 
| 55 |           static_cast<float>(system_settings_.GetSampleRateHz()) * | 
| 56 |           kUpdateTimeSeconds / | 
| 57 |           static_cast<float>(system_settings_.GetFramesPerBuffer())), | 
| 58 |       spectral_reverb_(system_settings_.GetSampleRateHz(), | 
| 59 |                        system_settings_.GetFramesPerBuffer()), | 
| 60 |       onset_compensator_(system_settings_.GetSampleRateHz(), | 
| 61 |                          system_settings_.GetFramesPerBuffer(), fft_manager), | 
| 62 |       num_frames_processed_on_empty_input_(0), | 
| 63 |       reverb_length_frames_(0), | 
| 64 |       output_buffer_(kNumStereoChannels, system_settings_.GetFramesPerBuffer()), | 
| 65 |       compensator_output_buffer_(kNumStereoChannels, | 
| 66 |                                  system_settings_.GetFramesPerBuffer()), | 
| 67 |       silence_mono_buffer_(kNumMonoChannels, | 
| 68 |                            system_settings_.GetFramesPerBuffer()) { | 
| 69 |   EnableProcessOnEmptyInput(enable: true); | 
| 70 |   output_buffer_.Clear(); | 
| 71 |   silence_mono_buffer_.Clear(); | 
| 72 |   Update(); | 
| 73 | } | 
| 74 |  | 
| 75 | void ReverbNode::Update() { | 
| 76 |   new_reverb_properties_ = system_settings_.GetReverbProperties(); | 
| 77 |  | 
| 78 |   rt60_updating_ = !EqualSafe(lhs_begin: std::begin(arr&: reverb_properties_.rt60_values), | 
| 79 |                               lhs_end: std::end(arr&: reverb_properties_.rt60_values), | 
| 80 |                               rhs_begin: std::begin(arr&: new_reverb_properties_.rt60_values), | 
| 81 |                               rhs_end: std::end(arr&: new_reverb_properties_.rt60_values)); | 
| 82 |   if (rt60_updating_) { | 
| 83 |     for (size_t i = 0; i < kNumReverbOctaveBands; ++i) { | 
| 84 |       rt60_band_update_steps_[i] = (new_reverb_properties_.rt60_values[i] - | 
| 85 |                                     reverb_properties_.rt60_values[i]) / | 
| 86 |                                    buffers_to_update_; | 
| 87 |     } | 
| 88 |   } | 
| 89 |   // Update the reverb gain if necessary. | 
| 90 |   gain_updating_ = reverb_properties_.gain != new_reverb_properties_.gain; | 
| 91 |   if (gain_updating_) { | 
| 92 |     gain_update_step_ = | 
| 93 |         (new_reverb_properties_.gain - reverb_properties_.gain) / | 
| 94 |         buffers_to_update_; | 
| 95 |   } | 
| 96 | } | 
| 97 |  | 
| 98 | const AudioBuffer* ReverbNode::GetOutputBuffer() const | 
| 99 | { | 
| 100 |     return &output_buffer_; | 
| 101 | } | 
| 102 |  | 
| 103 | const AudioBuffer* ReverbNode::AudioProcess(const NodeInput& input) { | 
| 104 |   if (rt60_updating_) { | 
| 105 |     for (size_t i = 0; i < kNumReverbOctaveBands; ++i) { | 
| 106 |       InterpolateFloatParam(update_step: rt60_band_update_steps_[i], | 
| 107 |                             target: new_reverb_properties_.rt60_values[i], | 
| 108 |                             current: &reverb_properties_.rt60_values[i]); | 
| 109 |     } | 
| 110 |     spectral_reverb_.SetRt60PerOctaveBand(reverb_properties_.rt60_values); | 
| 111 |     const auto max_rt_it = | 
| 112 |         std::max_element(first: std::begin(arr&: reverb_properties_.rt60_values), | 
| 113 |                          last: std::end(arr&: reverb_properties_.rt60_values)); | 
| 114 |     reverb_length_frames_ = static_cast<size_t>( | 
| 115 |         *max_rt_it * static_cast<float>(system_settings_.GetSampleRateHz())); | 
| 116 |     onset_compensator_.Update(rt60_values: reverb_properties_.rt60_values, | 
| 117 |                               gain: reverb_properties_.gain); | 
| 118 |     // |InterpolateFloatParam| will set the two values below to be equal on | 
| 119 |     // completion of interpolation. | 
| 120 |     rt60_updating_ = !EqualSafe(lhs_begin: std::begin(arr&: reverb_properties_.rt60_values), | 
| 121 |                                 lhs_end: std::end(arr&: reverb_properties_.rt60_values), | 
| 122 |                                 rhs_begin: std::begin(arr&: new_reverb_properties_.rt60_values), | 
| 123 |                                 rhs_end: std::end(arr&: new_reverb_properties_.rt60_values)); | 
| 124 |   } | 
| 125 |  | 
| 126 |   if (gain_updating_) { | 
| 127 |     InterpolateFloatParam(update_step: gain_update_step_, target: new_reverb_properties_.gain, | 
| 128 |                           current: &reverb_properties_.gain); | 
| 129 |     spectral_reverb_.SetGain(reverb_properties_.gain); | 
| 130 |     onset_compensator_.Update(rt60_values: reverb_properties_.rt60_values, | 
| 131 |                               gain: reverb_properties_.gain); | 
| 132 |     // |InterpolateFloatParam| will set the two values below to be equal on | 
| 133 |     // completion of interpolation. | 
| 134 |     gain_updating_ = reverb_properties_.gain != new_reverb_properties_.gain; | 
| 135 |   } | 
| 136 |  | 
| 137 |   const AudioBuffer* input_buffer = input.GetSingleInput(); | 
| 138 |   if (input_buffer == nullptr) { | 
| 139 |     // If we have no input, generate a silent input buffer until the node states | 
| 140 |     // are cleared. | 
| 141 |     if (num_frames_processed_on_empty_input_ < reverb_length_frames_) { | 
| 142 |       const size_t num_frames = system_settings_.GetFramesPerBuffer(); | 
| 143 |       num_frames_processed_on_empty_input_ += num_frames; | 
| 144 |       spectral_reverb_.Process(input: silence_mono_buffer_[0], left_out: &output_buffer_[0], | 
| 145 |                                right_out: &output_buffer_[1]); | 
| 146 |       return &output_buffer_; | 
| 147 |     } else { | 
| 148 |       // Skip processing entirely when the states are fully cleared. | 
| 149 |       return nullptr; | 
| 150 |     } | 
| 151 |   } | 
| 152 |   DCHECK_EQ(input_buffer->num_channels(), kNumMonoChannels); | 
| 153 |   num_frames_processed_on_empty_input_ = 0; | 
| 154 |   spectral_reverb_.Process(input: (*input_buffer)[0], left_out: &output_buffer_[0], | 
| 155 |                            right_out: &output_buffer_[1]); | 
| 156 |   onset_compensator_.Process(input: *input_buffer, output: &compensator_output_buffer_); | 
| 157 |   output_buffer_[0] += compensator_output_buffer_[0]; | 
| 158 |   output_buffer_[1] += compensator_output_buffer_[1]; | 
| 159 |   return &output_buffer_; | 
| 160 | } | 
| 161 |  | 
| 162 | }  // namespace vraudio | 
| 163 |  |