react-native-audio-api 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (242) hide show
  1. package/README.md +60 -1
  2. package/RNAudioAPI.podspec +46 -0
  3. package/android/CMakeLists.txt +74 -0
  4. package/android/build.gradle +194 -0
  5. package/android/gradle.properties +5 -0
  6. package/android/libs/fftw3/arm64-v8a/libfftw3.a +0 -0
  7. package/android/libs/fftw3/armeabi-v7a/libfftw3.a +0 -0
  8. package/android/libs/fftw3/x86/libfftw3.a +0 -0
  9. package/android/libs/fftw3/x86_64/libfftw3.a +0 -0
  10. package/android/libs/include/fftw3/fftw3.h +413 -0
  11. package/android/src/main/AndroidManifest.xml +3 -0
  12. package/android/src/main/AndroidManifestNew.xml +2 -0
  13. package/android/src/main/cpp/AudioAPIInstaller/AudioAPIInstaller.cpp +22 -0
  14. package/android/src/main/cpp/AudioAPIInstaller/AudioAPIInstaller.h +48 -0
  15. package/android/src/main/cpp/AudioPlayer/AudioPlayer.cpp +66 -0
  16. package/android/src/main/cpp/AudioPlayer/AudioPlayer.h +33 -0
  17. package/android/src/main/cpp/OnLoad.cpp +9 -0
  18. package/android/src/main/java/com/swmansion/audioapi/AudioAPIPackage.kt +14 -0
  19. package/android/src/main/java/com/swmansion/audioapi/module/AudioAPIInstaller.kt +21 -0
  20. package/android/src/main/java/com/swmansion/audioapi/nativemodules/AudioAPIModule.kt +25 -0
  21. package/common/cpp/AudioAPIInstaller/AudioAPIInstallerHostObject.cpp +52 -0
  22. package/common/cpp/AudioAPIInstaller/AudioAPIInstallerHostObject.h +45 -0
  23. package/common/cpp/AudioAPIInstaller/AudioAPIInstallerWrapper.h +38 -0
  24. package/common/cpp/AudioAPIInstaller/android/AudioAPIInstallerWrapper.cpp +16 -0
  25. package/common/cpp/AudioAPIInstaller/ios/AudioAPIInstallerWrapper.cpp +12 -0
  26. package/common/cpp/HostObjects/AudioBufferHostObject.cpp +143 -0
  27. package/common/cpp/HostObjects/AudioBufferHostObject.h +33 -0
  28. package/common/cpp/HostObjects/AudioBufferSourceNodeHostObject.cpp +79 -0
  29. package/common/cpp/HostObjects/AudioBufferSourceNodeHostObject.h +37 -0
  30. package/common/cpp/HostObjects/AudioContextHostObject.cpp +54 -0
  31. package/common/cpp/HostObjects/AudioContextHostObject.h +36 -0
  32. package/common/cpp/HostObjects/AudioDestinationNodeHostObject.cpp +33 -0
  33. package/common/cpp/HostObjects/AudioDestinationNodeHostObject.h +31 -0
  34. package/common/cpp/HostObjects/AudioNodeHostObject.cpp +102 -0
  35. package/common/cpp/HostObjects/AudioNodeHostObject.h +29 -0
  36. package/common/cpp/HostObjects/AudioParamHostObject.cpp +115 -0
  37. package/common/cpp/HostObjects/AudioParamHostObject.h +34 -0
  38. package/common/cpp/HostObjects/AudioScheduledSourceNodeHostObject.cpp +73 -0
  39. package/common/cpp/HostObjects/AudioScheduledSourceNodeHostObject.h +31 -0
  40. package/common/cpp/HostObjects/BaseAudioContextHostObject.cpp +214 -0
  41. package/common/cpp/HostObjects/BaseAudioContextHostObject.h +39 -0
  42. package/common/cpp/HostObjects/BiquadFilterNodeHostObject.cpp +125 -0
  43. package/common/cpp/HostObjects/BiquadFilterNodeHostObject.h +42 -0
  44. package/common/cpp/HostObjects/Constants.h +22 -0
  45. package/common/cpp/HostObjects/GainNodeHostObject.cpp +41 -0
  46. package/common/cpp/HostObjects/GainNodeHostObject.h +32 -0
  47. package/common/cpp/HostObjects/OscillatorNodeHostObject.cpp +88 -0
  48. package/common/cpp/HostObjects/OscillatorNodeHostObject.h +41 -0
  49. package/common/cpp/HostObjects/PeriodicWaveHostObject.cpp +33 -0
  50. package/common/cpp/HostObjects/PeriodicWaveHostObject.h +33 -0
  51. package/common/cpp/HostObjects/StereoPannerNodeHostObject.cpp +41 -0
  52. package/common/cpp/HostObjects/StereoPannerNodeHostObject.h +36 -0
  53. package/common/cpp/core/AudioArray.cpp +103 -0
  54. package/common/cpp/core/AudioArray.h +42 -0
  55. package/common/cpp/core/AudioBuffer.cpp +55 -0
  56. package/common/cpp/core/AudioBuffer.h +40 -0
  57. package/common/cpp/core/AudioBufferSourceNode.cpp +135 -0
  58. package/common/cpp/core/AudioBufferSourceNode.h +30 -0
  59. package/common/cpp/core/AudioBus.cpp +357 -0
  60. package/common/cpp/core/AudioBus.h +63 -0
  61. package/common/cpp/core/AudioContext.cpp +24 -0
  62. package/common/cpp/core/AudioContext.h +16 -0
  63. package/common/cpp/core/AudioDestinationNode.cpp +45 -0
  64. package/common/cpp/core/AudioDestinationNode.h +32 -0
  65. package/common/cpp/core/AudioNode.cpp +222 -0
  66. package/common/cpp/core/AudioNode.h +74 -0
  67. package/common/cpp/core/AudioNodeManager.cpp +72 -0
  68. package/common/cpp/core/AudioNodeManager.h +35 -0
  69. package/common/cpp/core/AudioParam.cpp +133 -0
  70. package/common/cpp/core/AudioParam.h +50 -0
  71. package/common/cpp/core/AudioScheduledSourceNode.cpp +53 -0
  72. package/common/cpp/core/AudioScheduledSourceNode.h +34 -0
  73. package/common/cpp/core/BaseAudioContext.cpp +157 -0
  74. package/common/cpp/core/BaseAudioContext.h +80 -0
  75. package/common/cpp/core/BiquadFilterNode.cpp +385 -0
  76. package/common/cpp/core/BiquadFilterNode.h +124 -0
  77. package/common/cpp/core/GainNode.cpp +30 -0
  78. package/common/cpp/core/GainNode.h +25 -0
  79. package/common/cpp/core/OscillatorNode.cpp +75 -0
  80. package/common/cpp/core/OscillatorNode.h +72 -0
  81. package/common/cpp/core/ParamChange.cpp +46 -0
  82. package/common/cpp/core/ParamChange.h +34 -0
  83. package/common/cpp/core/PeriodicWave.cpp +362 -0
  84. package/common/cpp/core/PeriodicWave.h +119 -0
  85. package/common/cpp/core/StereoPannerNode.cpp +56 -0
  86. package/common/cpp/core/StereoPannerNode.h +26 -0
  87. package/common/cpp/types/BiquadFilterType.h +19 -0
  88. package/common/cpp/types/ChannelCountMode.h +10 -0
  89. package/common/cpp/types/ChannelInterpretation.h +10 -0
  90. package/common/cpp/types/ContextState.h +10 -0
  91. package/common/cpp/types/OscillatorType.h +11 -0
  92. package/common/cpp/utils/FFTFrame.h +63 -0
  93. package/common/cpp/utils/Locker.h +47 -0
  94. package/common/cpp/utils/VectorMath.cpp +678 -0
  95. package/common/cpp/utils/VectorMath.h +71 -0
  96. package/common/cpp/utils/android/FFTFrame.cpp +22 -0
  97. package/common/cpp/utils/ios/FFTFrame.cpp +24 -0
  98. package/common/cpp/wrappers/AudioBufferSourceNodeWrapper.cpp +45 -0
  99. package/common/cpp/wrappers/AudioBufferSourceNodeWrapper.h +26 -0
  100. package/common/cpp/wrappers/AudioBufferWrapper.cpp +46 -0
  101. package/common/cpp/wrappers/AudioBufferWrapper.h +30 -0
  102. package/common/cpp/wrappers/AudioContextWrapper.cpp +17 -0
  103. package/common/cpp/wrappers/AudioContextWrapper.h +19 -0
  104. package/common/cpp/wrappers/AudioDestinationNodeWrapper.h +16 -0
  105. package/common/cpp/wrappers/AudioNodeWrapper.cpp +37 -0
  106. package/common/cpp/wrappers/AudioNodeWrapper.h +25 -0
  107. package/common/cpp/wrappers/AudioParamWrapper.cpp +42 -0
  108. package/common/cpp/wrappers/AudioParamWrapper.h +25 -0
  109. package/common/cpp/wrappers/AudioScheduledSourceNodeWrapper.cpp +23 -0
  110. package/common/cpp/wrappers/AudioScheduledSourceNodeWrapper.h +23 -0
  111. package/common/cpp/wrappers/BaseAudioContextWrapper.cpp +76 -0
  112. package/common/cpp/wrappers/BaseAudioContextWrapper.h +49 -0
  113. package/common/cpp/wrappers/BiquadFilterNodeWrapper.cpp +60 -0
  114. package/common/cpp/wrappers/BiquadFilterNodeWrapper.h +37 -0
  115. package/common/cpp/wrappers/GainNodeWrapper.cpp +14 -0
  116. package/common/cpp/wrappers/GainNodeWrapper.h +20 -0
  117. package/common/cpp/wrappers/OscillatorNodeWrapper.cpp +44 -0
  118. package/common/cpp/wrappers/OscillatorNodeWrapper.h +31 -0
  119. package/common/cpp/wrappers/PeriodicWaveWrapper.h +17 -0
  120. package/common/cpp/wrappers/StereoPannerNodeWrapper.cpp +16 -0
  121. package/common/cpp/wrappers/StereoPannerNodeWrapper.h +21 -0
  122. package/ios/AudioAPIModule.h +24 -0
  123. package/ios/AudioAPIModule.mm +44 -0
  124. package/ios/AudioPlayer/AudioPlayer.h +28 -0
  125. package/ios/AudioPlayer/AudioPlayer.m +119 -0
  126. package/ios/AudioPlayer/IOSAudioPlayer.h +33 -0
  127. package/ios/AudioPlayer/IOSAudioPlayer.mm +57 -0
  128. package/lib/module/core/AudioBuffer.js +37 -0
  129. package/lib/module/core/AudioBuffer.js.map +1 -0
  130. package/lib/module/core/AudioBufferSourceNode.js +28 -0
  131. package/lib/module/core/AudioBufferSourceNode.js.map +1 -0
  132. package/lib/module/core/AudioContext.js +10 -0
  133. package/lib/module/core/AudioContext.js.map +1 -0
  134. package/lib/module/core/AudioDestinationNode.js +7 -0
  135. package/lib/module/core/AudioDestinationNode.js.map +1 -0
  136. package/lib/module/core/AudioNode.js +22 -0
  137. package/lib/module/core/AudioNode.js.map +1 -0
  138. package/lib/module/core/AudioParam.js +35 -0
  139. package/lib/module/core/AudioParam.js.map +1 -0
  140. package/lib/module/core/AudioScheduledSourceNode.js +28 -0
  141. package/lib/module/core/AudioScheduledSourceNode.js.map +1 -0
  142. package/lib/module/core/BaseAudioContext.js +57 -0
  143. package/lib/module/core/BaseAudioContext.js.map +1 -0
  144. package/lib/module/core/BiquadFilterNode.js +25 -0
  145. package/lib/module/core/BiquadFilterNode.js.map +1 -0
  146. package/lib/module/core/GainNode.js +9 -0
  147. package/lib/module/core/GainNode.js.map +1 -0
  148. package/lib/module/core/OscillatorNode.js +24 -0
  149. package/lib/module/core/OscillatorNode.js.map +1 -0
  150. package/lib/module/core/PeriodicWave.js +8 -0
  151. package/lib/module/core/PeriodicWave.js.map +1 -0
  152. package/lib/module/core/StereoPannerNode.js +9 -0
  153. package/lib/module/core/StereoPannerNode.js.map +1 -0
  154. package/lib/module/core/types.js +2 -0
  155. package/lib/module/core/types.js.map +1 -0
  156. package/lib/module/errors/IndexSizeError.js +8 -0
  157. package/lib/module/errors/IndexSizeError.js.map +1 -0
  158. package/lib/module/errors/InvalidAccessError.js +8 -0
  159. package/lib/module/errors/InvalidAccessError.js.map +1 -0
  160. package/lib/module/errors/InvalidStateError.js +8 -0
  161. package/lib/module/errors/InvalidStateError.js.map +1 -0
  162. package/lib/module/errors/RangeError.js +8 -0
  163. package/lib/module/errors/RangeError.js.map +1 -0
  164. package/lib/module/errors/index.js +5 -0
  165. package/lib/module/errors/index.js.map +1 -0
  166. package/lib/module/index.js +18 -0
  167. package/lib/module/index.js.map +1 -0
  168. package/lib/module/interfaces.js +2 -0
  169. package/lib/module/interfaces.js.map +1 -0
  170. package/lib/module/modules/global.d.js +2 -0
  171. package/lib/module/modules/global.d.js.map +1 -0
  172. package/lib/module/utils/install.js +22 -0
  173. package/lib/module/utils/install.js.map +1 -0
  174. package/lib/typescript/core/AudioBuffer.d.ts +12 -0
  175. package/lib/typescript/core/AudioBuffer.d.ts.map +1 -0
  176. package/lib/typescript/core/AudioBufferSourceNode.d.ts +12 -0
  177. package/lib/typescript/core/AudioBufferSourceNode.d.ts.map +1 -0
  178. package/lib/typescript/core/AudioContext.d.ts +6 -0
  179. package/lib/typescript/core/AudioContext.d.ts.map +1 -0
  180. package/lib/typescript/core/AudioDestinationNode.d.ts +7 -0
  181. package/lib/typescript/core/AudioDestinationNode.d.ts.map +1 -0
  182. package/lib/typescript/core/AudioNode.d.ts +16 -0
  183. package/lib/typescript/core/AudioNode.d.ts.map +1 -0
  184. package/lib/typescript/core/AudioParam.d.ts +14 -0
  185. package/lib/typescript/core/AudioParam.d.ts.map +1 -0
  186. package/lib/typescript/core/AudioScheduledSourceNode.d.ts +10 -0
  187. package/lib/typescript/core/AudioScheduledSourceNode.d.ts.map +1 -0
  188. package/lib/typescript/core/BaseAudioContext.d.ts +26 -0
  189. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -0
  190. package/lib/typescript/core/BiquadFilterNode.d.ts +16 -0
  191. package/lib/typescript/core/BiquadFilterNode.d.ts.map +1 -0
  192. package/lib/typescript/core/GainNode.d.ts +9 -0
  193. package/lib/typescript/core/GainNode.d.ts.map +1 -0
  194. package/lib/typescript/core/OscillatorNode.d.ts +15 -0
  195. package/lib/typescript/core/OscillatorNode.d.ts.map +1 -0
  196. package/lib/typescript/core/PeriodicWave.d.ts +5 -0
  197. package/lib/typescript/core/PeriodicWave.d.ts.map +1 -0
  198. package/lib/typescript/core/StereoPannerNode.d.ts +9 -0
  199. package/lib/typescript/core/StereoPannerNode.d.ts.map +1 -0
  200. package/lib/typescript/core/types.d.ts +9 -0
  201. package/lib/typescript/core/types.d.ts.map +1 -0
  202. package/lib/typescript/errors/IndexSizeError.d.ts +5 -0
  203. package/lib/typescript/errors/IndexSizeError.d.ts.map +1 -0
  204. package/lib/typescript/errors/InvalidAccessError.d.ts +5 -0
  205. package/lib/typescript/errors/InvalidAccessError.d.ts.map +1 -0
  206. package/lib/typescript/errors/InvalidStateError.d.ts +5 -0
  207. package/lib/typescript/errors/InvalidStateError.d.ts.map +1 -0
  208. package/lib/typescript/errors/RangeError.d.ts +5 -0
  209. package/lib/typescript/errors/RangeError.d.ts.map +1 -0
  210. package/lib/typescript/errors/index.d.ts +5 -0
  211. package/lib/typescript/errors/index.d.ts.map +1 -0
  212. package/lib/typescript/index.d.ts +14 -0
  213. package/lib/typescript/index.d.ts.map +1 -0
  214. package/lib/typescript/interfaces.d.ts +78 -0
  215. package/lib/typescript/interfaces.d.ts.map +1 -0
  216. package/lib/typescript/utils/install.d.ts +7 -0
  217. package/lib/typescript/utils/install.d.ts.map +1 -0
  218. package/package.json +104 -5
  219. package/src/core/AudioBuffer.ts +68 -0
  220. package/src/core/AudioBufferSourceNode.ts +35 -0
  221. package/src/core/AudioContext.ts +12 -0
  222. package/src/core/AudioDestinationNode.ts +9 -0
  223. package/src/core/AudioNode.ts +38 -0
  224. package/src/core/AudioParam.ts +55 -0
  225. package/src/core/AudioScheduledSourceNode.ts +43 -0
  226. package/src/core/BaseAudioContext.ts +97 -0
  227. package/src/core/BiquadFilterNode.ts +49 -0
  228. package/src/core/GainNode.ts +13 -0
  229. package/src/core/OscillatorNode.ts +37 -0
  230. package/src/core/PeriodicWave.ts +10 -0
  231. package/src/core/StereoPannerNode.ts +13 -0
  232. package/src/core/types.ts +26 -0
  233. package/src/errors/IndexSizeError.ts +8 -0
  234. package/src/errors/InvalidAccessError.ts +8 -0
  235. package/src/errors/InvalidStateError.ts +8 -0
  236. package/src/errors/RangeError.ts +8 -0
  237. package/src/errors/index.ts +4 -0
  238. package/src/index.ts +25 -0
  239. package/src/interfaces.ts +120 -0
  240. package/src/modules/global.d.ts +10 -0
  241. package/src/utils/install.ts +39 -0
  242. package/index.ts +0 -1
