diff options
Diffstat (limited to 'src/3rdparty/resonance-audio/resonance_audio/graph/reverb_node.cc')
-rw-r--r-- | src/3rdparty/resonance-audio/resonance_audio/graph/reverb_node.cc | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/src/3rdparty/resonance-audio/resonance_audio/graph/reverb_node.cc b/src/3rdparty/resonance-audio/resonance_audio/graph/reverb_node.cc new file mode 100644 index 000000000..6a9999881 --- /dev/null +++ b/src/3rdparty/resonance-audio/resonance_audio/graph/reverb_node.cc @@ -0,0 +1,162 @@ +/* +Copyright 2018 Google Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS-IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "graph/reverb_node.h" + +#include <algorithm> +#include <cmath> + +#include "base/constants_and_types.h" +#include "base/logging.h" + + +namespace vraudio { + +namespace { + +// Default time in seconds to update the rt60s over. +const float kUpdateTimeSeconds = 1.0f; + +// Interpolates between the current and target values in steps of |update_step|, +// will set |current| to |target| when the diff between them is less than +// |update_step|. +inline void InterpolateFloatParam(float update_step, float target, + float* current) { + if (std::abs(target - *current) <= std::abs(update_step)) { + *current = target; + } else { + *current += update_step; + } +} + +} // namespace + +ReverbNode::ReverbNode(const SystemSettings& system_settings, + FftManager* fft_manager) + : system_settings_(system_settings), + rt60_band_update_steps_(kNumReverbOctaveBands, 0.0f), + gain_update_step_(0.0f), + rt60_updating_(false), + gain_updating_(false), + buffers_to_update_( + static_cast<float>(system_settings_.GetSampleRateHz()) * + kUpdateTimeSeconds / + static_cast<float>(system_settings_.GetFramesPerBuffer())), + spectral_reverb_(system_settings_.GetSampleRateHz(), + system_settings_.GetFramesPerBuffer()), + onset_compensator_(system_settings_.GetSampleRateHz(), + system_settings_.GetFramesPerBuffer(), fft_manager), + num_frames_processed_on_empty_input_(0), + reverb_length_frames_(0), + output_buffer_(kNumStereoChannels, system_settings_.GetFramesPerBuffer()), + compensator_output_buffer_(kNumStereoChannels, + system_settings_.GetFramesPerBuffer()), + silence_mono_buffer_(kNumMonoChannels, + system_settings_.GetFramesPerBuffer()) { + EnableProcessOnEmptyInput(true); + output_buffer_.Clear(); + silence_mono_buffer_.Clear(); + Update(); +} + +void ReverbNode::Update() { + new_reverb_properties_ = system_settings_.GetReverbProperties(); + + rt60_updating_ = !EqualSafe(std::begin(reverb_properties_.rt60_values), + std::end(reverb_properties_.rt60_values), + std::begin(new_reverb_properties_.rt60_values), + std::end(new_reverb_properties_.rt60_values)); + if (rt60_updating_) { + for (size_t i = 0; i < kNumReverbOctaveBands; ++i) { + rt60_band_update_steps_[i] = (new_reverb_properties_.rt60_values[i] - + reverb_properties_.rt60_values[i]) / + buffers_to_update_; + } + } + // Update the reverb gain if necessary. + gain_updating_ = reverb_properties_.gain != new_reverb_properties_.gain; + if (gain_updating_) { + gain_update_step_ = + (new_reverb_properties_.gain - reverb_properties_.gain) / + buffers_to_update_; + } +} + +const AudioBuffer* ReverbNode::GetOutputBuffer() const +{ + return &output_buffer_; +} + +const AudioBuffer* ReverbNode::AudioProcess(const NodeInput& input) { + if (rt60_updating_) { + for (size_t i = 0; i < kNumReverbOctaveBands; ++i) { + InterpolateFloatParam(rt60_band_update_steps_[i], + new_reverb_properties_.rt60_values[i], + &reverb_properties_.rt60_values[i]); + } + spectral_reverb_.SetRt60PerOctaveBand(reverb_properties_.rt60_values); + const auto max_rt_it = + std::max_element(std::begin(reverb_properties_.rt60_values), + std::end(reverb_properties_.rt60_values)); + reverb_length_frames_ = static_cast<size_t>( + *max_rt_it * static_cast<float>(system_settings_.GetSampleRateHz())); + onset_compensator_.Update(reverb_properties_.rt60_values, + reverb_properties_.gain); + // |InterpolateFloatParam| will set the two values below to be equal on + // completion of interpolation. + rt60_updating_ = !EqualSafe(std::begin(reverb_properties_.rt60_values), + std::end(reverb_properties_.rt60_values), + std::begin(new_reverb_properties_.rt60_values), + std::end(new_reverb_properties_.rt60_values)); + } + + if (gain_updating_) { + InterpolateFloatParam(gain_update_step_, new_reverb_properties_.gain, + &reverb_properties_.gain); + spectral_reverb_.SetGain(reverb_properties_.gain); + onset_compensator_.Update(reverb_properties_.rt60_values, + reverb_properties_.gain); + // |InterpolateFloatParam| will set the two values below to be equal on + // completion of interpolation. + gain_updating_ = reverb_properties_.gain != new_reverb_properties_.gain; + } + + const AudioBuffer* input_buffer = input.GetSingleInput(); + if (input_buffer == nullptr) { + // If we have no input, generate a silent input buffer until the node states + // are cleared. + if (num_frames_processed_on_empty_input_ < reverb_length_frames_) { + const size_t num_frames = system_settings_.GetFramesPerBuffer(); + num_frames_processed_on_empty_input_ += num_frames; + spectral_reverb_.Process(silence_mono_buffer_[0], &output_buffer_[0], + &output_buffer_[1]); + return &output_buffer_; + } else { + // Skip processing entirely when the states are fully cleared. + return nullptr; + } + } + DCHECK_EQ(input_buffer->num_channels(), kNumMonoChannels); + num_frames_processed_on_empty_input_ = 0; + spectral_reverb_.Process((*input_buffer)[0], &output_buffer_[0], + &output_buffer_[1]); + onset_compensator_.Process(*input_buffer, &compensator_output_buffer_); + output_buffer_[0] += compensator_output_buffer_[0]; + output_buffer_[1] += compensator_output_buffer_[1]; + return &output_buffer_; +} + +} // namespace vraudio |