react-native-audio-api 0.5.5 → 0.5.7

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 (44) hide show
  1. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +28 -0
  2. package/common/cpp/audioapi/HostObjects/OfflineAudioContextHostObject.h +70 -0
  3. package/common/cpp/audioapi/core/OfflineAudioContext.cpp +117 -0
  4. package/common/cpp/audioapi/core/OfflineAudioContext.h +40 -0
  5. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +3 -3
  6. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +28 -2
  7. package/common/cpp/audioapi/core/utils/AudioNodeDestructor.cpp +53 -0
  8. package/common/cpp/audioapi/core/utils/AudioNodeDestructor.h +33 -0
  9. package/common/cpp/audioapi/core/utils/AudioNodeManager.cpp +13 -10
  10. package/common/cpp/audioapi/core/utils/AudioNodeManager.h +3 -0
  11. package/common/cpp/audioapi/libs/signalsmith-stretch/fft-accelerate.h +326 -0
  12. package/common/cpp/audioapi/libs/signalsmith-stretch/fft.h +1257 -413
  13. package/common/cpp/audioapi/libs/signalsmith-stretch/signalsmith-stretch.h +398 -232
  14. package/common/cpp/audioapi/libs/signalsmith-stretch/stft.h +625 -0
  15. package/lib/module/api.js +2 -1
  16. package/lib/module/api.js.map +1 -1
  17. package/lib/module/api.web.js +1 -0
  18. package/lib/module/api.web.js.map +1 -1
  19. package/lib/module/core/OfflineAudioContext.js +57 -0
  20. package/lib/module/core/OfflineAudioContext.js.map +1 -0
  21. package/lib/module/web-core/OfflineAudioContext.js +90 -0
  22. package/lib/module/web-core/OfflineAudioContext.js.map +1 -0
  23. package/lib/typescript/api.d.ts +3 -1
  24. package/lib/typescript/api.d.ts.map +1 -1
  25. package/lib/typescript/api.web.d.ts +1 -0
  26. package/lib/typescript/api.web.d.ts.map +1 -1
  27. package/lib/typescript/core/OfflineAudioContext.d.ts +14 -0
  28. package/lib/typescript/core/OfflineAudioContext.d.ts.map +1 -0
  29. package/lib/typescript/interfaces.d.ts +6 -0
  30. package/lib/typescript/interfaces.d.ts.map +1 -1
  31. package/lib/typescript/types.d.ts +5 -0
  32. package/lib/typescript/types.d.ts.map +1 -1
  33. package/lib/typescript/web-core/OfflineAudioContext.d.ts +34 -0
  34. package/lib/typescript/web-core/OfflineAudioContext.d.ts.map +1 -0
  35. package/package.json +1 -1
  36. package/src/api.ts +11 -2
  37. package/src/api.web.ts +1 -0
  38. package/src/core/OfflineAudioContext.ts +94 -0
  39. package/src/interfaces.ts +11 -0
  40. package/src/types.ts +6 -0
  41. package/src/web-core/OfflineAudioContext.tsx +163 -0
  42. package/common/cpp/audioapi/libs/signalsmith-stretch/delay.h +0 -715
  43. package/common/cpp/audioapi/libs/signalsmith-stretch/perf.h +0 -82
  44. package/common/cpp/audioapi/libs/signalsmith-stretch/spectral.h +0 -493
