/* 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 #include #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(system_settings_.GetSampleRateHz()) * kUpdateTimeSeconds / static_cast(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( *max_rt_it * static_cast(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