| 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 "dsp/reverb_onset_update_processor.h" |
| 18 | |
| 19 | #include <algorithm> |
| 20 | |
| 21 | #include "base/constants_and_types.h" |
| 22 | #include "base/simd_utils.h" |
| 23 | #include "dsp/spectral_reverb_constants_and_tables.h" |
| 24 | #include "dsp/utils.h" |
| 25 | |
| 26 | namespace vraudio { |
| 27 | |
| 28 | namespace { |
| 29 | |
| 30 | // Find the absolute difference between two size_t values. |
| 31 | inline size_t absdiff(size_t lhs, size_t rhs) { |
| 32 | return lhs > rhs ? lhs - rhs : rhs - lhs; |
| 33 | } |
| 34 | |
| 35 | } // namespace |
| 36 | |
| 37 | ReverbOnsetUpdateProcessor::ReverbOnsetUpdateProcessor( |
| 38 | size_t frames_per_buffer, int sampling_rate, AudioBuffer* base_curves, |
| 39 | AudioBuffer* adder_curves) |
| 40 | : sampling_rate_(sampling_rate), |
| 41 | tail_update_cursor_(0), |
| 42 | tail_length_(CeilToMultipleOfFramesPerBuffer(size: kCorrectionCurveLength, |
| 43 | frames_per_buffer)), |
| 44 | gain_(1.0f), |
| 45 | curve_indices_(GetNumReverbOctaveBands(sampling_rate: sampling_rate_), kInvalidIndex), |
| 46 | pure_decay_coefficients_(curve_indices_.size(), 0.0f), |
| 47 | pure_decay_exponents_(curve_indices_.size(), 0.0f), |
| 48 | band_buffer_(kNumStereoChannels, frames_per_buffer), |
| 49 | envelope_buffer_(kNumMonoChannels, frames_per_buffer), |
| 50 | base_curves_(base_curves), |
| 51 | adder_curves_(adder_curves) {} |
| 52 | |
| 53 | void ReverbOnsetUpdateProcessor::SetReverbTimes(const float* rt60_values) { |
| 54 | DCHECK(rt60_values); |
| 55 | const size_t num_octave_bands = curve_indices_.size(); |
| 56 | const float sampling_rate_float = static_cast<float>(sampling_rate_); |
| 57 | tail_update_cursor_ = 0; |
| 58 | // Choose curves for each band. |
| 59 | for (size_t band = 0; band < num_octave_bands; ++band) { |
| 60 | curve_indices_[band] = |
| 61 | GetFeedbackIndexFromRt60(reverberation_time: rt60_values[band], sample_rate: sampling_rate_float); |
| 62 | // Deal with the case where only the convolution is needed. |
| 63 | if (curve_indices_[band] == kInvalidIndex) { |
| 64 | const float min_reverb_time = |
| 65 | kMinReverbTimeForFeedback48kHz * |
| 66 | (sampling_rate_float / kDefaultSpectralReverbSampleRate); |
| 67 | const float effective_rt = |
| 68 | rt60_values[band] <= min_reverb_time ? rt60_values[band] : 0.0f; |
| 69 | pure_decay_exponents_[band] = |
| 70 | std::abs(x: effective_rt) > kEpsilonFloat |
| 71 | ? std::exp(x: kNegativeLog1000 / |
| 72 | (sampling_rate_float * effective_rt)) |
| 73 | : 0.0f; |
| 74 | pure_decay_coefficients_[band] = pure_decay_exponents_[band]; |
| 75 | } |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | bool ReverbOnsetUpdateProcessor::Process( |
| 80 | const std::vector<AudioBuffer>& bandpassed_noise_left, |
| 81 | const std::vector<AudioBuffer>& bandpassed_noise_right, |
| 82 | AudioBuffer::Channel* kernel_channel_left, |
| 83 | AudioBuffer::Channel* kernel_channel_right) { |
| 84 | if (tail_update_cursor_ >= tail_length_) { |
| 85 | // Processing the reverb tail is finished. |
| 86 | tail_update_cursor_ = 0; |
| 87 | return false; |
| 88 | } |
| 89 | const size_t frames_per_buffer = band_buffer_.num_frames(); |
| 90 | DCHECK(kernel_channel_left); |
| 91 | DCHECK(kernel_channel_right); |
| 92 | DCHECK_EQ(bandpassed_noise_left.size(), curve_indices_.size()); |
| 93 | DCHECK_EQ(bandpassed_noise_right.size(), curve_indices_.size()); |
| 94 | DCHECK_EQ(bandpassed_noise_left[0].num_frames(), tail_length_); |
| 95 | DCHECK_EQ(bandpassed_noise_right[0].num_frames(), tail_length_); |
| 96 | DCHECK_GE(tail_length_, kCorrectionCurveLength); |
| 97 | DCHECK_EQ(kernel_channel_left->size(), frames_per_buffer); |
| 98 | DCHECK_EQ(kernel_channel_right->size(), frames_per_buffer); |
| 99 | |
| 100 | // Clear for accumulation per frequency band. |
| 101 | kernel_channel_left->Clear(); |
| 102 | kernel_channel_right->Clear(); |
| 103 | |
| 104 | AudioBuffer::Channel& band_channel_left = band_buffer_[0]; |
| 105 | AudioBuffer::Channel& band_channel_right = band_buffer_[1]; |
| 106 | // Define the number of samples we are still able to copy from the multiplier |
| 107 | // and adder curves. |
| 108 | const size_t copy_length = |
| 109 | frames_per_buffer + tail_update_cursor_ <= kCorrectionCurveLength |
| 110 | ? frames_per_buffer |
| 111 | : absdiff(lhs: kCorrectionCurveLength, rhs: tail_update_cursor_); |
| 112 | AudioBuffer::Channel* envelope_channel = &envelope_buffer_[0]; |
| 113 | // Compute the band buffer for each band response. |
| 114 | for (size_t band = 0; band < curve_indices_.size(); ++band) { |
| 115 | const AudioBuffer::Channel& noise_channel_left = |
| 116 | bandpassed_noise_left[band][0]; |
| 117 | const AudioBuffer::Channel& noise_channel_right = |
| 118 | bandpassed_noise_right[band][0]; |
| 119 | // Fill the band buffer with the next noise buffer and apply gain. |
| 120 | ScalarMultiply(length: frames_per_buffer, gain: gain_, |
| 121 | input: noise_channel_left.begin() + tail_update_cursor_, |
| 122 | output: band_channel_left.begin()); |
| 123 | ScalarMultiply(length: frames_per_buffer, gain: gain_, |
| 124 | input: noise_channel_right.begin() + tail_update_cursor_, |
| 125 | output: band_channel_right.begin()); |
| 126 | // Skip the band if we have an invalid index |
| 127 | const int curve_index = curve_indices_[band]; |
| 128 | if (curve_index != kInvalidIndex) { |
| 129 | // Apply the correct compensation curve to the buffer. |
| 130 | const float scale = kCurveCorrectionMultipliers[curve_index]; |
| 131 | AudioBuffer::Channel* adder_curve_channel; |
| 132 | if (tail_update_cursor_ < kCorrectionCurveLength) { |
| 133 | // Use either the high frequency or low frequency curve. |
| 134 | if (static_cast<size_t>(curve_index) >= kCurveChangeoverIndex) { |
| 135 | adder_curve_channel = &(*adder_curves_)[1]; |
| 136 | std::copy_n(first: (*base_curves_)[1].begin() + tail_update_cursor_, |
| 137 | n: copy_length, result: envelope_channel->begin()); |
| 138 | } else { |
| 139 | adder_curve_channel = &(*adder_curves_)[0]; |
| 140 | std::copy_n(first: (*base_curves_)[0].begin() + tail_update_cursor_, |
| 141 | n: copy_length, result: envelope_channel->begin()); |
| 142 | } |
| 143 | // Construct the correct envelope (chunk thereof). |
| 144 | ScalarMultiplyAndAccumulate( |
| 145 | length: copy_length, gain: scale, |
| 146 | input: adder_curve_channel->begin() + tail_update_cursor_, |
| 147 | accumulator: envelope_channel->begin()); |
| 148 | // Ensure the end part of the envelope does not contain spurious data. |
| 149 | std::fill(first: envelope_channel->begin() + copy_length, |
| 150 | last: envelope_channel->end(), value: 0.0f); |
| 151 | } else { |
| 152 | // If we have moved past the length of the correction curve, fill the |
| 153 | // envelope chunk with zeros. |
| 154 | envelope_channel->Clear(); |
| 155 | } |
| 156 | |
| 157 | // Apply that envelope to the given band and accumulate into the output. |
| 158 | MultiplyAndAccumulatePointwise( |
| 159 | length: frames_per_buffer, input_a: envelope_channel->begin(), |
| 160 | input_b: band_channel_left.begin(), accumulator: kernel_channel_left->begin()); |
| 161 | MultiplyAndAccumulatePointwise( |
| 162 | length: frames_per_buffer, input_a: envelope_channel->begin(), |
| 163 | input_b: band_channel_right.begin(), accumulator: kernel_channel_right->begin()); |
| 164 | } else { |
| 165 | // If the decay time is too short for the spectral reverb to make a |
| 166 | // contribution (0.15s @48kHz), the compensation filter will consist of |
| 167 | // the entire tail. |
| 168 | for (size_t frame = 0; frame < frames_per_buffer; ++frame) { |
| 169 | (*kernel_channel_left)[frame] += |
| 170 | pure_decay_coefficients_[band] * band_channel_left[frame]; |
| 171 | (*kernel_channel_right)[frame] += |
| 172 | pure_decay_coefficients_[band] * band_channel_right[frame]; |
| 173 | // Update the decay coefficient. |
| 174 | pure_decay_coefficients_[band] *= pure_decay_exponents_[band]; |
| 175 | } |
| 176 | } |
| 177 | } |
| 178 | // Update the cursor. |
| 179 | tail_update_cursor_ += frames_per_buffer; |
| 180 | |
| 181 | return true; |
| 182 | } |
| 183 | |
| 184 | } // namespace vraudio |
| 185 | |