summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/resonance-audio/resonance_audio/dsp/utils.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/resonance-audio/resonance_audio/dsp/utils.cc')
-rw-r--r--src/3rdparty/resonance-audio/resonance_audio/dsp/utils.cc190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/3rdparty/resonance-audio/resonance_audio/dsp/utils.cc b/src/3rdparty/resonance-audio/resonance_audio/dsp/utils.cc
new file mode 100644
index 000000000..e1d8396a0
--- /dev/null
+++ b/src/3rdparty/resonance-audio/resonance_audio/dsp/utils.cc
@@ -0,0 +1,190 @@
+/*
+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 "dsp/utils.h"
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+#include <random>
+#include <vector>
+
+#include "base/constants_and_types.h"
+#include "base/logging.h"
+#include "base/misc_math.h"
+
+#include "dsp/biquad_filter.h"
+#include "dsp/filter_coefficient_generators.h"
+
+namespace {
+
+// The mean and standard deviation of the normal distribution for bandlimited
+// Gaussian noise.
+const float kMean = 0.0f;
+const float kStandardDeviation = 1.0f;
+
+// Maximum group delay in seconds for each filter. In order to avoid audible
+// distortion, the maximum phase shift of a re-combined stereo sequence should
+// not exceed 5ms at high frequencies. That is why, maximum phase shift of
+// each filter is set to 1/2 of that value.
+const float kMaxGroupDelaySeconds = 0.0025f;
+
+// Phase modulation depth, chosen so that for a given max group delay filters
+// provide the lowest cross-correlation coefficient.
+const float kPhaseModulationDepth = 1.18f;
+
+// Constants used in the generation of uniform random number distributions.
+// https://en.wikipedia.org/wiki/Linear_congruential_generator
+const uint64 kMultiplier = 1664525L;
+const uint64 kIncrement = 1013904223L;
+const float kInt32ToFloat =
+ 1.0f / static_cast<float>(std::numeric_limits<uint32>::max());
+
+} // namespace
+
+namespace vraudio {
+
+void GenerateGaussianNoise(float mean, float std_deviation, unsigned seed,
+ AudioBuffer::Channel* noise_channel) {
+ DCHECK(noise_channel);
+ // First generate uniform noise.
+ GenerateUniformNoise(0.0f, 1.0f, seed, noise_channel);
+ const size_t length = noise_channel->size();
+
+ // Gaussian distribution with mean and standard deviation in pairs via the
+ // box-muller transform
+ // https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform.
+ for (size_t i = 0; i < length - 1; i += 2) {
+ const float part_one = std::sqrt(-2.0f * std::log((*noise_channel)[i]));
+ const float part_two = kTwoPi * (*noise_channel)[i + 1];
+ const float z0 = part_one * std::cos(part_two);
+ const float z1 = part_one * std::sin(part_two);
+ (*noise_channel)[i] = std_deviation * z0 + mean;
+ (*noise_channel)[i + 1] = std_deviation * z1 + mean;
+ }
+ // Handle the odd buffer length case cheaply.
+ if (length % 2 > 0) {
+ (*noise_channel)[length - 1] = (*noise_channel)[0];
+ }
+}
+
+void GenerateUniformNoise(float min, float max, unsigned seed,
+ AudioBuffer::Channel* noise_channel) {
+ // Simple random generator to avoid the use of std::uniform_real_distribution
+ // affected by https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56202
+ DCHECK(noise_channel);
+ DCHECK_LT(min, max);
+ const float scaled_conversion_factor = kInt32ToFloat * (max - min);
+ uint32 state = static_cast<uint32>(seed);
+ for (float& sample : *noise_channel) {
+ state = static_cast<uint32>(state * kMultiplier + kIncrement);
+ sample = min + static_cast<float>(state) * scaled_conversion_factor;
+ }
+}
+
+void GenerateBandLimitedGaussianNoise(float center_frequency, int sampling_rate,
+ unsigned seed,
+ AudioBuffer* noise_buffer) {
+
+
+ DCHECK(noise_buffer);
+ DCHECK_GT(sampling_rate, 0);
+ DCHECK_LT(center_frequency, static_cast<float>(sampling_rate) / 2.0f);
+ const size_t num_frames = noise_buffer->num_frames();
+
+ BiquadCoefficients bandpass_coefficients = ComputeBandPassBiquadCoefficients(
+ sampling_rate, center_frequency, /*bandwidth=*/1);
+ BiquadFilter bandpass_filter(bandpass_coefficients, num_frames);
+
+ for (auto& channel : *noise_buffer) {
+ GenerateGaussianNoise(kMean, kStandardDeviation, seed, &channel);
+ bandpass_filter.Filter(channel, &channel);
+ bandpass_filter.Clear();
+ }
+}
+
+std::unique_ptr<AudioBuffer> GenerateDecorrelationFilters(int sampling_rate) {
+
+ const int kMaxGroupDelaySamples = static_cast<int>(
+ roundf(kMaxGroupDelaySeconds * static_cast<float>(sampling_rate)));
+
+ // Filter coefficients according to:
+ // [1] F. Zotter, M. Frank, "Efficient Phantom Source Widening", Archives of
+ // Acoustics, Vol. 38, No. 1, pp. 27–37 (2013).
+ const float g0 = 1.0f - 0.25f * IntegerPow(kPhaseModulationDepth, 2);
+ const float g1 = 0.5f * kPhaseModulationDepth -
+ 0.0625f * IntegerPow(kPhaseModulationDepth, 3);
+ const float g2 = 0.1250f * IntegerPow(kPhaseModulationDepth, 2);
+ std::vector<float> filter1_coefficients{g2, g1, g0, -g1, g2};
+ std::vector<float> filter2_coefficients{g2, -g1, g0, g1, g2};
+
+ const size_t filter_length =
+ filter1_coefficients.size() * kMaxGroupDelaySamples;
+ std::unique_ptr<AudioBuffer> decorrelation_filters(
+ new AudioBuffer(kNumStereoChannels, filter_length));
+ decorrelation_filters->Clear();
+
+ for (size_t coefficient = 0; coefficient < filter1_coefficients.size();
+ ++coefficient) {
+ (*decorrelation_filters)[0][coefficient * kMaxGroupDelaySamples] =
+ filter1_coefficients[coefficient];
+ (*decorrelation_filters)[1][coefficient * kMaxGroupDelaySamples] =
+ filter2_coefficients[coefficient];
+ }
+
+ return decorrelation_filters;
+}
+
+size_t GetNumReverbOctaveBands(int sampling_rate) {
+ DCHECK_GT(sampling_rate, 0);
+
+ const float max_band =
+ log2f(0.5f * static_cast<float>(sampling_rate) / kLowestOctaveBandHz);
+ return std::min(kNumReverbOctaveBands, static_cast<size_t>(roundf(max_band)));
+}
+
+size_t GetNumSamplesFromMilliseconds(float milliseconds, int sampling_rate) {
+ DCHECK_GE(milliseconds, 0.0f);
+ DCHECK_GT(sampling_rate, 0);
+ return static_cast<size_t>(milliseconds * kSecondsFromMilliseconds *
+ static_cast<float>(sampling_rate));
+}
+
+size_t CeilToMultipleOfFramesPerBuffer(size_t size, size_t frames_per_buffer) {
+ DCHECK_NE(frames_per_buffer, 0U);
+ const size_t remainder = size % frames_per_buffer;
+ return remainder == 0 ? std::max(size, frames_per_buffer)
+ : size + frames_per_buffer - remainder;
+}
+
+void GenerateHannWindow(bool full_window, size_t window_length,
+ AudioBuffer::Channel* buffer) {
+
+ DCHECK(buffer);
+ DCHECK_LE(window_length, buffer->size());
+ const float full_window_scaling_factor =
+ kTwoPi / (static_cast<float>(window_length) - 1.0f);
+ const float half_window_scaling_factor =
+ kTwoPi / (2.0f * static_cast<float>(window_length) - 1.0f);
+ const float scaling_factor =
+ (full_window) ? full_window_scaling_factor : half_window_scaling_factor;
+ for (size_t i = 0; i < window_length; ++i) {
+ (*buffer)[i] =
+ 0.5f * (1.0f - std::cos(scaling_factor * static_cast<float>(i)));
+ }
+}
+
+} // namespace vraudio