@@ -1,715 +0,0 @@
1
- #ifndef SIGNALSMITH_DSP_DELAY_H
2
- #define SIGNALSMITH_DSP_DELAY_H
3
-
4
- #include <vector>
5
- #include <array>
6
- #include <cmath> // for std::ceil()
7
- #include <type_traits>
8
- #include <complex>
9
-
10
- #include <audioapi/libs/signalsmith-stretch/fft.h>
11
- #include <audioapi/dsp/Windows.h>
12
-
13
- namespace signalsmith {
14
- namespace delay {
15
- /** @defgroup Delay Delay utilities
16
- @brief Standalone templated classes for delays
17
-
18
- You can set up a `Buffer` or `MultiBuffer`, and get interpolated samples using a `Reader` (separately on each channel in the multi-channel case) - or you can use `Delay`/`MultiDelay` which include their own buffers.
19
-
20
- Interpolation quality is chosen using a template class, from @ref Interpolators.
21
-
22
- @{
23
- @file
24
- */
25
-
26
- /** @brief Single-channel delay buffer
27
-
28
- Access is used with `buffer[]`, relative to the internal read/write position ("head"). This head is moved using `++buffer` (or `buffer += n`), such that `buffer[1] == (buffer + 1)[0]` in a similar way iterators/pointers.
29
-
30
- Operations like `buffer - 10` or `buffer++` return a View, which holds a fixed position in the buffer (based on the read/write position at the time).
31
-
32
- The capacity includes both positive and negative indices. For example, a capacity of 100 would support using any of the ranges:
33
-
34
- * `buffer[-99]` to buffer[0]`
35
- * `buffer[-50]` to buffer[49]`
36
- * `buffer[0]` to buffer[99]`
37
-
38
- Although buffers are usually used with historical samples accessed using negative indices e.g. `buffer[-10]`, you could equally use it flipped around (moving the head backwards through the buffer using `--buffer`).
39
- */
40
- template<typename Sample>
41
- class Buffer {
42
- unsigned bufferIndex;
43
- unsigned bufferMask;
44
- std::vector<Sample> buffer;
45
- public:
46
- Buffer(int minCapacity=0) {
47
- resize(minCapacity);
48
- }
49
- // We shouldn't accidentally copy a delay buffer
50
- Buffer(const Buffer &other) = delete;
51
- Buffer & operator =(const Buffer &other) = delete;
52
- // But moving one is fine
53
- Buffer(Buffer &&other) = default;
54
- Buffer & operator =(Buffer &&other) = default;
55
-
56
- void resize(int minCapacity, Sample value=Sample()) {
57
- int bufferLength = 1;
58
- while (bufferLength < minCapacity) bufferLength *= 2;
59
- buffer.assign(bufferLength, value);
60
- bufferMask = unsigned(bufferLength - 1);
61
- bufferIndex = 0;
62
- }
63
- void reset(Sample value=Sample()) {
64
- buffer.assign(buffer.size(), value);
65
- }
66
-
67
- /// Holds a view for a particular position in the buffer
68
- template<bool isConst>
69
- class View {
70
- using CBuffer = typename std::conditional<isConst, const Buffer, Buffer>::type;
71
- using CSample = typename std::conditional<isConst, const Sample, Sample>::type;
72
- CBuffer *buffer = nullptr;
73
- unsigned bufferIndex = 0;
74
- public:
75
- View(CBuffer &buffer, int offset=0) : buffer(&buffer), bufferIndex(buffer.bufferIndex + (unsigned)offset) {}
76
- View(const View &other, int offset=0) : buffer(other.buffer), bufferIndex(other.bufferIndex + (unsigned)offset) {}
77
- View & operator =(const View &other) {
78
- buffer = other.buffer;
79
- bufferIndex = other.bufferIndex;
80
- return *this;
81
- }
82
-
83
- CSample & operator[](int offset) {
84
- return buffer->buffer[(bufferIndex + (unsigned)offset)&buffer->bufferMask];
85
- }
86
- const Sample & operator[](int offset) const {
87
- return buffer->buffer[(bufferIndex + (unsigned)offset)&buffer->bufferMask];
88
- }
89
-
90
- /// Write data into the buffer
91
- template<typename Data>
92
- void write(Data &&data, int length) {
93
- for (int i = 0; i < length; ++i) {
94
- (*this)[i] = data[i];
95
- }
96
- }
97
- /// Read data out from the buffer
98
- template<typename Data>
99
- void read(int length, Data &&data) const {
100
- for (int i = 0; i < length; ++i) {
101
- data[i] = (*this)[i];
102
- }
103
- }
104
-
105
- View operator +(int offset) const {
106
- return View(*this, offset);
107
- }
108
- View operator -(int offset) const {
109
- return View(*this, -offset);
110
- }
111
- };
112
- using MutableView = View<false>;
113
- using ConstView = View<true>;
114
-
115
- MutableView view(int offset=0) {
116
- return MutableView(*this, offset);
117
- }
118
- ConstView view(int offset=0) const {
119
- return ConstView(*this, offset);
120
- }
121
- ConstView constView(int offset=0) const {
122
- return ConstView(*this, offset);
123
- }
124
-
125
- Sample & operator[](int offset) {
126
- return buffer[(bufferIndex + (unsigned)offset)&bufferMask];
127
- }
128
- const Sample & operator[](int offset) const {
129
- return buffer[(bufferIndex + (unsigned)offset)&bufferMask];
130
- }
131
-
132
- /// Write data into the buffer
133
- template<typename Data>
134
- void write(Data &&data, int length) {
135
- for (int i = 0; i < length; ++i) {
136
- (*this)[i] = data[i];
137
- }
138
- }
139
- /// Read data out from the buffer
140
- template<typename Data>
141
- void read(int length, Data &&data) const {
142
- for (int i = 0; i < length; ++i) {
143
- data[i] = (*this)[i];
144
- }
145
- }
146
-
147
- Buffer & operator ++() {
148
- ++bufferIndex;
149
- return *this;
150
- }
151
- Buffer & operator +=(int i) {
152
- bufferIndex += (unsigned)i;
153
- return *this;
154
- }
155
- Buffer & operator --() {
156
- --bufferIndex;
157
- return *this;
158
- }
159
- Buffer & operator -=(int i) {
160
- bufferIndex -= (unsigned)i;
161
- return *this;
162
- }
163
-
164
- MutableView operator ++(int) {
165
- MutableView view(*this);
166
- ++bufferIndex;
167
- return view;
168
- }
169
- MutableView operator +(int i) {
170
- return MutableView(*this, i);
171
- }
172
- ConstView operator +(int i) const {
173
- return ConstView(*this, i);
174
- }
175
- MutableView operator --(int) {
176
- MutableView view(*this);
177
- --bufferIndex;
178
- return view;
179
- }
180
- MutableView operator -(int i) {
181
- return MutableView(*this, -i);
182
- }
183
- ConstView operator -(int i) const {
184
- return ConstView(*this, -i);
185
- }
186
- };
187
-
188
- /** @brief Multi-channel delay buffer
189
-
190
- This behaves similarly to the single-channel `Buffer`, with the following differences:
191
-
192
- * `buffer[c]` returns a view for a single channel, which behaves like the single-channel `Buffer::View`.
193
- * The constructor and `.resize()` take an additional first `channel` argument.
194
- */
195
- template<typename Sample>
196
- class MultiBuffer {
197
- int channels, stride;
198
- Buffer<Sample> buffer;
199
- public:
200
- using ConstChannel = typename Buffer<Sample>::ConstView;
201
- using MutableChannel = typename Buffer<Sample>::MutableView;
202
-
203
- MultiBuffer(int channels=0, int capacity=0) : channels(channels), stride(capacity), buffer(channels*capacity) {}
204
-
205
- void resize(int nChannels, int capacity, Sample value=Sample()) {
206
- channels = nChannels;
207
- stride = capacity;
208
- buffer.resize(channels*capacity, value);
209
- }
210
- void reset(Sample value=Sample()) {
211
- buffer.reset(value);
212
- }
213
-
214
- /// A reference-like multi-channel result for a particular sample index
215
- template<bool isConst>
216
- class Stride {
217
- using CChannel = typename std::conditional<isConst, ConstChannel, MutableChannel>::type;
218
- using CSample = typename std::conditional<isConst, const Sample, Sample>::type;
219
- CChannel view;
220
- int channels, stride;
221
- public:
222
- Stride(CChannel view, int channels, int stride) : view(view), channels(channels), stride(stride) {}
223
- Stride(const Stride &other) : view(other.view), channels(other.channels), stride(other.stride) {}
224
-
225
- CSample & operator[](int channel) {
226
- return view[channel*stride];
227
- }
228
- const Sample & operator[](int channel) const {
229
- return view[channel*stride];
230
- }
231
-
232
- /// Reads from the buffer into a multi-channel result
233
- template<class Data>
234
- void get(Data &&result) const {
235
- for (int c = 0; c < channels; ++c) {
236
- result[c] = view[c*stride];
237
- }
238
- }
239
- /// Writes from multi-channel data into the buffer
240
- template<class Data>
241
- void set(Data &&data) {
242
- for (int c = 0; c < channels; ++c) {
243
- view[c*stride] = data[c];
244
- }
245
- }
246
- template<class Data>
247
- Stride & operator =(const Data &data) {
248
- set(data);
249
- return *this;
250
- }
251
- Stride & operator =(const Stride &data) {
252
- set(data);
253
- return *this;
254
- }
255
- };
256
-
257
- Stride<false> at(int offset) {
258
- return {buffer.view(offset), channels, stride};
259
- }
260
- Stride<true> at(int offset) const {
261
- return {buffer.view(offset), channels, stride};
262
- }
263
-
264
- /// Holds a particular position in the buffer
265
- template<bool isConst>
266
- class View {
267
- using CChannel = typename std::conditional<isConst, ConstChannel, MutableChannel>::type;
268
- CChannel view;
269
- int channels, stride;
270
- public:
271
- View(CChannel view, int channels, int stride) : view(view), channels(channels), stride(stride) {}
272
-
273
- CChannel operator[](int channel) {
274
- return view + channel*stride;
275
- }
276
- ConstChannel operator[](int channel) const {
277
- return view + channel*stride;
278
- }
279
-
280
- Stride<isConst> at(int offset) {
281
- return {view + offset, channels, stride};
282
- }
283
- Stride<true> at(int offset) const {
284
- return {view + offset, channels, stride};
285
- }
286
- };
287
- using MutableView = View<false>;
288
- using ConstView = View<true>;
289
-
290
- MutableView view(int offset=0) {
291
- return MutableView(buffer.view(offset), channels, stride);
292
- }
293
- ConstView view(int offset=0) const {
294
- return ConstView(buffer.view(offset), channels, stride);
295
- }
296
- ConstView constView(int offset=0) const {
297
- return ConstView(buffer.view(offset), channels, stride);
298
- }
299
-
300
- MutableChannel operator[](int channel) {
301
- return buffer + channel*stride;
302
- }
303
- ConstChannel operator[](int channel) const {
304
- return buffer + channel*stride;
305
- }
306
-
307
- MultiBuffer & operator ++() {
308
- ++buffer;
309
- return *this;
310
- }
311
- MultiBuffer & operator +=(int i) {
312
- buffer += i;
313
- return *this;
314
- }
315
- MutableView operator ++(int) {
316
- return MutableView(buffer++, channels, stride);
317
- }
318
- MutableView operator +(int i) {
319
- return MutableView(buffer + i, channels, stride);
320
- }
321
- ConstView operator +(int i) const {
322
- return ConstView(buffer + i, channels, stride);
323
- }
324
- MultiBuffer & operator --() {
325
- --buffer;
326
- return *this;
327
- }
328
- MultiBuffer & operator -=(int i) {
329
- buffer -= i;
330
- return *this;
331
- }
332
- MutableView operator --(int) {
333
- return MutableView(buffer--, channels, stride);
334
- }
335
- MutableView operator -(int i) {
336
- return MutableView(buffer - i, channels, stride);
337
- }
338
- ConstView operator -(int i) const {
339
- return ConstView(buffer - i, channels, stride);
340
- }
341
- };
342
-
343
- /** \defgroup Interpolators Interpolators
344
- \ingroup Delay
345
- @{ */
346
- /// Nearest-neighbour interpolator
347
- /// \diagram{delay-random-access-nearest.svg,aliasing and maximum amplitude/delay errors for different input frequencies}
348
- template<typename Sample>
349
- struct InterpolatorNearest {
350
- static constexpr int inputLength = 1;
351
- static constexpr Sample latency = -0.5; // Because we're truncating, which rounds down too often
352
-
353
- template<class Data>
354
- static Sample fractional(const Data &data, Sample) {
355
- return data[0];
356
- }
357
- };
358
- /// Linear interpolator
359
- /// \diagram{delay-random-access-linear.svg,aliasing and maximum amplitude/delay errors for different input frequencies}
360
- template<typename Sample>
361
- struct InterpolatorLinear {
362
- static constexpr int inputLength = 2;
363
- static constexpr int latency = 0;
364
-
365
- template<class Data>
366
- static Sample fractional(const Data &data, Sample fractional) {
367
- Sample a = data[0], b = data[1];
368
- return a + fractional*(b - a);
369
- }
370
- };
371
- /// Spline cubic interpolator
372
- /// \diagram{delay-random-access-cubic.svg,aliasing and maximum amplitude/delay errors for different input frequencies}
373
- template<typename Sample>
374
- struct InterpolatorCubic {
375
- static constexpr int inputLength = 4;
376
- static constexpr int latency = 1;
377
-
378
- template<class Data>
379
- static Sample fractional(const Data &data, Sample fractional) {
380
- // Cubic interpolation
381
- Sample a = data[0], b = data[1], c = data[2], d = data[3];
382
- Sample cbDiff = c - b;
383
- Sample k1 = (c - a)*0.5;
384
- Sample k3 = k1 + (d - b)*0.5 - cbDiff*2;
385
- Sample k2 = cbDiff - k3 - k1;
386
- return b + fractional*(k1 + fractional*(k2 + fractional*k3)); // 16 ops total, not including the indexing
387
- }
388
- };
389
-
390
- // Efficient Algorithms and Structures for Fractional Delay Filtering Based on Lagrange Interpolation
391
- // Franck 2009 https://www.aes.org/e-lib/browse.cfm?elib=14647
392
- namespace _franck_impl {
393
- template<typename Sample, int n, int low, int high>
394
- struct ProductRange {
395
- using Array = std::array<Sample, (n + 1)>;
396
- static constexpr int mid = (low + high)/2;
397
- using Left = ProductRange<Sample, n, low, mid>;
398
- using Right = ProductRange<Sample, n, mid + 1, high>;
399
-
400
- Left left;
401
- Right right;
402
-
403
- const Sample total;
404
- ProductRange(Sample x) : left(x), right(x), total(left.total*right.total) {}
405
-
406
- template<class Data>
407
- Sample calculateResult(Sample extraFactor, const Data &data, const Array &invFactors) {
408
- return left.calculateResult(extraFactor*right.total, data, invFactors)
409
- + right.calculateResult(extraFactor*left.total, data, invFactors);
410
- }
411
- };
412
- template<typename Sample, int n, int index>
413
- struct ProductRange<Sample, n, index, index> {
414
- using Array = std::array<Sample, (n + 1)>;
415
-
416
- const Sample total;
417
- ProductRange(Sample x) : total(x - index) {}
418
-
419
- template<class Data>
420
- Sample calculateResult(Sample extraFactor, const Data &data, const Array &invFactors) {
421
- return extraFactor*data[index]*invFactors[index];
422
- }
423
- };
424
- }
425
- /** Fixed-order Lagrange interpolation.
426
- \diagram{interpolator-LagrangeN.svg,aliasing and amplitude/delay errors for different sizes}
427
- */
428
- template<typename Sample, int n>
429
- struct InterpolatorLagrangeN {
430
- static constexpr int inputLength = n + 1;
431
- static constexpr int latency = (n - 1)/2;
432
-
433
- using Array = std::array<Sample, (n + 1)>;
434
- Array invDivisors;
435
-
436
- InterpolatorLagrangeN() {
437
- for (int j = 0; j <= n; ++j) {
438
- double divisor = 1;
439
- for (int k = 0; k < j; ++k) divisor *= (j - k);
440
- for (int k = j + 1; k <= n; ++k) divisor *= (j - k);
441
- invDivisors[j] = 1/divisor;
442
- }
443
- }
444
-
445
- template<class Data>
446
- Sample fractional(const Data &data, Sample fractional) const {
447
- constexpr int mid = n/2;
448
- using Left = _franck_impl::ProductRange<Sample, n, 0, mid>;
449
- using Right = _franck_impl::ProductRange<Sample, n, mid + 1, n>;
450
-
451
- Sample x = fractional + latency;
452
-
453
- Left left(x);
454
- Right right(x);
455
-
456
- return left.calculateResult(right.total, data, invDivisors) + right.calculateResult(left.total, data, invDivisors);
457
- }
458
- };
459
- template<typename Sample>
460
- using InterpolatorLagrange3 = InterpolatorLagrangeN<Sample, 3>;
461
- template<typename Sample>
462
- using InterpolatorLagrange7 = InterpolatorLagrangeN<Sample, 7>;
463
- template<typename Sample>
464
- using InterpolatorLagrange19 = InterpolatorLagrangeN<Sample, 19>;
465
-
466
- /** Fixed-size Kaiser-windowed sinc interpolation.
467
- \diagram{interpolator-KaiserSincN.svg,aliasing and amplitude/delay errors for different sizes}
468
- If `minimumPhase` is enabled, a minimum-phase version of the kernel is used:
469
- \diagram{interpolator-KaiserSincN-min.svg,aliasing and amplitude/delay errors for minimum-phase mode}
470
- */
471
- template<typename Sample, int n, bool minimumPhase=false>
472
- struct InterpolatorKaiserSincN {
473
- static constexpr int inputLength = n;
474
- static constexpr Sample latency = minimumPhase ? 0 : (n*Sample(0.5) - 1);
475
-
476
- int subSampleSteps;
477
- std::vector<Sample> coefficients;
478
-
479
- InterpolatorKaiserSincN() : InterpolatorKaiserSincN(0.5 - 0.45/std::sqrt(n)) {}
480
- InterpolatorKaiserSincN(double passFreq) : InterpolatorKaiserSincN(passFreq, 1 - passFreq) {}
481
- InterpolatorKaiserSincN(double passFreq, double stopFreq) {
482
- subSampleSteps = 2*n; // Heuristic again. Really it depends on the bandwidth as well.
483
- float kaiserBandwidth = (stopFreq - passFreq)*(n + 1.0/subSampleSteps);
484
- kaiserBandwidth += 1.25f / kaiserBandwidth; // We want to place the first zero, but (because using this to window a sinc essentially integrates it in the freq-domain), our ripples (and therefore zeroes) are out of phase. This is a heuristic fix.
485
- double sincScale = audioapi::PI*(passFreq + stopFreq);
486
-
487
- double centreIndex = n*subSampleSteps*0.5, scaleFactor = 1.0/subSampleSteps;
488
- std::vector<Sample> windowedSinc(subSampleSteps*n + 1);
489
-
490
- audioapi::dsp::Kaiser::withBandwidth(kaiserBandwidth, false).apply(windowedSinc.data(), windowedSinc.size());
491
-
492
- for (size_t i = 0; i < windowedSinc.size(); ++i) {
493
- double x = (i - centreIndex)*scaleFactor;
494
- int intX = std::round(x);
495
- if (intX != 0 && std::abs(x - intX) < 1e-6) {
496
- // Exact 0s
497
- windowedSinc[i] = 0;
498
- } else if (std::abs(x) > 1e-6) {
499
- double p = x*sincScale;
500
- windowedSinc[i] *= std::sin(p)/p;
501
- }
502
- }
503
-
504
- if (minimumPhase) {
505
- signalsmith::fft::FFT<Sample> fft(windowedSinc.getSize()*2, 1);
506
- windowedSinc.resize(fft.size(), 0);
507
- std::vector<std::complex<Sample>> spectrum(fft.size());
508
- std::vector<std::complex<Sample>> cepstrum(fft.size());
509
- fft.fft(windowedSinc, spectrum);
510
- for (size_t i = 0; i < fft.size(); ++i) {
511
- spectrum[i] = std::log(std::abs(spectrum[i]) + 1e-30);
512
- }
513
- fft.fft(spectrum, cepstrum);
514
- for (size_t i = 1; i < fft.size()/2; ++i) {
515
- cepstrum[i] *= 0;
516
- }
517
- for (size_t i = fft.size()/2 + 1; i < fft.size(); ++i) {
518
- cepstrum[i] *= 2;
519
- }
520
- Sample scaling = Sample(1)/fft.size();
521
- fft.ifft(cepstrum, spectrum);
522
-
523
- for (size_t i = 0; i < fft.size(); ++i) {
524
- Sample phase = spectrum[i].imag()*scaling;
525
- Sample mag = std::exp(spectrum[i].real()*scaling);
526
- spectrum[i] = {mag*std::cos(phase), mag*std::sin(phase)};
527
- }
528
- fft.ifft(spectrum, cepstrum);
529
- windowedSinc.resize(subSampleSteps*n + 1);
530
- windowedSinc.shrink_to_fit();
531
- for (size_t i = 0; i < windowedSinc.size(); ++i) {
532
- windowedSinc[i] = cepstrum[i].real()*scaling;
533
- }
534
- }
535
-
536
- // Re-order into FIR fractional-delay blocks
537
- coefficients.resize(n*(subSampleSteps + 1));
538
- for (int k = 0; k <= subSampleSteps; ++k) {
539
- for (int i = 0; i < n; ++i) {
540
- coefficients[k*n + i] = windowedSinc[(subSampleSteps - k) + i*subSampleSteps];
541
- }
542
- }
543
- }
544
-
545
- template<class Data>
546
- Sample fractional(const Data &data, Sample fractional) const {
547
- Sample subSampleDelay = fractional*subSampleSteps;
548
- int lowIndex = subSampleDelay;
549
- if (lowIndex >= subSampleSteps) lowIndex = subSampleSteps - 1;
550
- Sample subSampleFractional = subSampleDelay - lowIndex;
551
- int highIndex = lowIndex + 1;
552
-
553
- Sample sumLow = 0, sumHigh = 0;
554
- const Sample *coeffLow = coefficients.data() + lowIndex*n;
555
- const Sample *coeffHigh = coefficients.data() + highIndex*n;
556
- for (int i = 0; i < n; ++i) {
557
- sumLow += data[i]*coeffLow[i];
558
- sumHigh += data[i]*coeffHigh[i];
559
- }
560
- return sumLow + (sumHigh - sumLow)*subSampleFractional;
561
- }
562
- };
563
-
564
- template<typename Sample>
565
- using InterpolatorKaiserSinc20 = InterpolatorKaiserSincN<Sample, 20>;
566
- template<typename Sample>
567
- using InterpolatorKaiserSinc8 = InterpolatorKaiserSincN<Sample, 8>;
568
- template<typename Sample>
569
- using InterpolatorKaiserSinc4 = InterpolatorKaiserSincN<Sample, 4>;
570
-
571
- template<typename Sample>
572
- using InterpolatorKaiserSinc20Min = InterpolatorKaiserSincN<Sample, 20, true>;
573
- template<typename Sample>
574
- using InterpolatorKaiserSinc8Min = InterpolatorKaiserSincN<Sample, 8, true>;
575
- template<typename Sample>
576
- using InterpolatorKaiserSinc4Min = InterpolatorKaiserSincN<Sample, 4, true>;
577
- /// @}
578
-
579
- /** @brief A delay-line reader which uses an external buffer
580
-
581
- This is useful if you have multiple delay-lines reading from the same buffer.
582
- */
583
- template<class Sample, template<typename> class Interpolator=InterpolatorLinear>
584
- class Reader : public Interpolator<Sample> /* so we can get the empty-base-class optimisation */ {
585
- using Super = Interpolator<Sample>;
586
- public:
587
- Reader () {}
588
- /// Pass in a configured interpolator
589
- Reader (const Interpolator<Sample> &interpolator) : Super(interpolator) {}
590
-
591
- template<typename Buffer>
592
- Sample read(const Buffer &buffer, Sample delaySamples) const {
593
- int startIndex = delaySamples;
594
- Sample remainder = delaySamples - startIndex;
595
-
596
- // Delay buffers use negative indices, but interpolators use positive ones
597
- using View = decltype(buffer - startIndex);
598
- struct Flipped {
599
- View view;
600
- Sample operator [](int i) const {
601
- return view[-i];
602
- }
603
- };
604
- return Super::fractional(Flipped{buffer - startIndex}, remainder);
605
- }
606
- };
607
-
608
- /** @brief A single-channel delay-line containing its own buffer.*/
609
- template<class Sample, template<typename> class Interpolator=InterpolatorLinear>
610
- class Delay : private Reader<Sample, Interpolator> {
611
- using Super = Reader<Sample, Interpolator>;
612
- Buffer<Sample> buffer;
613
- public:
614
- static constexpr Sample latency = Super::latency;
615
-
616
- Delay(int capacity=0) : buffer(1 + capacity + Super::inputLength) {}
617
- /// Pass in a configured interpolator
618
- Delay(const Interpolator<Sample> &interp, int capacity=0) : Super(interp), buffer(1 + capacity + Super::inputLength) {}
619
-
620
- void reset(Sample value=Sample()) {
621
- buffer.reset(value);
622
- }
623
- void resize(int minCapacity, Sample value=Sample()) {
624
- buffer.resize(minCapacity + Super::inputLength, value);
625
- }
626
-
627
- /** Read a sample from `delaySamples` >= 0 in the past.
628
- The interpolator may add its own latency on top of this (see `Delay::latency`). The default interpolation (linear) has 0 latency.
629
- */
630
- Sample read(Sample delaySamples) const {
631
- return Super::read(buffer, delaySamples);
632
- }
633
- /// Writes a sample. Returns the same object, so that you can say `delay.write(v).read(delay)`.
634
- Delay & write(Sample value) {
635
- ++buffer;
636
- buffer[0] = value;
637
- return *this;
638
- }
639
- };
640
-
641
- /** @brief A multi-channel delay-line with its own buffer. */
642
- template<class Sample, template<typename> class Interpolator=InterpolatorLinear>
643
- class MultiDelay : private Reader<Sample, Interpolator> {
644
- using Super = Reader<Sample, Interpolator>;
645
- int channels;
646
- MultiBuffer<Sample> multiBuffer;
647
- public:
648
- static constexpr Sample latency = Super::latency;
649
-
650
- MultiDelay(int channels=0, int capacity=0) : channels(channels), multiBuffer(channels, 1 + capacity + Super::inputLength) {}
651
-
652
- void reset(Sample value=Sample()) {
653
- multiBuffer.reset(value);
654
- }
655
- void resize(int nChannels, int capacity, Sample value=Sample()) {
656
- channels = nChannels;
657
- multiBuffer.resize(channels, capacity + Super::inputLength, value);
658
- }
659
-
660
- /// A single-channel delay-line view, similar to a `const Delay`
661
- struct ChannelView {
662
- static constexpr Sample latency = Super::latency;
663
-
664
- const Super &reader;
665
- typename MultiBuffer<Sample>::ConstChannel channel;
666
-
667
- Sample read(Sample delaySamples) const {
668
- return reader.read(channel, delaySamples);
669
- }
670
- };
671
- ChannelView operator [](int channel) const {
672
- return ChannelView{*this, multiBuffer[channel]};
673
- }
674
-
675
- /// A multi-channel result, lazily calculating samples
676
- struct DelayView {
677
- Super &reader;
678
- typename MultiBuffer<Sample>::ConstView view;
679
- Sample delaySamples;
680
-
681
- // Calculate samples on-the-fly
682
- Sample operator [](int c) const {
683
- return reader.read(view[c], delaySamples);
684
- }
685
- };
686
- DelayView read(Sample delaySamples) {
687
- return DelayView{*this, multiBuffer.constView(), delaySamples};
688
- }
689
- /// Reads into the provided output structure
690
- template<class Output>
691
- void read(Sample delaySamples, Output &output) {
692
- for (int c = 0; c < channels; ++c) {
693
- output[c] = Super::read(multiBuffer[c], delaySamples);
694
- }
695
- }
696
- /// Reads separate delays for each channel
697
- template<class Delays, class Output>
698
- void readMulti(const Delays &delays, Output &output) {
699
- for (int c = 0; c < channels; ++c) {
700
- output[c] = Super::read(multiBuffer[c], delays[c]);
701
- }
702
- }
703
- template<class Data>
704
- MultiDelay & write(const Data &data) {
705
- ++multiBuffer;
706
- for (int c = 0; c < channels; ++c) {
707
- multiBuffer[c][0] = data[c];
708
- }
709
- return *this;
710
- }
711
- };
712
-
713
- /** @} */
714
- }} // signalsmith::delay::
715
- #endif // include guard