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 | #ifndef RESONANCE_AUDIO_AMBISONICS_UTILS_H_ |
18 | #define RESONANCE_AUDIO_AMBISONICS_UTILS_H_ |
19 | |
20 | #include <cmath> |
21 | |
22 | #include "base/constants_and_types.h" |
23 | #include "base/logging.h" |
24 | #include "base/misc_math.h" |
25 | |
26 | namespace vraudio { |
27 | |
28 | // Returns ACN channel sequence from a degree and order of a spherical harmonic. |
29 | inline int AcnSequence(int degree, int order) { |
30 | DCHECK_GE(degree, 0); |
31 | DCHECK_LE(-degree, order); |
32 | DCHECK_LE(order, degree); |
33 | |
34 | return degree * degree + degree + order; |
35 | } |
36 | |
37 | // Returns normalization factor for Schmidt semi-normalized spherical harmonics |
38 | // used in AmbiX. |
39 | inline float Sn3dNormalization(int degree, int order) { |
40 | DCHECK_GE(degree, 0); |
41 | DCHECK_LE(-degree, order); |
42 | DCHECK_LE(order, degree); |
43 | return std::sqrt(x: (2.0f - ((order == 0) ? 1.0f : 0.0f)) * |
44 | Factorial(x: degree - std::abs(x: order)) / |
45 | Factorial(x: degree + std::abs(x: order))); |
46 | } |
47 | |
48 | // Returns the number of spherical harmonics for a periphonic ambisonic sound |
49 | // field of |ambisonic_order| at compile-time. |
50 | // We have to use template metaprogramming because MSVC12 doesn't support |
51 | // constexpr. |
52 | template <size_t AmbisonicOrder> |
53 | struct GetNumPeriphonicComponentsStatic { |
54 | enum { value = (AmbisonicOrder + 1) * (AmbisonicOrder + 1) }; |
55 | }; |
56 | |
57 | // Returns the number of spherical harmonics for a periphonic ambisonic sound |
58 | // field of |ambisonic_order|. |
59 | inline size_t GetNumPeriphonicComponents(int ambisonic_order) { |
60 | return static_cast<size_t>((ambisonic_order + 1) * (ambisonic_order + 1)); |
61 | } |
62 | |
63 | // Returns the number of periphonic spherical harmonics (SHs) for a particular |
64 | // Ambisonic order. E.g. number of 1st, 2nd or 3rd degree SHs in a 3rd order |
65 | // sound field. |
66 | inline size_t GetNumNthOrderPeriphonicComponents(int ambisonic_order) { |
67 | if (ambisonic_order == 0) return 1; |
68 | return static_cast<size_t>(GetNumPeriphonicComponents(ambisonic_order) - |
69 | GetNumPeriphonicComponents(ambisonic_order: ambisonic_order - 1)); |
70 | } |
71 | |
72 | // Calculates the ambisonic order of a periphonic sound field with the given |
73 | // number of spherical harmonics. |
74 | inline int GetPeriphonicAmbisonicOrder(size_t num_components) { |
75 | DCHECK_GT(num_components, 0); |
76 | const int ambisonic_order = static_cast<int>(std::sqrt(x: num_components)) - 1; |
77 | // Detect when num_components is not square. |
78 | DCHECK_EQ((ambisonic_order + 1) * (ambisonic_order + 1), |
79 | static_cast<int>(num_components)); |
80 | return ambisonic_order; |
81 | } |
82 | |
83 | // Calculates the order of the current spherical harmonic channel as the integer |
84 | // part of a square root of the channel number. Please note, that in Ambisonics |
85 | // the terms 'order' (usually denoted as 'n') and 'degree' (usually denoted as |
86 | // 'm') are used in the opposite meaning as in more traditional maths or physics |
87 | // conventions: |
88 | // [1] C. Nachbar, F. Zotter, E. Deleflie, A. Sontacchi, "AMBIX - A SUGGESTED |
89 | // AMBISONICS FORMAT", Proc. of the 2nd Ambisonics Symposium, June 2-3 2011, |
90 | // Lexington, KY, https://goo.gl/jzt4Yy. |
91 | inline int GetPeriphonicAmbisonicOrderForChannel(size_t channel) { |
92 | return static_cast<int>(sqrtf(x: static_cast<float>(channel))); |
93 | } |
94 | |
95 | // Calculates the degree of the current spherical harmonic channel. Please note, |
96 | // that in Ambisonics the terms 'order' (usually denoted as 'n') and 'degree' |
97 | // (usually denoted as 'm') are used in the opposite meaning as in more |
98 | // traditional maths or physics conventions: |
99 | // [1] C. Nachbar, F. Zotter, E. Deleflie, A. Sontacchi, "AMBIX - A SUGGESTED |
100 | // AMBISONICS FORMAT", Proc. of the 2nd Ambisonics Symposium, June 2-3 2011, |
101 | // Lexington, KY, https://goo.gl/jzt4Yy. |
102 | inline int GetPeriphonicAmbisonicDegreeForChannel(size_t channel) { |
103 | const int order = GetPeriphonicAmbisonicOrderForChannel(channel); |
104 | return static_cast<int>(channel) - order * (order + 1); |
105 | } |
106 | |
107 | // Returns whether the given |num_channels| corresponds to a valid ambisonic |
108 | // order configuration. |
109 | inline bool IsValidAmbisonicOrder(size_t num_channels) { |
110 | if (num_channels == 0) { |
111 | return false; |
112 | } |
113 | // Number of channels must be a square number for valid ambisonic orders. |
114 | const size_t sqrt_num_channels = static_cast<size_t>(std::sqrt(x: num_channels)); |
115 | return num_channels == sqrt_num_channels * sqrt_num_channels; |
116 | } |
117 | |
118 | } // namespace vraudio |
119 | |
120 | #endif // RESONANCE_AUDIO_AMBISONICS_UTILS_H_ |
121 | |