Source code

Revision control

Copy as Markdown

/*
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
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