summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/resonance-audio/resonance_audio/ambisonics/associated_legendre_polynomials_generator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/resonance-audio/resonance_audio/ambisonics/associated_legendre_polynomials_generator.cc')
-rw-r--r--src/3rdparty/resonance-audio/resonance_audio/ambisonics/associated_legendre_polynomials_generator.cc147
1 files changed, 147 insertions, 0 deletions
diff --git a/src/3rdparty/resonance-audio/resonance_audio/ambisonics/associated_legendre_polynomials_generator.cc b/src/3rdparty/resonance-audio/resonance_audio/ambisonics/associated_legendre_polynomials_generator.cc
new file mode 100644
index 000000000..49b7abf89
--- /dev/null
+++ b/src/3rdparty/resonance-audio/resonance_audio/ambisonics/associated_legendre_polynomials_generator.cc
@@ -0,0 +1,147 @@
+/*
+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 "ambisonics/associated_legendre_polynomials_generator.h"
+
+#include <cmath>
+
+#include "base/logging.h"
+#include "base/misc_math.h"
+
+namespace vraudio {
+
+AssociatedLegendrePolynomialsGenerator::AssociatedLegendrePolynomialsGenerator(
+ int max_degree, bool condon_shortley_phase, bool compute_negative_order)
+ : max_degree_(max_degree),
+ condon_shortley_phase_(condon_shortley_phase),
+ compute_negative_order_(compute_negative_order) {
+ DCHECK_GE(max_degree_, 0);
+}
+
+std::vector<float> AssociatedLegendrePolynomialsGenerator::Generate(
+ float x) const {
+ std::vector<float> values(GetNumValues());
+
+ // Bases for the recurrence relations.
+ values[GetIndex(0, 0)] = ComputeValue(0, 0, x, values);
+ if (max_degree_ >= 1) values[GetIndex(1, 0)] = ComputeValue(1, 0, x, values);
+
+ // Using recurrence relations, we now compute the rest of the values needed.
+ // (degree, 0), based on (degree - 1, 0) and (degree - 2, 0):
+ for (int degree = 2; degree <= max_degree_; ++degree) {
+ const int order = 0;
+ values[GetIndex(degree, order)] = ComputeValue(degree, order, x, values);
+ }
+ // (degree, degree):
+ for (int degree = 1; degree <= max_degree_; ++degree) {
+ const int order = degree;
+ values[GetIndex(degree, order)] = ComputeValue(degree, order, x, values);
+ }
+ // (degree, degree - 1):
+ for (int degree = 2; degree <= max_degree_; ++degree) {
+ const int order = degree - 1;
+ values[GetIndex(degree, order)] = ComputeValue(degree, order, x, values);
+ }
+ // The remaining positive orders, based on (degree - 1, order) and
+ // (degree - 2, order):
+ for (int degree = 3; degree <= max_degree_; ++degree) {
+ for (int order = 1; order <= degree - 2; ++order) {
+ values[GetIndex(degree, order)] = ComputeValue(degree, order, x, values);
+ }
+ }
+ // (degree, -order):
+ if (compute_negative_order_) {
+ for (int degree = 1; degree <= max_degree_; ++degree) {
+ for (int order = 1; order <= degree; ++order) {
+ values[GetIndex(degree, -order)] =
+ ComputeValue(degree, -order, x, values);
+ }
+ }
+ }
+ if (!condon_shortley_phase_) {
+ for (int degree = 1; degree <= max_degree_; ++degree) {
+ const int start_order = compute_negative_order_ ? -degree : 0;
+ for (int order = start_order; order <= degree; ++order) {
+ // Undo the Condon-Shortley phase.
+ values[GetIndex(degree, order)] *=
+ static_cast<float>(std::pow(-1, order));
+ }
+ }
+ }
+ return values;
+}
+
+size_t AssociatedLegendrePolynomialsGenerator::GetNumValues() const {
+ if (compute_negative_order_)
+ return (max_degree_ + 1) * (max_degree_ + 1);
+ else
+ return ((max_degree_ + 1) * (max_degree_ + 2)) / 2;
+}
+
+size_t AssociatedLegendrePolynomialsGenerator::GetIndex(int degree,
+ int order) const {
+ CheckIndexValidity(degree, order);
+ size_t result;
+ if (compute_negative_order_) {
+ result = static_cast<size_t>(degree * (degree + 1) + order);
+ } else {
+ result = static_cast<size_t>((degree * (degree + 1)) / 2 + order);
+ }
+ DCHECK_GE(result, 0U);
+ DCHECK_LT(result, GetNumValues());
+ return result;
+}
+
+float AssociatedLegendrePolynomialsGenerator::ComputeValue(
+ int degree, int order, float x, const std::vector<float>& values) const {
+ CheckIndexValidity(degree, order);
+ if (degree == 0 && order == 0) {
+ return 1;
+ } else if (degree == 1 && order == 0) {
+ return x;
+ } else if (degree == order) {
+ return std::pow(-1.0f, static_cast<float>(degree)) *
+ DoubleFactorial(2 * degree - 1) *
+ std::pow((1.0f - x * x), 0.5f * static_cast<float>(degree));
+ } else if (order == degree - 1) {
+ return x * static_cast<float>(2 * degree - 1) *
+ values[GetIndex(degree - 1, degree - 1)];
+ } else if (order < 0) {
+ return std::pow(-1.0f, static_cast<float>(order)) *
+ Factorial(degree + order) / Factorial(degree - order) *
+ values[GetIndex(degree, -order)];
+ } else {
+ return (static_cast<float>(2 * degree - 1) * x *
+ values[GetIndex(degree - 1, order)] -
+ static_cast<float>(degree - 1 + order) *
+ values[GetIndex(degree - 2, order)]) /
+ static_cast<float>(degree - order);
+ }
+}
+
+void AssociatedLegendrePolynomialsGenerator::CheckIndexValidity(
+ int degree, int order) const {
+ DCHECK_GE(degree, 0);
+ DCHECK_LE(degree, max_degree_);
+ if (compute_negative_order_) {
+ DCHECK_LE(-degree, order);
+ } else {
+ DCHECK_GE(order, 0);
+ }
+ DCHECK_LE(order, degree);
+}
+
+} // namespace vraudio