react-native-audio-api 0.4.11 → 0.4.12-beta.2

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 (128) hide show
  1. package/RNAudioAPI.podspec +11 -1
  2. package/android/CMakeLists.txt +9 -48
  3. package/android/src/main/cpp/audioapi/CMakeLists.txt +44 -0
  4. package/android/src/main/cpp/{AudioAPIModule.cpp → audioapi/android/AudioAPIModule.cpp} +1 -4
  5. package/android/src/main/cpp/{AudioAPIModule.h → audioapi/android/AudioAPIModule.h} +2 -1
  6. package/android/src/main/cpp/{OnLoad.cpp → audioapi/android/OnLoad.cpp} +2 -1
  7. package/android/src/main/cpp/{core → audioapi/android/core}/AudioDecoder.cpp +5 -5
  8. package/android/src/main/cpp/{core → audioapi/android/core}/AudioPlayer.cpp +5 -7
  9. package/android/src/main/cpp/{core → audioapi/android/core}/AudioPlayer.h +1 -0
  10. package/android/src/main/cpp/{libs → audioapi/android/libs}/pffft.c +2 -2
  11. package/android/src/main/java/com/swmansion/audioapi/AudioAPIPackage.kt +1 -0
  12. package/common/cpp/{installer → audioapi}/AudioAPIModuleInstaller.h +9 -7
  13. package/common/cpp/{HostObjects → audioapi/HostObjects}/AnalyserNodeHostObject.h +3 -3
  14. package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioBufferHostObject.h +3 -3
  15. package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioBufferSourceNodeHostObject.h +6 -7
  16. package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioContextHostObject.h +3 -3
  17. package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioDestinationNodeHostObject.h +3 -3
  18. package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioNodeHostObject.h +3 -3
  19. package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioParamHostObject.h +3 -3
  20. package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioScheduledSourceNodeHostObject.h +3 -3
  21. package/common/cpp/{HostObjects → audioapi/HostObjects}/BaseAudioContextHostObject.h +21 -14
  22. package/common/cpp/{HostObjects → audioapi/HostObjects}/BiquadFilterNodeHostObject.h +4 -4
  23. package/common/cpp/{HostObjects → audioapi/HostObjects}/GainNodeHostObject.h +6 -6
  24. package/common/cpp/{HostObjects → audioapi/HostObjects}/OscillatorNodeHostObject.h +5 -5
  25. package/common/cpp/{HostObjects → audioapi/HostObjects}/PeriodicWaveHostObject.h +2 -2
  26. package/common/cpp/{HostObjects → audioapi/HostObjects}/StereoPannerNodeHostObject.h +4 -4
  27. package/common/cpp/audioapi/HostObjects/StretcherNodeHostObject.h +35 -0
  28. package/common/cpp/{core → audioapi/core}/AudioContext.cpp +6 -6
  29. package/common/cpp/{core → audioapi/core}/AudioContext.h +2 -2
  30. package/common/cpp/{core → audioapi/core}/AudioNode.cpp +14 -12
  31. package/common/cpp/{core → audioapi/core}/AudioNode.h +9 -6
  32. package/common/cpp/{core → audioapi/core}/AudioParam.cpp +3 -4
  33. package/common/cpp/{core → audioapi/core}/AudioParam.h +3 -3
  34. package/common/cpp/{core → audioapi/core}/BaseAudioContext.cpp +20 -16
  35. package/common/cpp/{core → audioapi/core}/BaseAudioContext.h +6 -3
  36. package/common/cpp/{core → audioapi/core/analysis}/AnalyserNode.cpp +6 -10
  37. package/common/cpp/{core → audioapi/core/analysis}/AnalyserNode.h +4 -3
  38. package/common/cpp/{core → audioapi/core/destinations}/AudioDestinationNode.cpp +6 -6
  39. package/common/cpp/{core → audioapi/core/destinations}/AudioDestinationNode.h +2 -2
  40. package/common/cpp/{core → audioapi/core/effects}/BiquadFilterNode.cpp +4 -4
  41. package/common/cpp/{core → audioapi/core/effects}/BiquadFilterNode.h +4 -4
  42. package/common/cpp/{core → audioapi/core/effects}/GainNode.cpp +4 -4
  43. package/common/cpp/{core → audioapi/core/effects}/GainNode.h +3 -3
  44. package/common/cpp/{core → audioapi/core/effects}/PeriodicWave.cpp +4 -2
  45. package/common/cpp/{core → audioapi/core/effects}/PeriodicWave.h +2 -4
  46. package/common/cpp/{core → audioapi/core/effects}/StereoPannerNode.cpp +5 -7
  47. package/common/cpp/{core → audioapi/core/effects}/StereoPannerNode.h +4 -3
  48. package/common/cpp/audioapi/core/effects/StretcherNode.cpp +94 -0
  49. package/common/cpp/audioapi/core/effects/StretcherNode.h +35 -0
  50. package/common/cpp/{core → audioapi/core/sources}/AudioBuffer.cpp +3 -3
  51. package/common/cpp/{core → audioapi/core/sources}/AudioBufferSourceNode.cpp +8 -11
  52. package/common/cpp/{core → audioapi/core/sources}/AudioBufferSourceNode.h +5 -3
  53. package/common/cpp/{core → audioapi/core/sources}/AudioScheduledSourceNode.cpp +6 -8
  54. package/common/cpp/{core → audioapi/core/sources}/AudioScheduledSourceNode.h +3 -2
  55. package/common/cpp/{core → audioapi/core/sources}/OscillatorNode.cpp +4 -4
  56. package/common/cpp/{core → audioapi/core/sources}/OscillatorNode.h +5 -5
  57. package/common/cpp/{core → audioapi/core/utils}/AudioArray.cpp +2 -4
  58. package/common/cpp/{core → audioapi/core/utils}/AudioBus.cpp +12 -7
  59. package/common/cpp/{core → audioapi/core/utils}/AudioBus.h +5 -2
  60. package/common/cpp/{core → audioapi/core/utils}/AudioNodeManager.cpp +3 -4
  61. package/common/cpp/{core → audioapi/core/utils}/ParamChangeEvent.cpp +1 -3
  62. package/common/cpp/{core → audioapi/core/utils}/ParamChangeEvent.h +3 -1
  63. package/common/cpp/{utils → audioapi/dsp}/AudioUtils.cpp +1 -1
  64. package/common/cpp/{utils → audioapi/dsp}/FFTFrame.cpp +1 -10
  65. package/common/cpp/{utils → audioapi/dsp}/FFTFrame.h +4 -3
  66. package/common/cpp/{utils → audioapi/dsp}/VectorMath.cpp +2 -5
  67. package/common/cpp/{utils → audioapi/dsp}/VectorMath.h +2 -0
  68. package/common/cpp/{jsi → audioapi/jsi}/JsiHostObject.cpp +1 -1
  69. package/common/cpp/{jsi → audioapi/jsi}/JsiHostObject.h +2 -2
  70. package/common/cpp/{jsi → audioapi/jsi}/JsiPromise.cpp +2 -6
  71. package/common/cpp/{jsi → audioapi/jsi}/RuntimeAwareCache.h +2 -3
  72. package/common/cpp/{jsi → audioapi/jsi}/RuntimeLifecycleMonitor.cpp +1 -5
  73. package/common/cpp/{jsi → audioapi/jsi}/RuntimeLifecycleMonitor.h +3 -0
  74. package/common/cpp/audioapi/libs/dsp/common.h +47 -0
  75. package/common/cpp/audioapi/libs/dsp/delay.h +717 -0
  76. package/common/cpp/audioapi/libs/dsp/fft.h +523 -0
  77. package/common/cpp/audioapi/libs/dsp/perf.h +84 -0
  78. package/common/cpp/audioapi/libs/dsp/spectral.h +496 -0
  79. package/common/cpp/audioapi/libs/dsp/windows.h +219 -0
  80. package/common/cpp/audioapi/libs/signalsmith-stretch.h +637 -0
  81. package/ios/{AudioAPIModule.mm → audioapi/ios/AudioAPIModule.mm} +1 -1
  82. package/ios/{core → audioapi/ios/core}/AudioDecoder.mm +4 -4
  83. package/ios/{core → audioapi/ios/core}/AudioPlayer.m +3 -3
  84. package/ios/{core → audioapi/ios/core}/IOSAudioPlayer.mm +4 -4
  85. package/lib/module/core/BaseAudioContext.js +4 -0
  86. package/lib/module/core/BaseAudioContext.js.map +1 -1
  87. package/lib/module/core/StretcherNode.js +12 -0
  88. package/lib/module/core/StretcherNode.js.map +1 -0
  89. package/lib/module/index.js +1 -0
  90. package/lib/module/index.js.map +1 -1
  91. package/lib/module/index.web.js +1 -1
  92. package/lib/module/index.web.js.map +1 -1
  93. package/lib/typescript/core/BaseAudioContext.d.ts +2 -0
  94. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  95. package/lib/typescript/core/StretcherNode.d.ts +10 -0
  96. package/lib/typescript/core/StretcherNode.d.ts.map +1 -0
  97. package/lib/typescript/index.d.ts +1 -0
  98. package/lib/typescript/index.d.ts.map +1 -1
  99. package/lib/typescript/index.web.d.ts +1 -1
  100. package/lib/typescript/index.web.d.ts.map +1 -1
  101. package/lib/typescript/interfaces.d.ts +5 -0
  102. package/lib/typescript/interfaces.d.ts.map +1 -1
  103. package/package.json +6 -6
  104. package/src/core/BaseAudioContext.ts +5 -0
  105. package/src/core/StretcherNode.ts +15 -0
  106. package/src/index.ts +1 -0
  107. package/src/index.web.ts +1 -0
  108. package/src/interfaces.ts +6 -0
  109. package/common/cpp/installer/AudioAPIModuleInstaller.cpp +0 -49
  110. /package/android/src/main/cpp/{libs → audioapi/android/libs}/pffft.h +0 -0
  111. /package/common/cpp/{core → audioapi/core}/Constants.h +0 -0
  112. /package/common/cpp/{core → audioapi/core/sources}/AudioBuffer.h +0 -0
  113. /package/common/cpp/{types → audioapi/core/types}/BiquadFilterType.h +0 -0
  114. /package/common/cpp/{types → audioapi/core/types}/ChannelCountMode.h +0 -0
  115. /package/common/cpp/{types → audioapi/core/types}/ChannelInterpretation.h +0 -0
  116. /package/common/cpp/{types → audioapi/core/types}/ContextState.h +0 -0
  117. /package/common/cpp/{types → audioapi/core/types}/OscillatorType.h +0 -0
  118. /package/common/cpp/{types → audioapi/core/types}/ParamChangeEventType.h +0 -0
  119. /package/common/cpp/{core → audioapi/core/utils}/AudioArray.h +0 -0
  120. /package/common/cpp/{core → audioapi/core/utils}/AudioDecoder.h +0 -0
  121. /package/common/cpp/{core → audioapi/core/utils}/AudioNodeManager.h +0 -0
  122. /package/common/cpp/{utils → audioapi/core/utils}/Locker.h +0 -0
  123. /package/common/cpp/{utils → audioapi/dsp}/AudioUtils.h +0 -0
  124. /package/common/cpp/{jsi → audioapi/jsi}/JsiPromise.h +0 -0
  125. /package/common/cpp/{libs → audioapi/libs}/miniaudio.h +0 -0
  126. /package/ios/{AudioAPIModule.h → audioapi/ios/AudioAPIModule.h} +0 -0
  127. /package/ios/{core → audioapi/ios/core}/AudioPlayer.h +0 -0
  128. /package/ios/{core → audioapi/ios/core}/IOSAudioPlayer.h +0 -0
