react-native-audio-api 0.4.11 → 0.4.12-beta.1
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.
- package/common/cpp/HostObjects/AudioBufferSourceNodeHostObject.h +1 -2
- package/common/cpp/HostObjects/BaseAudioContextHostObject.h +8 -0
- package/common/cpp/HostObjects/GainNodeHostObject.h +2 -2
- package/common/cpp/HostObjects/StretcherNodeHostObject.h +35 -0
- package/common/cpp/core/AudioBus.cpp +8 -0
- package/common/cpp/core/AudioBus.h +3 -0
- package/common/cpp/core/AudioDestinationNode.cpp +1 -1
- package/common/cpp/core/AudioNode.cpp +9 -5
- package/common/cpp/core/AudioNode.h +4 -2
- package/common/cpp/core/BaseAudioContext.cpp +7 -0
- package/common/cpp/core/BaseAudioContext.h +2 -0
- package/common/cpp/core/StretcherNode.cpp +96 -0
- package/common/cpp/core/StretcherNode.h +63 -0
- package/common/cpp/installer/AudioAPIModuleInstaller.h +4 -4
- package/common/cpp/libs/dsp/LICENSE.txt +21 -0
- package/common/cpp/libs/dsp/README.md +40 -0
- package/common/cpp/libs/dsp/common.h +47 -0
- package/common/cpp/libs/dsp/curves.h +371 -0
- package/common/cpp/libs/dsp/delay.h +717 -0
- package/common/cpp/libs/dsp/envelopes.h +523 -0
- package/common/cpp/libs/dsp/fft.h +523 -0
- package/common/cpp/libs/dsp/filters.h +436 -0
- package/common/cpp/libs/dsp/mix.h +218 -0
- package/common/cpp/libs/dsp/perf.h +84 -0
- package/common/cpp/libs/dsp/rates.h +184 -0
- package/common/cpp/libs/dsp/spectral.h +496 -0
- package/common/cpp/libs/dsp/windows.h +219 -0
- package/common/cpp/libs/signalsmith-stretch.h +637 -0
- package/common/cpp/types/TimeStretchType.h +6 -0
- package/ios/core/AudioPlayer.m +2 -2
- package/lib/module/core/BaseAudioContext.js +4 -0
- package/lib/module/core/BaseAudioContext.js.map +1 -1
- package/lib/module/core/StretcherNode.js +12 -0
- package/lib/module/core/StretcherNode.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +1 -1
- package/lib/module/index.web.js.map +1 -1
- package/lib/typescript/core/BaseAudioContext.d.ts +2 -0
- package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/core/StretcherNode.d.ts +10 -0
- package/lib/typescript/core/StretcherNode.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/index.web.d.ts +1 -1
- package/lib/typescript/index.web.d.ts.map +1 -1
- package/lib/typescript/interfaces.d.ts +5 -0
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/BaseAudioContext.ts +5 -0
- package/src/core/StretcherNode.ts +15 -0
- package/src/index.ts +1 -0
- package/src/index.web.ts +1 -0
- package/src/interfaces.ts +6 -0
- package/common/cpp/installer/AudioAPIModuleInstaller.cpp +0 -49
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
#include "./common.h"
|
|
2
|
+
|
|
3
|
+
#ifndef SIGNALSMITH_FFT_V5
|
|
4
|
+
#define SIGNALSMITH_FFT_V5
|
|
5
|
+
|
|
6
|
+
#include "./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
|