react-native-audio-api 0.5.5 → 0.6.0-rc.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 (96) hide show
  1. package/RNAudioAPI.podspec +1 -1
  2. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +0 -20
  3. package/android/src/main/cpp/audioapi/android/core/AudioPlayer.h +0 -2
  4. package/android/src/main/java/com/swmansion/audioapi/AudioAPIPackage.kt +13 -0
  5. package/android/src/main/java/com/swmansion/audioapi/AudioManagerModule.kt +59 -0
  6. package/android/src/oldarch/NativeAudioManagerModuleSpec.java +99 -0
  7. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +30 -6
  8. package/common/cpp/audioapi/HostObjects/OfflineAudioContextHostObject.h +70 -0
  9. package/common/cpp/audioapi/core/AudioContext.cpp +1 -12
  10. package/common/cpp/audioapi/core/AudioContext.h +0 -1
  11. package/common/cpp/audioapi/core/OfflineAudioContext.cpp +117 -0
  12. package/common/cpp/audioapi/core/OfflineAudioContext.h +40 -0
  13. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +3 -3
  14. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +28 -2
  15. package/common/cpp/audioapi/core/utils/AudioNodeDestructor.cpp +53 -0
  16. package/common/cpp/audioapi/core/utils/AudioNodeDestructor.h +33 -0
  17. package/common/cpp/audioapi/core/utils/AudioNodeManager.cpp +13 -10
  18. package/common/cpp/audioapi/core/utils/AudioNodeManager.h +3 -0
  19. package/common/cpp/audioapi/libs/signalsmith-stretch/fft-accelerate.h +326 -0
  20. package/common/cpp/audioapi/libs/signalsmith-stretch/fft.h +1257 -413
  21. package/common/cpp/audioapi/libs/signalsmith-stretch/signalsmith-stretch.h +398 -232
  22. package/common/cpp/audioapi/libs/signalsmith-stretch/stft.h +625 -0
  23. package/ios/audioapi/ios/AudioAPIModule.mm +2 -3
  24. package/ios/audioapi/ios/AudioManagerModule.h +18 -0
  25. package/ios/audioapi/ios/AudioManagerModule.mm +92 -0
  26. package/ios/audioapi/ios/core/AudioPlayer.h +4 -12
  27. package/ios/audioapi/ios/core/AudioPlayer.m +26 -108
  28. package/ios/audioapi/ios/core/IOSAudioPlayer.h +1 -3
  29. package/ios/audioapi/ios/core/IOSAudioPlayer.mm +4 -28
  30. package/ios/audioapi/ios/system/AudioEngine.h +23 -0
  31. package/ios/audioapi/ios/system/AudioEngine.mm +137 -0
  32. package/ios/audioapi/ios/system/AudioSessionManager.h +22 -0
  33. package/ios/audioapi/ios/system/AudioSessionManager.mm +183 -0
  34. package/ios/audioapi/ios/system/LockScreenManager.h +23 -0
  35. package/ios/audioapi/ios/system/LockScreenManager.mm +299 -0
  36. package/ios/audioapi/ios/system/NotificationManager.h +16 -0
  37. package/ios/audioapi/ios/system/NotificationManager.mm +151 -0
  38. package/lib/module/api.js +3 -1
  39. package/lib/module/api.js.map +1 -1
  40. package/lib/module/api.web.js +1 -0
  41. package/lib/module/api.web.js.map +1 -1
  42. package/lib/module/core/AudioContext.js +2 -1
  43. package/lib/module/core/AudioContext.js.map +1 -1
  44. package/lib/module/core/OfflineAudioContext.js +57 -0
  45. package/lib/module/core/OfflineAudioContext.js.map +1 -0
  46. package/lib/module/specs/NativeAudioManagerModule.js +31 -0
  47. package/lib/module/specs/NativeAudioManagerModule.js.map +1 -0
  48. package/lib/module/specs/index.js +6 -0
  49. package/lib/module/specs/index.js.map +1 -0
  50. package/lib/module/system/AudioManager.js +66 -0
  51. package/lib/module/system/AudioManager.js.map +1 -0
  52. package/lib/module/system/index.js +4 -0
  53. package/lib/module/system/index.js.map +1 -0
  54. package/lib/module/system/types.js +2 -0
  55. package/lib/module/system/types.js.map +1 -0
  56. package/lib/module/web-core/OfflineAudioContext.js +90 -0
  57. package/lib/module/web-core/OfflineAudioContext.js.map +1 -0
  58. package/lib/typescript/api.d.ts +4 -1
  59. package/lib/typescript/api.d.ts.map +1 -1
  60. package/lib/typescript/api.web.d.ts +1 -0
  61. package/lib/typescript/api.web.d.ts.map +1 -1
  62. package/lib/typescript/core/AudioContext.d.ts.map +1 -1
  63. package/lib/typescript/core/OfflineAudioContext.d.ts +14 -0
  64. package/lib/typescript/core/OfflineAudioContext.d.ts.map +1 -0
  65. package/lib/typescript/interfaces.d.ts +6 -0
  66. package/lib/typescript/interfaces.d.ts.map +1 -1
  67. package/lib/typescript/specs/NativeAudioManagerModule.d.ts +13 -0
  68. package/lib/typescript/specs/NativeAudioManagerModule.d.ts.map +1 -0
  69. package/lib/typescript/specs/index.d.ts +4 -0
  70. package/lib/typescript/specs/index.d.ts.map +1 -0
  71. package/lib/typescript/system/AudioManager.d.ts +12 -0
  72. package/lib/typescript/system/AudioManager.d.ts.map +1 -0
  73. package/lib/typescript/system/index.d.ts +2 -0
  74. package/lib/typescript/system/index.d.ts.map +1 -0
  75. package/lib/typescript/system/types.d.ts +28 -0
  76. package/lib/typescript/system/types.d.ts.map +1 -0
  77. package/lib/typescript/types.d.ts +5 -0
  78. package/lib/typescript/types.d.ts.map +1 -1
  79. package/lib/typescript/web-core/OfflineAudioContext.d.ts +34 -0
  80. package/lib/typescript/web-core/OfflineAudioContext.d.ts.map +1 -0
  81. package/package.json +2 -2
  82. package/src/api.ts +12 -2
  83. package/src/api.web.ts +1 -0
  84. package/src/core/AudioContext.ts +6 -1
  85. package/src/core/OfflineAudioContext.ts +94 -0
  86. package/src/interfaces.ts +11 -0
  87. package/src/specs/NativeAudioManagerModule.ts +51 -0
  88. package/src/specs/index.ts +6 -0
  89. package/src/system/AudioManager.ts +122 -0
  90. package/src/system/index.ts +1 -0
  91. package/src/system/types.ts +68 -0
  92. package/src/types.ts +6 -0
  93. package/src/web-core/OfflineAudioContext.tsx +163 -0
  94. package/common/cpp/audioapi/libs/signalsmith-stretch/delay.h +0 -715
  95. package/common/cpp/audioapi/libs/signalsmith-stretch/perf.h +0 -82
  96. package/common/cpp/audioapi/libs/signalsmith-stretch/spectral.h +0 -493