@@ -0,0 +1,362 @@
1
+ /*
2
+ * Copyright (C) 2012 Google Inc. All rights reserved.
3
+ *
4
+ * Redistribution and use in source and binary forms, with or without
5
+ * modification, are permitted provided that the following conditions
6
+ * are met:
7
+ *
8
+ * 1. Redistributions of source code must retain the above copyright
9
+ * notice, this list of conditions and the following disclaimer.
10
+ * 2. Redistributions in binary form must reproduce the above copyright
11
+ * notice, this list of conditions and the following disclaimer in the
12
+ * documentation and/or other materials provided with the distribution.
13
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
14
+ * its contributors may be used to endorse or promote products derived
15
+ * from this software without specific prior written permission.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ */
28
+
29
+ #include "PeriodicWave.h"
30
+
31
+ constexpr unsigned NumberOfOctaveBands = 3;
32
+ constexpr float CentsPerRange = 1200.0f / NumberOfOctaveBands;
33
+ constexpr float interpolate2Point = 0.3;
34
+ constexpr float interpolate3Point = 0.16;
35
+
36
+ namespace audioapi {
37
+ PeriodicWave::PeriodicWave(int sampleRate, bool disableNormalization)
38
+ : sampleRate_(sampleRate), disableNormalization_(disableNormalization) {
39
+ numberOfRanges_ = lround(
40
+ NumberOfOctaveBands * log2f(static_cast<float>(getPeriodicWaveSize())));
41
+ auto nyquistFrequency = sampleRate_ / 2;
42
+ lowestFundamentalFrequency_ = static_cast<float>(nyquistFrequency) /
43
+ static_cast<float>(getMaxNumberOfPartials());
44
+ scale_ = static_cast<float>(getPeriodicWaveSize()) /
45
+ static_cast<float>(sampleRate_);
46
+ bandLimitedTables_ = new float *[numberOfRanges_];
47
+ }
48
+
49
+ PeriodicWave::PeriodicWave(
50
+ int sampleRate,
51
+ audioapi::OscillatorType type,
52
+ bool disableNormalization)
53
+ : PeriodicWave(sampleRate, disableNormalization) {
54
+ this->generateBasicWaveForm(type);
55
+ }
56
+
57
+ PeriodicWave::PeriodicWave(
58
+ int sampleRate,
59
+ float *real,
60
+ float *imaginary,
61
+ int length,
62
+ bool disableNormalization)
63
+ : PeriodicWave(sampleRate, disableNormalization) {
64
+ createBandLimitedTables(real, imaginary, length);
65
+ }
66
+
67
+ int PeriodicWave::getPeriodicWaveSize() const {
68
+ if (sampleRate_ <= 24000) {
69
+ return 2048;
70
+ }
71
+
72
+ if (sampleRate_ <= 88200) {
73
+ return 4096;
74
+ }
75
+
76
+ return 16384;
77
+ }
78
+
79
+ float PeriodicWave::getScale() const {
80
+ return scale_;
81
+ }
82
+
83
+ float PeriodicWave::getSample(
84
+ float fundamentalFrequency,
85
+ float phase,
86
+ float phaseIncrement) {
87
+ float *lowerWaveData = nullptr;
88
+ float *higherWaveData = nullptr;
89
+
90
+ auto interpolationFactor = getWaveDataForFundamentalFrequency(
91
+ fundamentalFrequency, lowerWaveData, higherWaveData);
92
+
93
+ return doInterpolation(
94
+ phase,
95
+ phaseIncrement,
96
+ interpolationFactor,
97
+ lowerWaveData,
98
+ higherWaveData);
99
+ }
100
+
101
+ int PeriodicWave::getMaxNumberOfPartials() const {
102
+ return getPeriodicWaveSize() / 2;
103
+ }
104
+
105
+ int PeriodicWave::getNumberOfPartialsPerRange(int rangeIndex) const {
106
+ // Number of cents below nyquist where we cull partials.
107
+ auto centsToCull = static_cast<float>(rangeIndex) * CentsPerRange;
108
+
109
+ // A value from 0 -> 1 representing what fraction of the partials to keep.
110
+ auto cullingScale = std::powf(2, -centsToCull / 1200);
111
+
112
+ // The very top range will have all the partials culled.
113
+ int numberOfPartials =
114
+ floor(static_cast<float>(getMaxNumberOfPartials()) * cullingScale);
115
+
116
+ return numberOfPartials;
117
+ }
118
+
119
+ void PeriodicWave::generateBasicWaveForm(OscillatorType type) {
120
+ auto fftSize = getPeriodicWaveSize();
121
+ /*
122
+ * For real-valued time-domain signals, the FFT outputs a Hermitian symmetric
123
+ * sequence (where the positive frequencies are the complex conjugate of the
124
+ * negative ones). This symmetry implies that real signals have mirrored
125
+ * frequency components. In such scenarios, all 'real' frequency information
126
+ * is contained in the first half of the transform, and altering parts such as
127
+ * real and imaginary can finely shape which harmonic content is retained or
128
+ * discarded.
129
+ */
130
+ auto halfSize = fftSize / 2;
131
+
132
+ auto *real = new float[halfSize];
133
+ auto *imaginary = new float[halfSize];
134
+
135
+ // Reset Direct Current (DC) component. First element of frequency domain
136
+ // representation - c0. https://math24.net/complex-form-fourier-series.html
137
+ real[0] = 0.0f;
138
+ imaginary[0] = 0.0f;
139
+
140
+ for (int i = 1; i < halfSize; i++) {
141
+ // All waveforms are odd functions with a positive slope at time 0.
142
+ // Hence the coefficients for cos() are always 0.
143
+
144
+ // Formulas for Fourier coefficients:
145
+ // https://mathworld.wolfram.com/FourierSeries.html
146
+
147
+ // Coefficient for sin()
148
+ float b;
149
+
150
+ auto piFactor = static_cast<float>(1.0f / (i * M_PI));
151
+
152
+ switch (type) {
153
+ case OscillatorType::SINE:
154
+ b = (i == 1) ? 1.0f : 0.0f;
155
+ break;
156
+ case OscillatorType::SQUARE:
157
+ // https://mathworld.wolfram.com/FourierSeriesSquareWave.html
158
+ b = ((i & 1) == 1) ? 4 * piFactor : 0.0f;
159
+ break;
160
+ case OscillatorType::SAWTOOTH:
161
+ // https://mathworld.wolfram.com/FourierSeriesSawtoothWave.html - our
162
+ // Function differs from this one, but coefficients calculation looks
163
+ // similar. our function - f(x) = 2(x / (2 * pi) - floor(x / (2 * pi) +
164
+ // 0.5)));
165
+ // https://www.wolframalpha.com/input?i=2%28x+%2F+%282+*+pi%29+-+floor%28x+%2F+%282+*+pi%29+%2B+0.5%29%29%29%3B
166
+ b = 2 * piFactor * ((i & 1) == 1 ? 1.0f : -1.0f);
167
+ break;
168
+ case OscillatorType::TRIANGLE:
169
+ // https://mathworld.wolfram.com/FourierSeriesTriangleWave.html
170
+ if ((i & 1) == 1) {
171
+ b = 8.0f * piFactor * piFactor * ((i & 3) == 1 ? 1.0f : -1.0f);
172
+ } else {
173
+ b = 0.0f;
174
+ }
175
+ break;
176
+ case OscillatorType::CUSTOM:
177
+ throw std::invalid_argument("Custom waveforms are not supported.");
178
+ }
179
+
180
+ real[i] = 0.0f;
181
+ imaginary[i] = b;
182
+ }
183
+
184
+ createBandLimitedTables(real, imaginary, halfSize);
185
+ }
186
+
187
+ void PeriodicWave::createBandLimitedTables(
188
+ const float *realData,
189
+ const float *imaginaryData,
190
+ int size) {
191
+ float normalizationFactor = 0.5f;
192
+
193
+ auto fftSize = getPeriodicWaveSize();
194
+ auto halfSize = fftSize / 2;
195
+
196
+ size = std::min(size, halfSize);
197
+
198
+ for (int rangeIndex = 0; rangeIndex < numberOfRanges_; rangeIndex++) {
199
+ FFTFrame fftFrame(fftSize);
200
+
201
+ auto *realFFTFrameData = fftFrame.getRealData();
202
+ auto *imaginaryFFTFrameData = fftFrame.getImaginaryData();
203
+
204
+ // copy real and imaginary data to the FFT frame and scale it
205
+ VectorMath::multiplyByScalar(
206
+ realData, static_cast<float>(fftSize), realFFTFrameData, size);
207
+ VectorMath::multiplyByScalar(
208
+ imaginaryData,
209
+ -static_cast<float>(fftSize),
210
+ imaginaryFFTFrameData,
211
+ size);
212
+
213
+ // Find the starting partial where we should start culling.
214
+ // We need to clear out the highest frequencies to band-limit the waveform.
215
+ auto numberOfPartials = getNumberOfPartialsPerRange(rangeIndex);
216
+
217
+ // Clamp the size to the number of partials.
218
+ auto clampedSize = std::min(size, numberOfPartials);
219
+ if (clampedSize < halfSize) {
220
+ // Zero out the higher frequencies for certain range.
221
+ std::fill(
222
+ realFFTFrameData + clampedSize, realFFTFrameData + halfSize, 0.0f);
223
+ std::fill(
224
+ imaginaryFFTFrameData + clampedSize,
225
+ imaginaryFFTFrameData + halfSize,
226
+ 0.0f);
227
+ }
228
+
229
+ // Zero out the nquist and DC components.
230
+ realFFTFrameData[0] = 0.0f;
231
+ imaginaryFFTFrameData[0] = 0.0f;
232
+
233
+ bandLimitedTables_[rangeIndex] = new float[fftSize];
234
+
235
+ // Perform the inverse FFT to get the time domain representation of the
236
+ // band-limited waveform.
237
+ fftFrame.inverse(bandLimitedTables_[rangeIndex]);
238
+
239
+ if (!disableNormalization_ && rangeIndex == 0) {
240
+ float maxValue =
241
+ VectorMath::maximumMagnitude(bandLimitedTables_[rangeIndex], fftSize);
242
+ if (maxValue != 0) {
243
+ normalizationFactor = 1.0f / maxValue;
244
+ }
245
+ }
246
+
247
+ VectorMath::multiplyByScalar(
248
+ bandLimitedTables_[rangeIndex],
249
+ normalizationFactor,
250
+ bandLimitedTables_[rangeIndex],
251
+ fftSize);
252
+ }
253
+ }
254
+
255
+ float PeriodicWave::getWaveDataForFundamentalFrequency(
256
+ float fundamentalFrequency,
257
+ float *&lowerWaveData,
258
+ float *&higherWaveData) {
259
+ // negative frequencies are allowed and will be treated as positive.
260
+ fundamentalFrequency = std::fabs(fundamentalFrequency);
261
+
262
+ // calculating lower and higher range index for the given fundamental
263
+ // frequency.
264
+ float ratio = fundamentalFrequency > 0
265
+ ? fundamentalFrequency / lowestFundamentalFrequency_
266
+ : 0.5f;
267
+ float centsAboveLowestFrequency = log2f(ratio) * 1200;
268
+
269
+ float pitchRange = 1 + centsAboveLowestFrequency / CentsPerRange;
270
+
271
+ pitchRange =
272
+ std::clamp(pitchRange, 0.0f, static_cast<float>(numberOfRanges_ - 1));
273
+
274
+ int lowerRangeIndex = static_cast<int>(pitchRange);
275
+ int higherRangeIndex = lowerRangeIndex < numberOfRanges_ - 1
276
+ ? lowerRangeIndex + 1
277
+ : lowerRangeIndex;
278
+
279
+ // get the wave data for the lower and higher range index.
280
+ lowerWaveData = bandLimitedTables_[lowerRangeIndex];
281
+ higherWaveData = bandLimitedTables_[higherRangeIndex];
282
+
283
+ // calculate the interpolation factor between the lower and higher range data.
284
+ return pitchRange - static_cast<float>(lowerRangeIndex);
285
+ }
286
+
287
+ float PeriodicWave::doInterpolation(
288
+ float phase,
289
+ float phaseIncrement,
290
+ float waveTableInterpolationFactor,
291
+ const float *lowerWaveData,
292
+ const float *higherWaveData) const {
293
+ float lowerWaveDataSample = 0;
294
+ float higherWaveDataSample = 0;
295
+
296
+ // We use linear, 3-point Lagrange, or 5-point Lagrange interpolation based on
297
+ // the value of phase increment. https://dlmf.nist.gov/3.3#ii
298
+
299
+ int index = static_cast<int>(phase);
300
+ auto factor = phase - static_cast<float>(index);
301
+
302
+ if (phaseIncrement >= interpolate2Point) { // linear interpolation
303
+ int indices[2];
304
+
305
+ for (int i = 0; i < 2; i++) {
306
+ indices[i] = (index + i) &
307
+ (getPeriodicWaveSize() -
308
+ 1); // more efficient alternative to % getPeriodicWaveSize()
309
+ }
310
+
311
+ auto lowerWaveDataSample1 = lowerWaveData[indices[0]];
312
+ auto lowerWaveDataSample2 = lowerWaveData[indices[1]];
313
+ auto higherWaveDataSample1 = higherWaveData[indices[0]];
314
+ auto higherWaveDataSample2 = higherWaveData[indices[1]];
315
+
316
+ lowerWaveDataSample =
317
+ (1 - factor) * lowerWaveDataSample1 + factor * lowerWaveDataSample2;
318
+ higherWaveDataSample =
319
+ (1 - factor) * higherWaveDataSample1 + factor * higherWaveDataSample2;
320
+ } else if (phaseIncrement >= interpolate3Point) { // 3-point Lagrange
321
+ // interpolation
322
+ int indices[3];
323
+
324
+ for (int i = 0; i < 3; i++) {
325
+ indices[i] = (index + i - 1) & (getPeriodicWaveSize() - 1);
326
+ }
327
+
328
+ float A[3];
329
+
330
+ A[0] = factor * (factor - 1) / 2;
331
+ A[1] = 1 - factor * factor;
332
+ A[2] = factor * (factor + 1) / 2;
333
+
334
+ for (int i = 0; i < 3; i++) {
335
+ lowerWaveDataSample += lowerWaveData[indices[i]] * A[i];
336
+ higherWaveDataSample += higherWaveData[indices[i]] * A[i];
337
+ }
338
+ } else { // 5-point Lagrange interpolation
339
+ int indices[5];
340
+
341
+ for (int i = 0; i < 5; i++) {
342
+ indices[i] = (index + i - 2) & (getPeriodicWaveSize() - 1);
343
+ }
344
+
345
+ float A[5];
346
+
347
+ A[0] = factor * (factor * factor - 1) * (factor - 2) / 24;
348
+ A[1] = -factor * (factor - 1) * (factor * factor - 4) / 6;
349
+ A[2] = (factor * factor - 1) * (factor * factor - 4) / 4;
350
+ A[3] = -factor * (factor + 1) * (factor * factor - 4) / 6;
351
+ A[4] = factor * (factor * factor - 1) * (factor + 2) / 24;
352
+
353
+ for (int i = 0; i < 5; i++) {
354
+ lowerWaveDataSample += lowerWaveData[indices[i]] * A[i];
355
+ higherWaveDataSample += higherWaveData[indices[i]] * A[i];
356
+ }
357
+ }
358
+
359
+ return (1 - waveTableInterpolationFactor) * higherWaveDataSample +
360
+ waveTableInterpolationFactor * lowerWaveDataSample;
361
+ }
362
+ } // namespace audioapi
@@ -0,0 +1,119 @@
1
+ /*
2
+ * Copyright (C) 2012 Google Inc. All rights reserved.
3
+ *
4
+ * Redistribution and use in source and binary forms, with or without
5
+ * modification, are permitted provided that the following conditions
6
+ * are met:
7
+ *
8
+ * 1. Redistributions of source code must retain the above copyright
9
+ * notice, this list of conditions and the following disclaimer.
10
+ * 2. Redistributions in binary form must reproduce the above copyright
11
+ * notice, this list of conditions and the following disclaimer in the
12
+ * documentation and/or other materials provided with the distribution.
13
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
14
+ * its contributors may be used to endorse or promote products derived
15
+ * from this software without specific prior written permission.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ */
28
+
29
+ #pragma once
30
+
31
+ #include <algorithm>
32
+ #include <cmath>
33
+ #include <memory>
34
+
35
+ #include "FFTFrame.h"
36
+ #include "OscillatorType.h"
37
+ #include "VectorMath.h"
38
+
39
+ namespace audioapi {
40
+ class PeriodicWave {
41
+ public:
42
+ explicit PeriodicWave(
43
+ int sampleRate,
44
+ OscillatorType type,
45
+ bool disableNormalization);
46
+ explicit PeriodicWave(
47
+ int sampleRate,
48
+ float *real,
49
+ float *imaginary,
50
+ int length,
51
+ bool disableNormalization);
52
+
53
+ [[nodiscard]] int getPeriodicWaveSize() const;
54
+ [[nodiscard]] float getScale() const;
55
+
56
+ float
57
+ getSample(float fundamentalFrequency, float phase, float phaseIncrement);
58
+
59
+ private:
60
+ explicit PeriodicWave(int sampleRate, bool disableNormalization);
61
+
62
+ // Partial is any frequency component of a sound.
63
+ // Both harmonics(fundamentalFrequency * k) and overtones are partials.
64
+ [[nodiscard]] int getMaxNumberOfPartials() const;
65
+
66
+ // Returns the number of partials to keep for a given range.
67
+ // Controlling the number of partials in each range allows for a more
68
+ // efficient representation of the waveform and prevents aliasing.
69
+ [[nodiscard]] int getNumberOfPartialsPerRange(int rangeIndex) const;
70
+
71
+ // This function generates real and imaginary parts of the waveTable,
72
+ // real and imaginary arrays represent the coefficients of the harmonic
73
+ // components in the frequency domain, specifically as part of a complex
74
+ // representation used by Fourier Transform methods to describe signals.
75
+ void generateBasicWaveForm(OscillatorType type);
76
+
77
+ // This function creates band-limited tables for the given real and
78
+ // imaginary data. The tables are created for each range of the partials.
79
+ // The higher frequencies are culled to band-limit the waveform.
80
+ // For each range, the inverse FFT is performed to get the time domain
81
+ // representation of the band-limited waveform.
82
+ void
83
+ createBandLimitedTables(const float *real, const float *imaginary, int size);
84
+
85
+ // This function returns the interpolation factor between the lower and higher
86
+ // range data and sets the lower and higher wave data for the given
87
+ // fundamental frequency.
88
+ float getWaveDataForFundamentalFrequency(
89
+ float fundamentalFrequency,
90
+ float *&lowerWaveData,
91
+ float *&higherWaveData);
92
+
93
+ // This function performs interpolation between the lower and higher range
94
+ // data based on the interpolation factor and current buffer index. Type of
95
+ // interpolation is determined by the phase increment. Returns the
96
+ // interpolated sample.
97
+ float doInterpolation(
98
+ float bufferIndex,
99
+ float phaseIncrement,
100
+ float waveTableInterpolationFactor,
101
+ const float *lowerWaveData,
102
+ const float *higherWaveData) const;
103
+
104
+ // determines the time resolution of the waveform.
105
+ int sampleRate_;
106
+ // determines number of frequency segments (or bands) the signal is divided.
107
+ int numberOfRanges_;
108
+ // the lowest frequency (in hertz) where playback will include all of the
109
+ // partials.
110
+ float lowestFundamentalFrequency_;
111
+ // scaling factor used to adjust size of period of waveform to the sample
112
+ // rate.
113
+ float scale_;
114
+ // array of band-limited waveforms.
115
+ float **bandLimitedTables_;
116
+ // if true, the waveTable is not normalized.
117
+ bool disableNormalization_;
118
+ };
119
+ } // namespace audioapi
@@ -0,0 +1,56 @@
1
+ #include "AudioBus.h"
2
+ #include "Constants.h"
3
+ #include "AudioArray.h"
4
+ #include "StereoPannerNode.h"
5
+ #include "BaseAudioContext.h"
6
+
7
+ // https://webaudio.github.io/web-audio-api/#stereopanner-algorithm
8
+
9
+ namespace audioapi {
10
+
11
+ StereoPannerNode::StereoPannerNode(BaseAudioContext *context)
12
+ : AudioNode(context) {
13
+ channelCountMode_ = ChannelCountMode::CLAMPED_MAX;
14
+ panParam_ = std::make_shared<AudioParam>(context, 0.0, -MAX_PAN, MAX_PAN);
15
+ isInitialized_ = true;
16
+ }
17
+
18
+ std::shared_ptr<AudioParam> StereoPannerNode::getPanParam() const {
19
+ return panParam_;
20
+ }
21
+
22
+ void StereoPannerNode::processNode(AudioBus* processingBus, int framesToProcess) {
23
+ // TODO: Currently assumed channelCount is 2
24
+ // it should:
25
+ // - support mono-channel buses
26
+ // - throw errors when trying to setup stereo panner with more than 2 channels
27
+
28
+ double time = context_->getCurrentTime();
29
+ double deltaTime = 1.0 / context_->getSampleRate();
30
+
31
+ AudioArray* left = processingBus->getChannelByType(AudioBus::ChannelLeft);
32
+ AudioArray* right = processingBus->getChannelByType(AudioBus::ChannelRight);
33
+
34
+ for (int i = 0; i < framesToProcess; i += 1) {
35
+ float pan = panParam_->getValueAtTime(time);
36
+ float x = (pan <= 0 ? pan + 1 : pan) * M_PI / 2;
37
+
38
+ float gainL = static_cast<float>(cos(x));
39
+ float gainR = static_cast<float>(sin(x));
40
+
41
+ float inputL = (*left)[i];
42
+ float inputR = (*right)[i];
43
+
44
+ if (pan <= 0) {
45
+ (*left)[i] = inputL + inputR * gainL;
46
+ (*right)[i] = inputR * gainR;
47
+ } else {
48
+ (*left)[i] = inputL * gainL;
49
+ (*right)[i] = inputR + inputL * gainR;
50
+ }
51
+
52
+ time += deltaTime;
53
+ }
54
+ }
55
+
56
+ } // namespace audioapi
@@ -0,0 +1,26 @@
1
+ #pragma once
2
+
3
+ #include <algorithm>
4
+ #include <memory>
5
+
6
+ #include "AudioNode.h"
7
+ #include "AudioParam.h"
8
+
9
+ namespace audioapi {
10
+
11
+ class AudioBus;
12
+
13
+ class StereoPannerNode : public AudioNode {
14
+ public:
15
+ explicit StereoPannerNode(BaseAudioContext *context);
16
+
17
+ [[nodiscard]] std::shared_ptr<AudioParam> getPanParam() const;
18
+
19
+ protected:
20
+ void processNode(AudioBus* processingBus, int framesToProcess) override;
21
+
22
+ private:
23
+ std::shared_ptr<AudioParam> panParam_;
24
+ };
25
+
26
+ } // namespace audioapi
@@ -0,0 +1,19 @@
1
+ #pragma once
2
+
3
+ #include <algorithm>
4
+ #include <stdexcept>
5
+ #include <string>
6
+
7
+ namespace audioapi {
8
+
9
+ enum class BiquadFilterType {
10
+ LOWPASS,
11
+ HIGHPASS,
12
+ BANDPASS,
13
+ LOWSHELF,
14
+ HIGHSHELF,
15
+ PEAKING,
16
+ NOTCH,
17
+ ALLPASS
18
+ };
19
+ } // namespace audioapi
@@ -0,0 +1,10 @@
1
+ #pragma once
2
+
3
+ #include <stdexcept>
4
+ #include <string>
5
+
6
+ namespace audioapi {
7
+
8
+ enum class ChannelCountMode { MAX, CLAMPED_MAX, EXPLICIT };
9
+
10
+ }
@@ -0,0 +1,10 @@
1
+ #pragma once
2
+
3
+ #include <stdexcept>
4
+ #include <string>
5
+
6
+ namespace audioapi {
7
+
8
+ enum class ChannelInterpretation { SPEAKERS, DISCRETE };
9
+
10
+ }
@@ -0,0 +1,10 @@
1
+ #pragma once
2
+
3
+ #include <stdexcept>
4
+ #include <string>
5
+
6
+ namespace audioapi {
7
+
8
+ enum class ContextState { SUSPENDED, RUNNING, CLOSED };
9
+
10
+ }
@@ -0,0 +1,11 @@
1
+ #pragma once
2
+
3
+ #include <algorithm>
4
+ #include <stdexcept>
5
+ #include <string>
6
+
7
+ namespace audioapi {
8
+
9
+ enum class OscillatorType { SINE, SQUARE, SAWTOOTH, TRIANGLE, CUSTOM };
10
+
11
+ } // namespace audioapi
@@ -0,0 +1,63 @@
1
+ /*
2
+ * Copyright (C) 2010 Google Inc. All rights reserved.
3
+ *
4
+ * Redistribution and use in source and binary forms, with or without
5
+ * modification, are permitted provided that the following conditions
6
+ * are met:
7
+ *
8
+ * 1. Redistributions of source code must retain the above copyright
9
+ * notice, this list of conditions and the following disclaimer.
10
+ * 2. Redistributions in binary form must reproduce the above copyright
11
+ * notice, this list of conditions and the following disclaimer in the
12
+ * documentation and/or other materials provided with the distribution.
13
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
14
+ * its contributors may be used to endorse or promote products derived
15
+ * from this software without specific prior written permission.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ */
28
+
29
+ #pragma once
30
+
31
+ #include <algorithm>
32
+ #include <cmath>
33
+ #include <utility>
34
+
35
+ #include "VectorMath.h"
36
+
37
+ namespace audioapi {
38
+
39
+ class FFTFrame {
40
+ public:
41
+ explicit FFTFrame(int size): size_(size), log2Size_(static_cast<int>(log2(size))), realData_(new float[size]), imaginaryData_(new float[size]) {}
42
+ ~FFTFrame() {
43
+ delete[] realData_;
44
+ delete[] imaginaryData_;
45
+ }
46
+
47
+ [[nodiscard]] float *getRealData() const {
48
+ return realData_;
49
+ }
50
+ [[nodiscard]] float *getImaginaryData() const {
51
+ return imaginaryData_;
52
+ }
53
+
54
+ void inverse(float *data);
55
+
56
+ private:
57
+ int size_;
58
+ int log2Size_;
59
+ float *realData_;
60
+ float *imaginaryData_;
61
+ };
62
+
63
+ } // namespace audioapi