@@ -0,0 +1,523 @@
1
+ #include <audioapi/libs/dsp/common.h>
2
+
3
+ #ifndef SIGNALSMITH_FFT_V5
4
+ #define SIGNALSMITH_FFT_V5
5
+
6
+ #include <audioapi/libs/dsp/perf.h>
7
+
8
+ #include <vector>
9
+ #include <complex>
10
+ #include <cmath>
11
+
12
+ namespace signalsmith { namespace fft {
13
+ /** @defgroup FFT FFT (complex and real)
14
+ @brief Fourier transforms (complex and real)
15
+
16
+ @{
17
+ @file
18
+ */
19
+
20
+ namespace _fft_impl {
21
+
22
+ template <typename V>
23
+ SIGNALSMITH_INLINE V complexReal(const std::complex<V> &c) {
24
+ return ((V*)(&c))[0];
25
+ }
26
+ template <typename V>
27
+ SIGNALSMITH_INLINE V complexImag(const std::complex<V> &c) {
28
+ return ((V*)(&c))[1];
29
+ }
30
+
31
+ // Complex multiplication has edge-cases around Inf/NaN - handling those properly makes std::complex non-inlineable, so we use our own
32
+ template <bool conjugateSecond, typename V>
33
+ SIGNALSMITH_INLINE std::complex<V> complexMul(const std::complex<V> &a, const std::complex<V> &b) {
34
+ V aReal = complexReal(a), aImag = complexImag(a);
35
+ V bReal = complexReal(b), bImag = complexImag(b);
36
+ return conjugateSecond ? std::complex<V>{
37
+ bReal*aReal + bImag*aImag,
38
+ bReal*aImag - bImag*aReal
39
+ } : std::complex<V>{
40
+ aReal*bReal - aImag*bImag,
41
+ aReal*bImag + aImag*bReal
42
+ };
43
+ }
44
+
45
+ template<bool flipped, typename V>
46
+ SIGNALSMITH_INLINE std::complex<V> complexAddI(const std::complex<V> &a, const std::complex<V> &b) {
47
+ V aReal = complexReal(a), aImag = complexImag(a);
48
+ V bReal = complexReal(b), bImag = complexImag(b);
49
+ return flipped ? std::complex<V>{
50
+ aReal + bImag,
51
+ aImag - bReal
52
+ } : std::complex<V>{
53
+ aReal - bImag,
54
+ aImag + bReal
55
+ };
56
+ }
57
+
58
+ // Use SFINAE to get an iterator from std::begin(), if supported - otherwise assume the value itself is an iterator
59
+ template<typename T, typename=void>
60
+ struct GetIterator {
61
+ static T get(const T &t) {
62
+ return t;
63
+ }
64
+ };
65
+ template<typename T>
66
+ struct GetIterator<T, decltype((void)std::begin(std::declval<T>()))> {
67
+ static auto get(const T &t) -> decltype(std::begin(t)) {
68
+ return std::begin(t);
69
+ }
70
+ };
71
+ }
72
+
73
+ /** Floating-point FFT implementation.
74
+ It is fast for 2^a * 3^b.
75
+ Here are the peak and RMS errors for `float`/`double` computation:
76
+ \diagram{fft-errors.svg Simulated errors for pure-tone harmonic inputs\, compared to a theoretical upper bound from "Roundoff error analysis of the fast Fourier transform" (G. Ramos, 1971)}
77
+ */
78
+ template<typename V=double>
79
+ class FFT {
80
+ using complex = std::complex<V>;
81
+ size_t _size;
82
+ std::vector<complex> workingVector;
83
+
84
+ enum class StepType {
85
+ generic, step2, step3, step4
86
+ };
87
+ struct Step {
88
+ StepType type;
89
+ size_t factor;
90
+ size_t startIndex;
91
+ size_t innerRepeats;
92
+ size_t outerRepeats;
93
+ size_t twiddleIndex;
94
+ };
95
+ std::vector<size_t> factors;
96
+ std::vector<Step> plan;
97
+ std::vector<complex> twiddleVector;
98
+
99
+ struct PermutationPair {size_t from, to;};
100
+ std::vector<PermutationPair> permutation;
101
+
102
+ void addPlanSteps(size_t factorIndex, size_t start, size_t length, size_t repeats) {
103
+ if (factorIndex >= factors.size()) return;
104
+
105
+ size_t factor = factors[factorIndex];
106
+ if (factorIndex + 1 < factors.size()) {
107
+ if (factors[factorIndex] == 2 && factors[factorIndex + 1] == 2) {
108
+ ++factorIndex;
109
+ factor = 4;
110
+ }
111
+ }
112
+
113
+ size_t subLength = length/factor;
114
+ Step mainStep{StepType::generic, factor, start, subLength, repeats, twiddleVector.size()};
115
+
116
+ if (factor == 2) mainStep.type = StepType::step2;
117
+ if (factor == 3) mainStep.type = StepType::step3;
118
+ if (factor == 4) mainStep.type = StepType::step4;
119
+
120
+ // Twiddles
121
+ bool foundStep = false;
122
+ for (const Step &existingStep : plan) {
123
+ if (existingStep.factor == mainStep.factor && existingStep.innerRepeats == mainStep.innerRepeats) {
124
+ foundStep = true;
125
+ mainStep.twiddleIndex = existingStep.twiddleIndex;
126
+ break;
127
+ }
128
+ }
129
+ if (!foundStep) {
130
+ for (size_t i = 0; i < subLength; ++i) {
131
+ for (size_t f = 0; f < factor; ++f) {
132
+ double phase = 2*M_PI*i*f/length;
133
+ complex twiddle = {V(std::cos(phase)), V(-std::sin(phase))};
134
+ twiddleVector.push_back(twiddle);
135
+ }
136
+ }
137
+ }
138
+
139
+ if (repeats == 1 && sizeof(complex)*subLength > 65536) {
140
+ for (size_t i = 0; i < factor; ++i) {
141
+ addPlanSteps(factorIndex + 1, start + i*subLength, subLength, 1);
142
+ }
143
+ } else {
144
+ addPlanSteps(factorIndex + 1, start, subLength, repeats*factor);
145
+ }
146
+ plan.push_back(mainStep);
147
+ }
148
+ void setPlan() {
149
+ factors.resize(0);
150
+ size_t size = _size, factor = 2;
151
+ while (size > 1) {
152
+ if (size%factor == 0) {
153
+ factors.push_back(factor);
154
+ size /= factor;
155
+ } else if (factor > sqrt(size)) {
156
+ factor = size;
157
+ } else {
158
+ ++factor;
159
+ }
160
+ }
161
+
162
+ plan.resize(0);
163
+ twiddleVector.resize(0);
164
+ addPlanSteps(0, 0, _size, 1);
165
+ twiddleVector.shrink_to_fit();
166
+
167
+ permutation.resize(0);
168
+ permutation.reserve(_size);
169
+ permutation.push_back(PermutationPair{0, 0});
170
+ size_t indexLow = 0, indexHigh = factors.size();
171
+ size_t inputStepLow = _size, outputStepLow = 1;
172
+ size_t inputStepHigh = 1, outputStepHigh = _size;
173
+ while (outputStepLow*inputStepHigh < _size) {
174
+ size_t f, inputStep, outputStep;
175
+ if (outputStepLow <= inputStepHigh) {
176
+ f = factors[indexLow++];
177
+ inputStep = (inputStepLow /= f);
178
+ outputStep = outputStepLow;
179
+ outputStepLow *= f;
180
+ } else {
181
+ f = factors[--indexHigh];
182
+ inputStep = inputStepHigh;
183
+ inputStepHigh *= f;
184
+ outputStep = (outputStepHigh /= f);
185
+ }
186
+ size_t oldSize = permutation.size();
187
+ for (size_t i = 1; i < f; ++i) {
188
+ for (size_t j = 0; j < oldSize; ++j) {
189
+ PermutationPair pair = permutation[j];
190
+ pair.from += i*inputStep;
191
+ pair.to += i*outputStep;
192
+ permutation.push_back(pair);
193
+ }
194
+ }
195
+ }
196
+ }
197
+
198
+ template<bool inverse, typename RandomAccessIterator>
199
+ void fftStepGeneric(RandomAccessIterator &&origData, const Step &step) {
200
+ complex *working = workingVector.data();
201
+ const size_t stride = step.innerRepeats;
202
+
203
+ for (size_t outerRepeat = 0; outerRepeat < step.outerRepeats; ++outerRepeat) {
204
+ RandomAccessIterator data = origData;
205
+
206
+ const complex *twiddles = twiddleVector.data() + step.twiddleIndex;
207
+ const size_t factor = step.factor;
208
+ for (size_t repeat = 0; repeat < step.innerRepeats; ++repeat) {
209
+ for (size_t i = 0; i < step.factor; ++i) {
210
+ working[i] = _fft_impl::complexMul<inverse>(data[i*stride], twiddles[i]);
211
+ }
212
+ for (size_t f = 0; f < factor; ++f) {
213
+ complex sum = working[0];
214
+ for (size_t i = 1; i < factor; ++i) {
215
+ double phase = 2*M_PI*f*i/factor;
216
+ complex twiddle = {V(std::cos(phase)), V(-std::sin(phase))};
217
+ sum += _fft_impl::complexMul<inverse>(working[i], twiddle);
218
+ }
219
+ data[f*stride] = sum;
220
+ }
221
+ ++data;
222
+ twiddles += factor;
223
+ }
224
+ origData += step.factor*step.innerRepeats;
225
+ }
226
+ }
227
+
228
+ template<bool inverse, typename RandomAccessIterator>
229
+ SIGNALSMITH_INLINE void fftStep2(RandomAccessIterator &&origData, const Step &step) {
230
+ const size_t stride = step.innerRepeats;
231
+ const complex *origTwiddles = twiddleVector.data() + step.twiddleIndex;
232
+ for (size_t outerRepeat = 0; outerRepeat < step.outerRepeats; ++outerRepeat) {
233
+ const complex* twiddles = origTwiddles;
234
+ for (RandomAccessIterator data = origData; data < origData + stride; ++data) {
235
+ complex A = data[0];
236
+ complex B = _fft_impl::complexMul<inverse>(data[stride], twiddles[1]);
237
+
238
+ data[0] = A + B;
239
+ data[stride] = A - B;
240
+ twiddles += 2;
241
+ }
242
+ origData += 2*stride;
243
+ }
244
+ }
245
+
246
+ template<bool inverse, typename RandomAccessIterator>
247
+ SIGNALSMITH_INLINE void fftStep3(RandomAccessIterator &&origData, const Step &step) {
248
+ constexpr complex factor3 = {-0.5, inverse ? 0.8660254037844386 : -0.8660254037844386};
249
+ const size_t stride = step.innerRepeats;
250
+ const complex *origTwiddles = twiddleVector.data() + step.twiddleIndex;
251
+
252
+ for (size_t outerRepeat = 0; outerRepeat < step.outerRepeats; ++outerRepeat) {
253
+ const complex* twiddles = origTwiddles;
254
+ for (RandomAccessIterator data = origData; data < origData + stride; ++data) {
255
+ complex A = data[0];
256
+ complex B = _fft_impl::complexMul<inverse>(data[stride], twiddles[1]);
257
+ complex C = _fft_impl::complexMul<inverse>(data[stride*2], twiddles[2]);
258
+
259
+ complex realSum = A + (B + C)*factor3.real();
260
+ complex imagSum = (B - C)*factor3.imag();
261
+
262
+ data[0] = A + B + C;
263
+ data[stride] = _fft_impl::complexAddI<false>(realSum, imagSum);
264
+ data[stride*2] = _fft_impl::complexAddI<true>(realSum, imagSum);
265
+
266
+ twiddles += 3;
267
+ }
268
+ origData += 3*stride;
269
+ }
270
+ }
271
+
272
+ template<bool inverse, typename RandomAccessIterator>
273
+ SIGNALSMITH_INLINE void fftStep4(RandomAccessIterator &&origData, const Step &step) {
274
+ const size_t stride = step.innerRepeats;
275
+ const complex *origTwiddles = twiddleVector.data() + step.twiddleIndex;
276
+
277
+ for (size_t outerRepeat = 0; outerRepeat < step.outerRepeats; ++outerRepeat) {
278
+ const complex* twiddles = origTwiddles;
279
+ for (RandomAccessIterator data = origData; data < origData + stride; ++data) {
280
+ complex A = data[0];
281
+ complex C = _fft_impl::complexMul<inverse>(data[stride], twiddles[2]);
282
+ complex B = _fft_impl::complexMul<inverse>(data[stride*2], twiddles[1]);
283
+ complex D = _fft_impl::complexMul<inverse>(data[stride*3], twiddles[3]);
284
+
285
+ complex sumAC = A + C, sumBD = B + D;
286
+ complex diffAC = A - C, diffBD = B - D;
287
+
288
+ data[0] = sumAC + sumBD;
289
+ data[stride] = _fft_impl::complexAddI<!inverse>(diffAC, diffBD);
290
+ data[stride*2] = sumAC - sumBD;
291
+ data[stride*3] = _fft_impl::complexAddI<inverse>(diffAC, diffBD);
292
+
293
+ twiddles += 4;
294
+ }
295
+ origData += 4*stride;
296
+ }
297
+ }
298
+
299
+ template<typename InputIterator, typename OutputIterator>
300
+ void permute(InputIterator input, OutputIterator data) {
301
+ for (auto pair : permutation) {
302
+ data[pair.from] = input[pair.to];
303
+ }
304
+ }
305
+
306
+ template<bool inverse, typename InputIterator, typename OutputIterator>
307
+ void run(InputIterator &&input, OutputIterator &&data) {
308
+ permute(input, data);
309
+
310
+ for (const Step &step : plan) {
311
+ switch (step.type) {
312
+ case StepType::generic:
313
+ fftStepGeneric<inverse>(data + step.startIndex, step);
314
+ break;
315
+ case StepType::step2:
316
+ fftStep2<inverse>(data + step.startIndex, step);
317
+ break;
318
+ case StepType::step3:
319
+ fftStep3<inverse>(data + step.startIndex, step);
320
+ break;
321
+ case StepType::step4:
322
+ fftStep4<inverse>(data + step.startIndex, step);
323
+ break;
324
+ }
325
+ }
326
+ }
327
+
328
+ static bool validSize(size_t size) {
329
+ constexpr static bool filter[32] = {
330
+ 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, // 0-9
331
+ 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, // 10-19
332
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, // 20-29
333
+ 0, 0
334
+ };
335
+ return filter[size];
336
+ }
337
+ public:
338
+ static size_t fastSizeAbove(size_t size) {
339
+ size_t power2 = 1;
340
+ while (size >= 32) {
341
+ size = (size - 1)/2 + 1;
342
+ power2 *= 2;
343
+ }
344
+ while (size < 32 && !validSize(size)) {
345
+ ++size;
346
+ }
347
+ return power2*size;
348
+ }
349
+ static size_t fastSizeBelow(size_t size) {
350
+ size_t power2 = 1;
351
+ while (size >= 32) {
352
+ size /= 2;
353
+ power2 *= 2;
354
+ }
355
+ while (size > 1 && !validSize(size)) {
356
+ --size;
357
+ }
358
+ return power2*size;
359
+ }
360
+
361
+ FFT(size_t size, int fastDirection=0) : _size(0) {
362
+ if (fastDirection > 0) size = fastSizeAbove(size);
363
+ if (fastDirection < 0) size = fastSizeBelow(size);
364
+ this->setSize(size);
365
+ }
366
+
367
+ size_t setSize(size_t size) {
368
+ if (size != _size) {
369
+ _size = size;
370
+ workingVector.resize(size);
371
+ setPlan();
372
+ }
373
+ return _size;
374
+ }
375
+ size_t setFastSizeAbove(size_t size) {
376
+ return setSize(fastSizeAbove(size));
377
+ }
378
+ size_t setFastSizeBelow(size_t size) {
379
+ return setSize(fastSizeBelow(size));
380
+ }
381
+ const size_t & size() const {
382
+ return _size;
383
+ }
384
+
385
+ template<typename InputIterator, typename OutputIterator>
386
+ void fft(InputIterator &&input, OutputIterator &&output) {
387
+ auto inputIter = _fft_impl::GetIterator<InputIterator>::get(input);
388
+ auto outputIter = _fft_impl::GetIterator<OutputIterator>::get(output);
389
+ return run<false>(inputIter, outputIter);
390
+ }
391
+
392
+ template<typename InputIterator, typename OutputIterator>
393
+ void ifft(InputIterator &&input, OutputIterator &&output) {
394
+ auto inputIter = _fft_impl::GetIterator<InputIterator>::get(input);
395
+ auto outputIter = _fft_impl::GetIterator<OutputIterator>::get(output);
396
+ return run<true>(inputIter, outputIter);
397
+ }
398
+ };
399
+
400
+ struct FFTOptions {
401
+ static constexpr int halfFreqShift = 1;
402
+ };
403
+
404
+ template<typename V, int optionFlags=0>
405
+ class RealFFT {
406
+ static constexpr bool modified = (optionFlags&FFTOptions::halfFreqShift);
407
+
408
+ using complex = std::complex<V>;
409
+ std::vector<complex> complexBuffer1, complexBuffer2;
410
+ std::vector<complex> twiddlesMinusI;
411
+ std::vector<complex> modifiedRotations;
412
+ FFT<V> complexFft;
413
+ public:
414
+ static size_t fastSizeAbove(size_t size) {
415
+ return FFT<V>::fastSizeAbove((size + 1)/2)*2;
416
+ }
417
+ static size_t fastSizeBelow(size_t size) {
418
+ return FFT<V>::fastSizeBelow(size/2)*2;
419
+ }
420
+
421
+ RealFFT(size_t size=0, int fastDirection=0) : complexFft(0) {
422
+ if (fastDirection > 0) size = fastSizeAbove(size);
423
+ if (fastDirection < 0) size = fastSizeBelow(size);
424
+ this->setSize(std::max<size_t>(size, 2));
425
+ }
426
+
427
+ size_t setSize(size_t size) {
428
+ complexBuffer1.resize(size/2);
429
+ complexBuffer2.resize(size/2);
430
+
431
+ size_t hhSize = size/4 + 1;
432
+ twiddlesMinusI.resize(hhSize);
433
+ for (size_t i = 0; i < hhSize; ++i) {
434
+ V rotPhase = -2*M_PI*(modified ? i + 0.5 : i)/size;
435
+ twiddlesMinusI[i] = {std::sin(rotPhase), -std::cos(rotPhase)};
436
+ }
437
+ if (modified) {
438
+ modifiedRotations.resize(size/2);
439
+ for (size_t i = 0; i < size/2; ++i) {
440
+ V rotPhase = -2*M_PI*i/size;
441
+ modifiedRotations[i] = {std::cos(rotPhase), std::sin(rotPhase)};
442
+ }
443
+ }
444
+
445
+ return complexFft.setSize(size/2);
446
+ }
447
+ size_t setFastSizeAbove(size_t size) {
448
+ return setSize(fastSizeAbove(size));
449
+ }
450
+ size_t setFastSizeBelow(size_t size) {
451
+ return setSize(fastSizeBelow(size));
452
+ }
453
+ size_t size() const {
454
+ return complexFft.size()*2;
455
+ }
456
+
457
+ template<typename InputIterator, typename OutputIterator>
458
+ void fft(InputIterator &&input, OutputIterator &&output) {
459
+ size_t hSize = complexFft.size();
460
+ for (size_t i = 0; i < hSize; ++i) {
461
+ if (modified) {
462
+ complexBuffer1[i] = _fft_impl::complexMul<false>({input[2*i], input[2*i + 1]}, modifiedRotations[i]);
463
+ } else {
464
+ complexBuffer1[i] = {input[2*i], input[2*i + 1]};
465
+ }
466
+ }
467
+
468
+ complexFft.fft(complexBuffer1.data(), complexBuffer2.data());
469
+
470
+ if (!modified) output[0] = {
471
+ complexBuffer2[0].real() + complexBuffer2[0].imag(),
472
+ complexBuffer2[0].real() - complexBuffer2[0].imag()
473
+ };
474
+ for (size_t i = modified ? 0 : 1; i <= hSize/2; ++i) {
475
+ size_t conjI = modified ? (hSize - 1 - i) : (hSize - i);
476
+
477
+ complex odd = (complexBuffer2[i] + conj(complexBuffer2[conjI]))*(V)0.5;
478
+ complex evenI = (complexBuffer2[i] - conj(complexBuffer2[conjI]))*(V)0.5;
479
+ complex evenRotMinusI = _fft_impl::complexMul<false>(evenI, twiddlesMinusI[i]);
480
+
481
+ output[i] = odd + evenRotMinusI;
482
+ output[conjI] = conj(odd - evenRotMinusI);
483
+ }
484
+ }
485
+
486
+ template<typename InputIterator, typename OutputIterator>
487
+ void ifft(InputIterator &&input, OutputIterator &&output) {
488
+ size_t hSize = complexFft.size();
489
+ if (!modified) complexBuffer1[0] = {
490
+ input[0].real() + input[0].imag(),
491
+ input[0].real() - input[0].imag()
492
+ };
493
+ for (size_t i = modified ? 0 : 1; i <= hSize/2; ++i) {
494
+ size_t conjI = modified ? (hSize - 1 - i) : (hSize - i);
495
+ complex v = input[i], v2 = input[conjI];
496
+
497
+ complex odd = v + conj(v2);
498
+ complex evenRotMinusI = v - conj(v2);
499
+ complex evenI = _fft_impl::complexMul<true>(evenRotMinusI, twiddlesMinusI[i]);
500
+
501
+ complexBuffer1[i] = odd + evenI;
502
+ complexBuffer1[conjI] = conj(odd - evenI);
503
+ }
504
+
505
+ complexFft.ifft(complexBuffer1.data(), complexBuffer2.data());
506
+
507
+ for (size_t i = 0; i < hSize; ++i) {
508
+ complex v = complexBuffer2[i];
509
+ if (modified) v = _fft_impl::complexMul<true>(v, modifiedRotations[i]);
510
+ output[2*i] = v.real();
511
+ output[2*i + 1] = v.imag();
512
+ }
513
+ }
514
+ };
515
+
516
+ template<typename V>
517
+ struct ModifiedRealFFT : public RealFFT<V, FFTOptions::halfFreqShift> {
518
+ using RealFFT<V, FFTOptions::halfFreqShift>::RealFFT;
519
+ };
520
+
521
+ /// @}
522
+ }} // namespace
523
+ #endif // include guard
@@ -0,0 +1,84 @@
1
+ #include <audioapi/libs/dsp/common.h>
2
+
3
+ #ifndef SIGNALSMITH_DSP_PERF_H
4
+ #define SIGNALSMITH_DSP_PERF_H
5
+
6
+ #include <complex>
7
+
8
+ #if defined(__SSE__) || defined(_M_X64)
9
+ # include <xmmintrin.h>
10
+ #else
11
+ # include <cstdint> // for uintptr_t
12
+ #endif
13
+
14
+ namespace signalsmith {
15
+ namespace perf {
16
+ /** @defgroup Performance Performance helpers
17
+ @brief Nothing serious, just some `#defines` and helpers
18
+
19
+ @{
20
+ @file
21
+ */
22
+
23
+ /// *Really* insist that a function/method is inlined (mostly for performance in DEBUG builds)
24
+ #ifndef SIGNALSMITH_INLINE
25
+ #ifdef __GNUC__
26
+ #define SIGNALSMITH_INLINE __attribute__((always_inline)) inline
27
+ #elif defined(__MSVC__)
28
+ #define SIGNALSMITH_INLINE __forceinline inline
29
+ #else
30
+ #define SIGNALSMITH_INLINE inline
31
+ #endif
32
+ #endif
33
+
34
+ /** @brief Complex-multiplication (with optional conjugate second-arg), without handling NaN/Infinity
35
+ The `std::complex` multiplication has edge-cases around NaNs which slow things down and prevent auto-vectorisation. Flags like `-ffast-math` sort this out anyway, but this helps with Debug builds.
36
+ */
37
+ template <bool conjugateSecond=false, typename V>
38
+ SIGNALSMITH_INLINE static std::complex<V> mul(const std::complex<V> &a, const std::complex<V> &b) {
39
+ return conjugateSecond ? std::complex<V>{
40
+ b.real()*a.real() + b.imag()*a.imag(),
41
+ b.real()*a.imag() - b.imag()*a.real()
42
+ } : std::complex<V>{
43
+ a.real()*b.real() - a.imag()*b.imag(),
44
+ a.real()*b.imag() + a.imag()*b.real()
45
+ };
46
+ }
47
+
48
+ #if defined(__SSE__) || defined(_M_X64)
49
+ class StopDenormals {
50
+ unsigned int controlStatusRegister;
51
+ public:
52
+ StopDenormals() : controlStatusRegister(_mm_getcsr()) {
53
+ _mm_setcsr(controlStatusRegister|0x8040); // Flush-to-Zero and Denormals-Are-Zero
54
+ }
55
+ ~StopDenormals() {
56
+ _mm_setcsr(controlStatusRegister);
57
+ }
58
+ };
59
+ #elif (defined (__ARM_NEON) || defined (__ARM_NEON__))
60
+ class StopDenormals {
61
+ uintptr_t status;
62
+ public:
63
+ StopDenormals() {
64
+ uintptr_t asmStatus;
65
+ asm volatile("mrs %0, fpcr" : "=r"(asmStatus));
66
+ status = asmStatus = asmStatus|0x01000000U; // Flush to Zero
67
+ asm volatile("msr fpcr, %0" : : "ri"(asmStatus));
68
+ }
69
+ ~StopDenormals() {
70
+ uintptr_t asmStatus = status;
71
+ asm volatile("msr fpcr, %0" : : "ri"(asmStatus));
72
+ }
73
+ };
74
+ #else
75
+ # if __cplusplus >= 202302L
76
+ # warning "The `StopDenormals` class doesn't do anything for this architecture"
77
+ # endif
78
+ class StopDenormals {}; // FIXME: add for other architectures
79
+ #endif
80
+
81
+ /** @} */
82
+ }} // signalsmith::perf::
83
+
84
+ #endif // include guard