1 /*
2 * Copyright (c) 2024, Alliance for Open Media. All rights reserved
3 *
4 * This source code is subject to the terms of the BSD 3-Clause Clear License
5 * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
6 * License was not distributed with this source code in the LICENSE file, you
7 * can obtain it at www.aomedia.org/license/software-license/bsd-3-c-c. If the
8 * Alliance for Open Media Patent License 1.0 was not distributed with this
9 * source code in the PATENTS file, you can obtain it at
10 * www.aomedia.org/license/patent.
11 */
12
13 #ifndef CLI_AMBISONIC_ENCODER_AMBISONIC_UTILS_H_
14 #define CLI_AMBISONIC_ENCODER_AMBISONIC_UTILS_H_
15
16 #include <cmath>
17 #include <numbers>
18
19 #include "absl/log/check.h"
20
21 // TODO(b/400635711): Use the one in the obr library once it is open-sourced.
22 // This code is forked from Resonance Audio's `misc_math.h`.
23 namespace iamf_tools {
24 // Defines conversion factor from degrees to radians.
25 inline constexpr float kRadiansFromDegrees =
26 static_cast<float>(std::numbers::pi_v<float> / 180.0);
27
28 // Defines conversion factor from radians to degrees.
29 inline constexpr float kDegreesFromRadians =
30 static_cast<float>(180.0 / std::numbers::pi_v<float>);
31
32 /*!\brief Returns the factorial (!) of x. If x < 0, it returns 0.
33 *
34 * \param x Input to take factorial of.
35 * \return Computed factorial of input; 0 if the input is negative.
36 */
Factorial(int x)37 inline float Factorial(int x) {
38 if (x < 0) {
39 return 0.0f;
40 }
41 float result = 1.0f;
42 for (; x > 0; --x) {
43 result *= static_cast<float>(x);
44 }
45 return result;
46 }
47
48 /*!\brief Returns the double factorial (!!) of x.
49 *
50 * For odd x: 1 * 3 * 5 * ... * (x - 2) * x.
51 * For even x: 2 * 4 * 6 * ... * (x - 2) * x.
52 * If x < 0, it returns 0.
53 *
54 * \param x Input to take double factorial of.
55 * \return Computed double factorial of input; 0 if the input is negative.
56 */
DoubleFactorial(int x)57 inline float DoubleFactorial(int x) {
58 if (x < 0) {
59 return 0.0f;
60 }
61 float result = 1.0f;
62 for (; x > 0; x -= 2) {
63 result *= static_cast<float>(x);
64 }
65 return result;
66 }
67
68 /*!\brief Computes `base`^`exp`, where `exp` is a *non-negative* integer.
69 *
70 * Computed using the squared exponentiation (a.k.a double-and-add) method.
71 * When `T` is a floating point type, this has the same semantics as pow(), but
72 * is much faster.
73 * `T` can also be any integral type, in which case computations will be
74 * performed in the value domain of this integral type, and overflow semantics
75 * will be those of `T`.
76 * You can also use any type for which `operator*=` is defined.
77
78 * \param base Input to the exponent function. Any type for which *= is defined.
79 * \param exp Integer exponent, must be greater than or equal to zero.
80 * \return `base`^`exp`.
81 */
82 template <typename T>
IntegerPow(T base,int exp)83 static inline T IntegerPow(T base, int exp) {
84 DCHECK_GE(exp, 0);
85 T result = static_cast<T>(1);
86 while (true) {
87 if (exp & 1) {
88 result *= base;
89 }
90 exp >>= 1;
91 if (!exp) break;
92 base *= base;
93 }
94 return result;
95 }
96
97 /*!\brief Computes ACN channel sequence from a degree and order.
98 *
99 * \param degree Degree of the spherical harmonic.
100 * \param order Order of the spherical harmonic.
101 * \return Computed ACN channel sequence.
102 */
AcnSequence(int degree,int order)103 inline int AcnSequence(int degree, int order) {
104 DCHECK_GE(degree, 0);
105 DCHECK_LE(-degree, order);
106 DCHECK_LE(order, degree);
107
108 return degree * degree + degree + order;
109 }
110
111 /*!\brief Computes normalization factor for Schmidt semi-normalized harmonics.
112 *
113 * The Schmidt semi-normalized spherical harmonics is used in AmbiX.
114 *
115 * \param degree Degree of the spherical harmonic.
116 * \param order Order of the spherical harmonic.
117 * \return Computed normalization factor.
118 */
Sn3dNormalization(int degree,int order)119 inline float Sn3dNormalization(int degree, int order) {
120 DCHECK_GE(degree, 0);
121 DCHECK_LE(-degree, order);
122 DCHECK_LE(order, degree);
123 return std::sqrt((2.0f - ((order == 0) ? 1.0f : 0.0f)) *
124 Factorial(degree - std::abs(order)) /
125 Factorial(degree + std::abs(order)));
126 }
127
128 } // namespace iamf_tools
129
130 #endif // CLI_AMBISONIC_ENCODER_AMBISONIC_UTILS_H_
131