@@ -0,0 +1,53 @@
1
+ #include <audioapi/core/AudioNode.h>
2
+ #include <audioapi/core/utils/AudioNodeDestructor.h>
3
+ #include <audioapi/core/utils/Locker.h>
4
+
5
+ namespace audioapi {
6
+
7
+ AudioNodeDestructor::AudioNodeDestructor()
8
+ : thread_(std::thread(&AudioNodeDestructor::process, this)),
9
+ isExiting_(false) {}
10
+
11
+ AudioNodeDestructor::~AudioNodeDestructor() {
12
+ isExiting_ = true;
13
+
14
+ cv_.notify_one(); // call process for the last time
15
+ if (thread_.joinable()) {
16
+ thread_.join();
17
+ }
18
+ }
19
+
20
+ void AudioNodeDestructor::tryCallWithLock(
21
+ const std::function<void()> &callback) {
22
+ if (auto lock = Locker::tryLock(mutex_)) {
23
+ callback();
24
+ }
25
+ }
26
+
27
+ void AudioNodeDestructor::addNodeForDeconstruction(
28
+ const std::shared_ptr<AudioNode> &node) {
29
+ // NOTE: this method must be called within `tryCallWithLock`
30
+ nodesForDeconstruction_.emplace_back(node);
31
+ }
32
+
33
+ void AudioNodeDestructor::notify() {
34
+ cv_.notify_one();
35
+ }
36
+
37
+ void AudioNodeDestructor::process() {
38
+ std::unique_lock<std::mutex> lock(mutex_);
39
+ while (!isExiting_) {
40
+ cv_.wait(lock, [this] {
41
+ return isExiting_ || !nodesForDeconstruction_.empty();
42
+ });
43
+
44
+ if (isExiting_)
45
+ break;
46
+
47
+ if (!isExiting_ && !nodesForDeconstruction_.empty()) {
48
+ nodesForDeconstruction_.clear();
49
+ }
50
+ }
51
+ }
52
+
53
+ } // namespace audioapi
@@ -0,0 +1,33 @@
1
+ #pragma once
2
+
3
+ #include <condition_variable>
4
+ #include <mutex>
5
+ #include <thread>
6
+ #include <atomic>
7
+ #include <vector>
8
+ #include <memory>
9
+
10
+ namespace audioapi {
11
+
12
+ class AudioNode;
13
+
14
+ class AudioNodeDestructor {
15
+ public:
16
+ AudioNodeDestructor();
17
+ ~AudioNodeDestructor();
18
+
19
+ void tryCallWithLock(const std::function<void()> &callback);
20
+ void addNodeForDeconstruction(const std::shared_ptr<AudioNode> &node);
21
+ void notify();
22
+
23
+ private:
24
+ mutable std::mutex mutex_;
25
+ std::thread thread_;
26
+ std::condition_variable cv_;
27
+ std::vector<std::shared_ptr<AudioNode>> nodesForDeconstruction_;
28
+
29
+ std::atomic<bool> isExiting_;
30
+
31
+ void process();
32
+ };
33
+ } // namespace audioapi
@@ -55,17 +55,20 @@ void AudioNodeManager::settlePendingConnections() {
55
55
  }
56
56
 
57
57
  void AudioNodeManager::prepareNodesForDestruction() {
58
- auto it = nodes_.begin();
59
-
60
- while (it != nodes_.end()) {
61
- if (it->use_count() == 1) {
62
- assert(it->get()->inputNodes_.empty());
63
- it->get()->cleanup();
64
- it = nodes_.erase(it);
65
- } else {
66
- ++it;
58
+ nodeDeconstructor_.tryCallWithLock([this]() {
59
+ auto it = nodes_.begin();
60
+
61
+ while (it != nodes_.end()) {
62
+ if (it->use_count() == 1) {
63
+ nodeDeconstructor_.addNodeForDeconstruction(*it);
64
+ it->get()->cleanup();
65
+ it = nodes_.erase(it);
66
+ } else {
67
+ ++it;
68
+ }
67
69
  }
68
- }
70
+ });
71
+ nodeDeconstructor_.notify();
69
72
  }
70
73
 
71
74
  void AudioNodeManager::cleanup() {
@@ -1,5 +1,7 @@
1
1
  #pragma once
2
2
 
3
+ #include <audioapi/core/utils/AudioNodeDestructor.h>
4
+
3
5
  #include <memory>
4
6
  #include <mutex>
5
7
  #include <tuple>
@@ -31,6 +33,7 @@ class AudioNodeManager {
31
33
 
32
34
  private:
33
35
  std::mutex graphLock_;
36
+ AudioNodeDestructor nodeDeconstructor_;
34
37
 
35
38
  // all nodes created in the context
36
39
  std::unordered_set<std::shared_ptr<AudioNode>> nodes_;
@@ -0,0 +1,326 @@
1
+ // If possible, only include vecLib, since JUCE has conflicts with vImage
2
+ #if defined(HAVE_ACCELERATE)
3
+ #include <Accelerate/Accelerate.h>
4
+
5
+ namespace signalsmith { namespace linear {
6
+
7
+ namespace _impl {
8
+ template<>
9
+ inline void complexMul<float>(std::complex<float> *a, const std::complex<float> *b, const std::complex<float> *c, size_t size) {
10
+ DSPSplitComplex aSplit = {(float *)a, (float *)a + 1};
11
+ DSPSplitComplex bSplit = {(float *)b, (float *)b + 1};
12
+ DSPSplitComplex cSplit = {(float *)c, (float *)c + 1};
13
+ vDSP_zvmul(&cSplit, 2, &bSplit, 2, &aSplit, 2, size, 1);
14
+ }
15
+ template<>
16
+ inline void complexMulConj<float>(std::complex<float> *a, const std::complex<float> *b, const std::complex<float> *c, size_t size) {
17
+ DSPSplitComplex aSplit = {(float *)a, (float *)a + 1};
18
+ DSPSplitComplex bSplit = {(float *)b, (float *)b + 1};
19
+ DSPSplitComplex cSplit = {(float *)c, (float *)c + 1};
20
+ vDSP_zvmul(&cSplit, 2, &bSplit, 2, &aSplit, 2, size, -1);
21
+ }
22
+ template<>
23
+ inline void complexMul<float>(float *ar, float *ai, const float *br, const float *bi, const float *cr, const float *ci, size_t size) {
24
+ DSPSplitComplex aSplit = {ar, ai};
25
+ DSPSplitComplex bSplit = {(float *)br, (float *)bi};
26
+ DSPSplitComplex cSplit = {(float *)cr, (float *)ci};
27
+ vDSP_zvmul(&cSplit, 1, &bSplit, 1, &aSplit, 1, size, 1);
28
+ }
29
+ template<>
30
+ inline void complexMulConj<float>(float *ar, float *ai, const float *br, const float *bi, const float *cr, const float *ci, size_t size) {
31
+ DSPSplitComplex aSplit = {ar, ai};
32
+ DSPSplitComplex bSplit = {(float *)br, (float *)bi};
33
+ DSPSplitComplex cSplit = {(float *)cr, (float *)ci};
34
+ vDSP_zvmul(&cSplit, 1, &bSplit, 1, &aSplit, 1, size, -1);
35
+ }
36
+
37
+ // doubles
38
+ template<>
39
+ inline void complexMul<double>(std::complex<double> *a, const std::complex<double> *b, const std::complex<double> *c, size_t size) {
40
+ DSPDoubleSplitComplex aSplit = {(double *)a, (double *)a + 1};
41
+ DSPDoubleSplitComplex bSplit = {(double *)b, (double *)b + 1};
42
+ DSPDoubleSplitComplex cSplit = {(double *)c, (double *)c + 1};
43
+ vDSP_zvmulD(&cSplit, 2, &bSplit, 2, &aSplit, 2, size, 1);
44
+ }
45
+ template<>
46
+ inline void complexMulConj<double>(std::complex<double> *a, const std::complex<double> *b, const std::complex<double> *c, size_t size) {
47
+ DSPDoubleSplitComplex aSplit = {(double *)a, (double *)a + 1};
48
+ DSPDoubleSplitComplex bSplit = {(double *)b, (double *)b + 1};
49
+ DSPDoubleSplitComplex cSplit = {(double *)c, (double *)c + 1};
50
+ vDSP_zvmulD(&cSplit, 2, &bSplit, 2, &aSplit, 2, size, -1);
51
+ }
52
+ template<>
53
+ inline void complexMul<double>(double *ar, double *ai, const double *br, const double *bi, const double *cr, const double *ci, size_t size) {
54
+ DSPDoubleSplitComplex aSplit = {ar, ai};
55
+ DSPDoubleSplitComplex bSplit = {(double *)br, (double *)bi};
56
+ DSPDoubleSplitComplex cSplit = {(double *)cr, (double *)ci};
57
+ vDSP_zvmulD(&cSplit, 1, &bSplit, 1, &aSplit, 1, size, 1);
58
+ }
59
+ template<>
60
+ inline void complexMulConj<double>(double *ar, double *ai, const double *br, const double *bi, const double *cr, const double *ci, size_t size) {
61
+ DSPDoubleSplitComplex aSplit = {ar, ai};
62
+ DSPDoubleSplitComplex bSplit = {(double *)br, (double *)bi};
63
+ DSPDoubleSplitComplex cSplit = {(double *)cr, (double *)ci};
64
+ vDSP_zvmulD(&cSplit, 1, &bSplit, 1, &aSplit, 1, size, -1);
65
+ }
66
+ }
67
+
68
+ template<>
69
+ struct Pow2FFT<float> {
70
+ static constexpr bool prefersSplit = true;
71
+
72
+ using Complex = std::complex<float>;
73
+
74
+ Pow2FFT(size_t size = 0) {
75
+ resize(size);
76
+ }
77
+ ~Pow2FFT() {
78
+ if (hasSetup) vDSP_destroy_fftsetup(fftSetup);
79
+ }
80
+
81
+ void resize(size_t size) {
82
+ _size = size;
83
+ if (hasSetup) vDSP_destroy_fftsetup(fftSetup);
84
+ if (!size) {
85
+ hasSetup = false;
86
+ return;
87
+ }
88
+
89
+ splitReal.resize(size);
90
+ splitImag.resize(size);
91
+ log2 = std::round(std::log2(size));
92
+ fftSetup = vDSP_create_fftsetup(log2, FFT_RADIX2);
93
+ hasSetup = true;
94
+ }
95
+
96
+ void fft(const Complex* input, Complex* output) {
97
+ DSPSplitComplex splitComplex{ splitReal.data(), splitImag.data() };
98
+ vDSP_ctoz((DSPComplex*)input, 2, &splitComplex, 1, _size);
99
+ vDSP_fft_zip(fftSetup, &splitComplex, 1, log2, kFFTDirection_Forward);
100
+ vDSP_ztoc(&splitComplex, 1, (DSPComplex*)output, 2, _size);
101
+ }
102
+ void fft(const float *inR, const float *inI, float *outR, float *outI) {
103
+ DSPSplitComplex inSplit{(float *)inR, (float *)inI};
104
+ DSPSplitComplex outSplit{outR, outI};
105
+ vDSP_fft_zop(fftSetup, &inSplit, 1, &outSplit, 1, log2, kFFTDirection_Forward);
106
+ }
107
+
108
+ void ifft(const Complex* input, Complex* output) {
109
+ DSPSplitComplex splitComplex{ splitReal.data(), splitImag.data() };
110
+ vDSP_ctoz((DSPComplex*)input, 2, &splitComplex, 1, _size);
111
+ vDSP_fft_zip(fftSetup, &splitComplex, 1, log2, kFFTDirection_Inverse);
112
+ vDSP_ztoc(&splitComplex, 1, (DSPComplex*)output, 2, _size);
113
+ }
114
+ void ifft(const float *inR, const float *inI, float *outR, float *outI) {
115
+ DSPSplitComplex inSplit{(float *)inR, (float *)inI};
116
+ DSPSplitComplex outSplit{outR, outI};
117
+ vDSP_fft_zop(fftSetup, &inSplit, 1, &outSplit, 1, log2, kFFTDirection_Inverse);
118
+ }
119
+
120
+ private:
121
+ size_t _size = 0;
122
+ bool hasSetup = false;
123
+ FFTSetup fftSetup;
124
+ int log2 = 0;
125
+ std::vector<float> splitReal, splitImag;
126
+ };
127
+
128
+ template<>
129
+ struct Pow2RealFFT<float> {
130
+ static constexpr bool prefersSplit = true;
131
+
132
+ using Complex = std::complex<float>;
133
+
134
+ Pow2RealFFT(size_t size = 0) {
135
+ resize(size);
136
+ }
137
+ ~Pow2RealFFT() {
138
+ if (hasSetup) vDSP_destroy_fftsetup(fftSetup);
139
+ }
140
+
141
+ void resize(size_t size) {
142
+ _size = size;
143
+ if (hasSetup) vDSP_destroy_fftsetup(fftSetup);
144
+ if (!size) {
145
+ hasSetup = false;
146
+ return;
147
+ }
148
+
149
+ splitReal.resize(size);
150
+ splitImag.resize(size);
151
+ log2 = std::log2(size);
152
+ fftSetup = vDSP_create_fftsetup(log2, FFT_RADIX2);
153
+ hasSetup = true;
154
+ }
155
+
156
+ void fft(const float* input, Complex* output) {
157
+ float mul = 0.5f;
158
+ vDSP_vsmul(input, 2, &mul, splitReal.data(), 1, _size/2);
159
+ vDSP_vsmul(input + 1, 2, &mul, splitImag.data(), 1, _size/2);
160
+ DSPSplitComplex tmpSplit{splitReal.data(), splitImag.data()};
161
+ vDSP_fft_zrip(fftSetup, &tmpSplit, 1, log2, kFFTDirection_Forward);
162
+ vDSP_ztoc(&tmpSplit, 1, (DSPComplex *)output, 2, _size/2);
163
+ }
164
+ void fft(const float *inR, float *outR, float *outI) {
165
+ DSPSplitComplex outputSplit{outR, outI};
166
+ float mul = 0.5f;
167
+ vDSP_vsmul(inR, 2, &mul, outR, 1, _size/2);
168
+ vDSP_vsmul(inR + 1, 2, &mul, outI, 1, _size/2);
169
+ vDSP_fft_zrip(fftSetup, &outputSplit, 1, log2, kFFTDirection_Forward);
170
+ }
171
+
172
+ void ifft(const Complex * input, float * output) {
173
+ DSPSplitComplex tmpSplit{splitReal.data(), splitImag.data()};
174
+ vDSP_ctoz((DSPComplex*)input, 2, &tmpSplit, 1, _size/2);
175
+ vDSP_fft_zrip(fftSetup, &tmpSplit, 1, log2, kFFTDirection_Inverse);
176
+ DSPSplitComplex outputSplit{output, output + 1};
177
+ vDSP_zvmov(&tmpSplit, 1, &outputSplit, 2, _size/2);
178
+ }
179
+ void ifft(const float *inR, const float *inI, float *outR) {
180
+ DSPSplitComplex inputSplit{(float *)inR, (float *)inI};
181
+ DSPSplitComplex tmpSplit{splitReal.data(), splitImag.data()};
182
+ vDSP_fft_zrop(fftSetup, &inputSplit, 1, &tmpSplit, 1, log2, kFFTDirection_Inverse);
183
+ DSPSplitComplex outputSplit{outR, outR + 1};
184
+ // We can't use vDSP_ztoc without knowing the alignment
185
+ vDSP_zvmov(&tmpSplit, 1, &outputSplit, 2, _size/2);
186
+ }
187
+
188
+ private:
189
+ size_t _size = 0;
190
+ bool hasSetup = false;
191
+ FFTSetup fftSetup;
192
+ int log2 = 0;
193
+ std::vector<float> splitReal, splitImag;
194
+ };
195
+
196
+ template<>
197
+ struct Pow2FFT<double> {
198
+ static constexpr bool prefersSplit = true;
199
+
200
+ using Complex = std::complex<double>;
201
+
202
+ Pow2FFT(size_t size=0) {
203
+ resize(size);
204
+ }
205
+ ~Pow2FFT() {
206
+ if (hasSetup) vDSP_destroy_fftsetupD(fftSetup);
207
+ }
208
+
209
+ void resize(size_t size) {
210
+ _size = size;
211
+ if (hasSetup) vDSP_destroy_fftsetupD(fftSetup);
212
+ if (!size) {
213
+ hasSetup = false;
214
+ return;
215
+ }
216
+
217
+ log2 = std::round(std::log2(size));
218
+ fftSetup = vDSP_create_fftsetupD(log2, FFT_RADIX2);
219
+ hasSetup = true;
220
+
221
+ splitReal.resize(size);
222
+ splitImag.resize(size);
223
+ }
224
+
225
+ void fft(const Complex* input, Complex* output) {
226
+ DSPDoubleSplitComplex splitComplex{ splitReal.data(), splitImag.data() };
227
+ vDSP_ctozD((DSPDoubleComplex*)input, 2, &splitComplex, 1, _size);
228
+ vDSP_fft_zipD(fftSetup, &splitComplex, 1, log2, kFFTDirection_Forward);
229
+ vDSP_ztocD(&splitComplex, 1, (DSPDoubleComplex*)output, 2, _size);
230
+ }
231
+ void fft(const double *inR, const double *inI, double *outR, double *outI) {
232
+ DSPDoubleSplitComplex inSplit{(double *)inR, (double *)inI};
233
+ DSPDoubleSplitComplex outSplit{outR, outI};
234
+ vDSP_fft_zopD(fftSetup, &inSplit, 1, &outSplit, 1, log2, kFFTDirection_Forward);
235
+ }
236
+
237
+ void ifft(const Complex* input, Complex* output) {
238
+ DSPDoubleSplitComplex splitComplex{ splitReal.data(), splitImag.data() };
239
+ vDSP_ctozD((DSPDoubleComplex*)input, 2, &splitComplex, 1, _size);
240
+ vDSP_fft_zipD(fftSetup, &splitComplex, 1, log2, kFFTDirection_Inverse);
241
+ vDSP_ztocD(&splitComplex, 1, (DSPDoubleComplex*)output, 2, _size);
242
+ }
243
+ void ifft(const double *inR, const double *inI, double *outR, double *outI) {
244
+ DSPDoubleSplitComplex inSplit{(double *)inR, (double *)inI};
245
+ DSPDoubleSplitComplex outSplit{outR, outI};
246
+ vDSP_fft_zopD(fftSetup, &inSplit, 1, &outSplit, 1, log2, kFFTDirection_Inverse);
247
+ }
248
+
249
+ private:
250
+ size_t _size = 0;
251
+ bool hasSetup = false;
252
+ FFTSetupD fftSetup;
253
+ int log2 = 0;
254
+ std::vector<double> splitReal, splitImag;
255
+ };
256
+
257
+ template<>
258
+ struct Pow2RealFFT<double> {
259
+ static constexpr bool prefersSplit = true;
260
+
261
+ using Complex = std::complex<double>;
262
+
263
+ Pow2RealFFT(size_t size = 0) {
264
+ resize(size);
265
+ }
266
+ ~Pow2RealFFT() {
267
+ if (hasSetup) vDSP_destroy_fftsetupD(fftSetup);
268
+ }
269
+
270
+ void resize(size_t size) {
271
+ _size = size;
272
+ if (hasSetup) vDSP_destroy_fftsetupD(fftSetup);
273
+ if (!size) {
274
+ hasSetup = false;
275
+ return;
276
+ }
277
+
278
+ splitReal.resize(size);
279
+ splitImag.resize(size);
280
+ log2 = std::log2(size);
281
+ fftSetup = vDSP_create_fftsetupD(log2, FFT_RADIX2);
282
+ hasSetup = true;
283
+ }
284
+
285
+ void fft(const double* input, Complex* output) {
286
+ double mul = 0.5f;
287
+ vDSP_vsmulD(input, 2, &mul, splitReal.data(), 1, _size/2);
288
+ vDSP_vsmulD(input + 1, 2, &mul, splitImag.data(), 1, _size/2);
289
+ DSPDoubleSplitComplex tmpSplit{splitReal.data(), splitImag.data()};
290
+ vDSP_fft_zripD(fftSetup, &tmpSplit, 1, log2, kFFTDirection_Forward);
291
+ vDSP_ztocD(&tmpSplit, 1, (DSPDoubleComplex *)output, 2, _size/2);
292
+ }
293
+ void fft(const double *inR, double *outR, double *outI) {
294
+ DSPDoubleSplitComplex outputSplit{outR, outI};
295
+ double mul = 0.5f;
296
+ vDSP_vsmulD(inR, 2, &mul, outR, 1, _size/2);
297
+ vDSP_vsmulD(inR + 1, 2, &mul, outI, 1, _size/2);
298
+ vDSP_fft_zripD(fftSetup, &outputSplit, 1, log2, kFFTDirection_Forward);
299
+ }
300
+
301
+ void ifft(const Complex * input, double * output) {
302
+ DSPDoubleSplitComplex tmpSplit{splitReal.data(), splitImag.data()};
303
+ vDSP_ctozD((DSPDoubleComplex*)input, 2, &tmpSplit, 1, _size/2);
304
+ vDSP_fft_zripD(fftSetup, &tmpSplit, 1, log2, kFFTDirection_Inverse);
305
+ DSPDoubleSplitComplex outputSplit{output, output + 1};
306
+ vDSP_zvmovD(&tmpSplit, 1, &outputSplit, 2, _size/2);
307
+ }
308
+ void ifft(const double *inR, const double *inI, double *outR) {
309
+ DSPDoubleSplitComplex inputSplit{(double *)inR, (double *)inI};
310
+ DSPDoubleSplitComplex tmpSplit{splitReal.data(), splitImag.data()};
311
+ vDSP_fft_zropD(fftSetup, &inputSplit, 1, &tmpSplit, 1, log2, kFFTDirection_Inverse);
312
+ DSPDoubleSplitComplex outputSplit{outR, outR + 1};
313
+ // We can't use vDSP_ztoc without knowing the alignment
314
+ vDSP_zvmovD(&tmpSplit, 1, &outputSplit, 2, _size/2);
315
+ }
316
+
317
+ private:
318
+ size_t _size = 0;
319
+ bool hasSetup = false;
320
+ FFTSetupD fftSetup;
321
+ int log2 = 0;
322
+ std::vector<double> splitReal, splitImag;
323
+ };
324
+
325
+ }} // namespace
326
+ #endif