react-native-audio-api 0.4.12-beta.1 → 0.4.12-beta.3

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 (114) hide show
  1. package/RNAudioAPI.podspec +14 -4
  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 +5 -3
  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 +5 -5
  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 +14 -15
  22. package/common/cpp/{HostObjects → audioapi/HostObjects}/BiquadFilterNodeHostObject.h +4 -4
  23. package/common/cpp/{HostObjects → audioapi/HostObjects}/GainNodeHostObject.h +4 -4
  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 +5 -7
  31. package/common/cpp/{core → audioapi/core}/AudioNode.h +5 -4
  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 +14 -17
  35. package/common/cpp/{core → audioapi/core}/BaseAudioContext.h +4 -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 +5 -5
  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/{core → audioapi/core/effects}/StretcherNode.cpp +4 -6
  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 +4 -7
  59. package/common/cpp/{core → audioapi/core/utils}/AudioBus.h +2 -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/{libs → audioapi/libs}/dsp/delay.h +35 -35
  75. package/common/cpp/{libs → audioapi/libs}/dsp/fft.h +21 -21
  76. package/common/cpp/{libs → audioapi/libs}/dsp/perf.h +3 -3
  77. package/common/cpp/{libs → audioapi/libs}/dsp/spectral.h +39 -39
  78. package/common/cpp/{libs → audioapi/libs}/dsp/windows.h +11 -11
  79. package/common/cpp/{libs → audioapi/libs}/signalsmith-stretch.h +30 -30
  80. package/ios/{AudioAPIModule.mm → audioapi/ios/AudioAPIModule.mm} +15 -8
  81. package/ios/{core → audioapi/ios/core}/AudioDecoder.mm +4 -4
  82. package/ios/{core → audioapi/ios/core}/AudioPlayer.m +1 -1
  83. package/ios/{core → audioapi/ios/core}/IOSAudioPlayer.mm +4 -4
  84. package/package.json +6 -6
  85. package/common/cpp/HostObjects/StretcherNodeHostObject.h +0 -35
  86. package/common/cpp/core/StretcherNode.h +0 -63
  87. package/common/cpp/libs/dsp/LICENSE.txt +0 -21
  88. package/common/cpp/libs/dsp/README.md +0 -40
  89. package/common/cpp/libs/dsp/curves.h +0 -371
  90. package/common/cpp/libs/dsp/envelopes.h +0 -523
  91. package/common/cpp/libs/dsp/filters.h +0 -436
  92. package/common/cpp/libs/dsp/mix.h +0 -218
  93. package/common/cpp/libs/dsp/rates.h +0 -184
  94. package/common/cpp/types/TimeStretchType.h +0 -6
  95. /package/android/src/main/cpp/{libs → audioapi/android/libs}/pffft.h +0 -0
  96. /package/common/cpp/{core → audioapi/core}/Constants.h +0 -0
  97. /package/common/cpp/{core → audioapi/core/sources}/AudioBuffer.h +0 -0
  98. /package/common/cpp/{types → audioapi/core/types}/BiquadFilterType.h +0 -0
  99. /package/common/cpp/{types → audioapi/core/types}/ChannelCountMode.h +0 -0
  100. /package/common/cpp/{types → audioapi/core/types}/ChannelInterpretation.h +0 -0
  101. /package/common/cpp/{types → audioapi/core/types}/ContextState.h +0 -0
  102. /package/common/cpp/{types → audioapi/core/types}/OscillatorType.h +0 -0
  103. /package/common/cpp/{types → audioapi/core/types}/ParamChangeEventType.h +0 -0
  104. /package/common/cpp/{core → audioapi/core/utils}/AudioArray.h +0 -0
  105. /package/common/cpp/{core → audioapi/core/utils}/AudioDecoder.h +0 -0
  106. /package/common/cpp/{core → audioapi/core/utils}/AudioNodeManager.h +0 -0
  107. /package/common/cpp/{utils → audioapi/core/utils}/Locker.h +0 -0
  108. /package/common/cpp/{utils → audioapi/dsp}/AudioUtils.h +0 -0
  109. /package/common/cpp/{jsi → audioapi/jsi}/JsiPromise.h +0 -0
  110. /package/common/cpp/{libs → audioapi/libs}/dsp/common.h +0 -0
  111. /package/common/cpp/{libs → audioapi/libs}/miniaudio.h +0 -0
  112. /package/ios/{AudioAPIModule.h → audioapi/ios/AudioAPIModule.h} +0 -0
  113. /package/ios/{core → audioapi/ios/core}/AudioPlayer.h +0 -0
  114. /package/ios/{core → audioapi/ios/core}/IOSAudioPlayer.h +0 -0
@@ -1,523 +0,0 @@
1
- #include "./common.h"
2
-
3
- #ifndef SIGNALSMITH_DSP_ENVELOPES_H
4
- #define SIGNALSMITH_DSP_ENVELOPES_H
5
-
6
- #include <cmath>
7
- #include <random>
8
- #include <vector>
9
- #include <iterator>
10
-
11
- namespace signalsmith {
12
- namespace envelopes {
13
- /** @defgroup Envelopes Envelopes and LFOs
14
- @brief LFOs, envelopes and filters for manipulating them
15
-
16
- @{
17
- @file
18
- */
19
-
20
- /** An LFO based on cubic segments.
21
- You can randomise the rate and/or the depth. Randomising the depth past `0.5` means it no longer neatly alternates sides:
22
- \diagram{cubic-lfo-example.svg,Some example LFO curves.}
23
- Without randomisation, it is approximately sine-like:
24
- \diagram{cubic-lfo-spectrum-pure.svg}
25
- */
26
- class CubicLfo {
27
- float ratio = 0;
28
- float ratioStep = 0;
29
-
30
- float valueFrom = 0, valueTo = 1, valueRange = 1;
31
- float targetLow = 0, targetHigh = 1;
32
- float targetRate = 0;
33
- float rateRandom = 0.5, depthRandom = 0;
34
- bool freshReset = true;
35
-
36
- std::default_random_engine randomEngine;
37
- std::uniform_real_distribution<float> randomUnit;
38
- float random() {
39
- return randomUnit(randomEngine);
40
- }
41
- float randomRate() {
42
- return targetRate*exp(rateRandom*(random() - 0.5));
43
- }
44
- float randomTarget(float previous) {
45
- float randomOffset = depthRandom*random()*(targetLow - targetHigh);
46
- if (previous < (targetLow + targetHigh)*0.5f) {
47
- return targetHigh + randomOffset;
48
- } else {
49
- return targetLow - randomOffset;
50
- }
51
- }
52
- public:
53
- CubicLfo() : randomEngine(std::random_device()()), randomUnit(0, 1) {
54
- reset();
55
- }
56
- CubicLfo(long seed) : randomUnit(0, 1) {
57
- randomEngine.seed(seed);
58
- reset();
59
- }
60
-
61
- /// Resets the LFO state, starting with random phase.
62
- void reset() {
63
- ratio = random();
64
- ratioStep = randomRate();
65
- if (random() < 0.5) {
66
- valueFrom = targetLow;
67
- valueTo = targetHigh;
68
- } else {
69
- valueFrom = targetHigh;
70
- valueTo = targetLow;
71
- }
72
- valueRange = valueTo - valueFrom;
73
- freshReset = true;
74
- }
75
- /** Smoothly updates the LFO parameters.
76
-
77
- If called directly after `.reset()`, oscillation will immediately start within the specified range. Otherwise, it will remain smooth and fit within the new range after at most one cycle:
78
- \diagram{cubic-lfo-changes.svg}
79
-
80
- The LFO will complete a full oscillation in (approximately) `1/rate` samples. `rateVariation` can be any number, but 0-1 is a good range.
81
-
82
- `depthVariation` must be in the range [0, 1], where ≤ 0.5 produces random amplitude but still alternates up/down.
83
- \diagram{cubic-lfo-spectrum.svg,Spectra for the two types of randomisation - note the jump as depth variation goes past 50%}
84
- */
85
- void set(float low, float high, float rate, float rateVariation=0, float depthVariation=0) {
86
- rate *= 2; // We want to go up and down during this period
87
- targetRate = rate;
88
- targetLow = std::min(low, high);
89
- targetHigh = std::max(low, high);
90
- rateRandom = rateVariation;
91
- depthRandom = std::min<float>(1, std::max<float>(0, depthVariation));
92
-
93
- // If we haven't called .next() yet, don't bother being smooth.
94
- if (freshReset) return reset();
95
-
96
- // Only update the current rate if it's outside our new random-variation range
97
- float maxRandomRatio = exp((float)0.5*rateRandom);
98
- if (ratioStep > rate*maxRandomRatio || ratioStep < rate/maxRandomRatio) {
99
- ratioStep = randomRate();
100
- }
101
- }
102
-
103
- /// Returns the next output sample
104
- float next() {
105
- freshReset = false;
106
- float result = ratio*ratio*(3 - 2*ratio)*valueRange + valueFrom;
107
-
108
- ratio += ratioStep;
109
- while (ratio >= 1) {
110
- ratio -= 1;
111
- ratioStep = randomRate();
112
- valueFrom = valueTo;
113
- valueTo = randomTarget(valueFrom);
114
- valueRange = valueTo - valueFrom;
115
- }
116
- return result;
117
- }
118
- };
119
-
120
- /** Variable-width rectangular sum */
121
- template<typename Sample=double>
122
- class BoxSum {
123
- int bufferLength, index;
124
- std::vector<Sample> buffer;
125
- Sample sum = 0, wrapJump = 0;
126
- public:
127
- BoxSum(int maxLength) {
128
- resize(maxLength);
129
- }
130
-
131
- /// Sets the maximum size (and reset contents)
132
- void resize(int maxLength) {
133
- bufferLength = maxLength + 1;
134
- buffer.resize(bufferLength);
135
- if (maxLength != 0) buffer.shrink_to_fit();
136
- reset();
137
- }
138
-
139
- /// Resets (with an optional "fill" value)
140
- void reset(Sample value=Sample()) {
141
- index = 0;
142
- sum = 0;
143
- for (size_t i = 0; i < buffer.size(); ++i) {
144
- buffer[i] = sum;
145
- sum += value;
146
- }
147
- wrapJump = sum;
148
- sum = 0;
149
- }
150
-
151
- Sample read(int width) {
152
- int readIndex = index - width;
153
- double result = sum;
154
- if (readIndex < 0) {
155
- result += wrapJump;
156
- readIndex += bufferLength;
157
- }
158
- return result - buffer[readIndex];
159
- }
160
-
161
- void write(Sample value) {
162
- ++index;
163
- if (index == bufferLength) {
164
- index = 0;
165
- wrapJump = sum;
166
- sum = 0;
167
- }
168
- sum += value;
169
- buffer[index] = sum;
170
- }
171
-
172
- Sample readWrite(Sample value, int width) {
173
- write(value);
174
- return read(width);
175
- }
176
- };
177
-
178
- /** Rectangular moving average filter (FIR).
179
- \diagram{box-filter-example.svg}
180
- A filter of length 1 has order 0 (i.e. does nothing). */
181
- template<typename Sample=double>
182
- class BoxFilter {
183
- BoxSum<Sample> boxSum;
184
- int _length, _maxLength;
185
- Sample multiplier;
186
- public:
187
- BoxFilter(int maxLength) : boxSum(maxLength) {
188
- resize(maxLength);
189
- }
190
- /// Sets the maximum size (and current size, and resets)
191
- void resize(int maxLength) {
192
- _maxLength = maxLength;
193
- boxSum.resize(maxLength);
194
- set(maxLength);
195
- }
196
- /// Sets the current size (expanding/allocating only if needed)
197
- void set(int length) {
198
- _length = length;
199
- multiplier = Sample(1)/length;
200
- if (length > _maxLength) resize(length);
201
- }
202
-
203
- /// Resets (with an optional "fill" value)
204
- void reset(Sample fill=Sample()) {
205
- boxSum.reset(fill);
206
- }
207
-
208
- Sample operator()(Sample v) {
209
- return boxSum.readWrite(v, _length)*multiplier;
210
- }
211
- };
212
-
213
- /** FIR filter made from a stack of `BoxFilter`s.
214
- This filter has a non-negative impulse (monotonic step response), making it useful for smoothing positive-only values. It provides an optimal set of box-lengths, chosen to minimise peaks in the stop-band:
215
- \diagram{box-stack-long.svg,Impulse responses for various stack sizes at length N=1000}
216
- Since the underlying box-averages must have integer width, the peaks are slightly higher for shorter lengths with higher numbers of layers:
217
- \diagram{box-stack-short-freq.svg,Frequency responses for various stack sizes at length N=30}
218
- */
219
- template<typename Sample=double>
220
- class BoxStackFilter {
221
- struct Layer {
222
- double ratio = 0, lengthError = 0;
223
- int length = 0;
224
- BoxFilter<Sample> filter{0};
225
- Layer() {}
226
- };
227
- int _size;
228
- std::vector<Layer> layers;
229
-
230
- template<class Iterable>
231
- void setupLayers(const Iterable &ratios) {
232
- layers.resize(0);
233
- double sum = 0;
234
- for (auto ratio : ratios) {
235
- Layer layer;
236
- layer.ratio = ratio;
237
- layers.push_back(layer);
238
- sum += ratio;
239
- }
240
- double factor = 1/sum;
241
- for (auto &l : layers) {
242
- l.ratio *= factor;
243
- }
244
- }
245
- public:
246
- BoxStackFilter(int maxSize, int layers=4) {
247
- resize(maxSize, layers);
248
- }
249
-
250
- /// Returns an optimal set of length ratios (heuristic for larger depths)
251
- static std::vector<double> optimalRatios(int layerCount) {
252
- // Coefficients up to 6, found through numerical search
253
- static double hardcoded[] = {1, 0.58224186169, 0.41775813831, 0.404078562416, 0.334851475794, 0.261069961789, 0.307944914938, 0.27369945234, 0.22913263601, 0.189222996712, 0.248329349789, 0.229253789144, 0.201191468123, 0.173033035122, 0.148192357821, 0.205275202874, 0.198413552119, 0.178256637764, 0.157821404506, 0.138663023387, 0.121570179349 /*, 0.178479592135, 0.171760666359, 0.158434068954, 0.143107825806, 0.125907148711, 0.11853946895, 0.103771229086, 0.155427880834, 0.153063152848, 0.142803459422, 0.131358358458, 0.104157805178, 0.119338029601, 0.0901675284678, 0.103683785192, 0.143949349747, 0.139813248378, 0.132051305252, 0.122216776152, 0.112888320989, 0.102534988632, 0.0928386714364, 0.0719750997699, 0.0817322396428, 0.130587011572, 0.127244563184, 0.121228748787, 0.113509941974, 0.105000272288, 0.0961938290157, 0.0880639725438, 0.0738389766046, 0.0746781936619, 0.0696544903682 */};
254
- if (layerCount <= 0) {
255
- return {};
256
- } else if (layerCount <= 6) {
257
- double *start = &hardcoded[layerCount*(layerCount - 1)/2];
258
- return std::vector<double>(start, start + layerCount);
259
- }
260
- std::vector<double> result(layerCount);
261
-
262
- double invN = 1.0/layerCount, sqrtN = std::sqrt(layerCount);
263
- double p = 1 - invN;
264
- double k = 1 + 4.5/sqrtN + 0.08*sqrtN;
265
-
266
- double sum = 0;
267
- for (int i = 0; i < layerCount; ++i) {
268
- double x = i*invN;
269
- double power = -x*(1 - p*std::exp(-x*k));
270
- double length = std::pow(2, power);
271
- result[i] = length;
272
- sum += length;
273
- }
274
- double factor = 1/sum;
275
- for (auto &r : result) r *= factor;
276
- return result;
277
- }
278
- /** Approximate (optimal) bandwidth for a given number of layers
279
- \diagram{box-stack-bandwidth.svg,Approximate main lobe width (bandwidth)}
280
- */
281
- static constexpr double layersToBandwidth(int layers) {
282
- return 1.58*(layers + 0.1);
283
- }
284
- /** Approximate (optimal) peak in the stop-band
285
- \diagram{box-stack-peak.svg,Heuristic stop-band peak}
286
- */
287
- static constexpr double layersToPeakDb(int layers) {
288
- return 5 - layers*18;
289
- }
290
-
291
- /// Sets size using an optimal (heuristic at larger sizes) set of length ratios
292
- void resize(int maxSize, int layerCount) {
293
- resize(maxSize, optimalRatios(layerCount));
294
- }
295
- /// Sets the maximum (and current) impulse response length and explicit length ratios
296
- template<class List>
297
- auto resize(int maxSize, List ratios) -> decltype(void(std::begin(ratios)), void(std::end(ratios))) {
298
- setupLayers(ratios);
299
- for (auto &layer : layers) layer.filter.resize(0); // .set() will expand it later
300
- _size = -1;
301
- set(maxSize);
302
- reset();
303
- }
304
- void resize(int maxSize, std::initializer_list<double> ratios) {
305
- resize<const std::initializer_list<double> &>(maxSize, ratios);
306
- }
307
-
308
- /// Sets the impulse response length (does not reset if `size` ≤ `maxSize`)
309
- void set(int size) {
310
- if (layers.size() == 0) return; // meaningless
311
-
312
- if (_size == size) return;
313
- _size = size;
314
- int order = size - 1;
315
- int totalOrder = 0;
316
-
317
- for (auto &layer : layers) {
318
- double layerOrderFractional = layer.ratio*order;
319
- int layerOrder = int(layerOrderFractional);
320
- layer.length = layerOrder + 1;
321
- layer.lengthError = layerOrder - layerOrderFractional;
322
- totalOrder += layerOrder;
323
- }
324
- // Round some of them up, so the total is correct - this is O(N²), but `layers.size()` is small
325
- while (totalOrder < order) {
326
- int minIndex = 0;
327
- double minError = layers[0].lengthError;
328
- for (size_t i = 1; i < layers.size(); ++i) {
329
- if (layers[i].lengthError < minError) {
330
- minError = layers[i].lengthError;
331
- minIndex = i;
332
- }
333
- }
334
- layers[minIndex].length++;
335
- layers[minIndex].lengthError += 1;
336
- totalOrder++;
337
- }
338
- for (auto &layer : layers) layer.filter.set(layer.length);
339
- }
340
-
341
- /// Resets the filter
342
- void reset(Sample fill=Sample()) {
343
- for (auto &layer : layers) layer.filter.reset(fill);
344
- }
345
-
346
- Sample operator()(Sample v) {
347
- for (auto &layer : layers) {
348
- v = layer.filter(v);
349
- }
350
- return v;
351
- }
352
- };
353
-
354
- /** Peak-hold filter.
355
- \diagram{peak-hold.svg}
356
-
357
- The size is variable, and can be changed instantly with `.set()`, or by using `.push()`/`.pop()` in an unbalanced way.
358
-
359
- This has complexity O(1) every sample when the length remains constant (balanced `.push()`/`.pop()`, or using `filter(v)`), and amortised O(1) complexity otherwise. To avoid allocations while running, it pre-allocates a vector (not a `std::deque`) which determines the maximum length.
360
- */
361
- template<typename Sample>
362
- class PeakHold {
363
- static constexpr Sample lowest = std::numeric_limits<Sample>::lowest();
364
- int bufferMask;
365
- std::vector<Sample> buffer;
366
- int backIndex = 0, middleStart = 0, workingIndex = 0, middleEnd = 0, frontIndex = 0;
367
- Sample frontMax = lowest, workingMax = lowest, middleMax = lowest;
368
-
369
- public:
370
- PeakHold(int maxLength) {
371
- resize(maxLength);
372
- }
373
- int size() {
374
- return frontIndex - backIndex;
375
- }
376
- void resize(int maxLength) {
377
- int bufferLength = 1;
378
- while (bufferLength < maxLength) bufferLength *= 2;
379
- buffer.resize(bufferLength);
380
- bufferMask = bufferLength - 1;
381
-
382
- frontIndex = backIndex + maxLength;
383
- reset();
384
- }
385
- void reset(Sample fill=lowest) {
386
- int prevSize = size();
387
- buffer.assign(buffer.size(), fill);
388
- frontMax = workingMax = middleMax = lowest;
389
- middleEnd = workingIndex = frontIndex = 0;
390
- middleStart = middleEnd - (prevSize/2);
391
- backIndex = frontIndex - prevSize;
392
- }
393
- /** Sets the size immediately.
394
- Must be `0 <= newSize <= maxLength` (see constructor and `.resize()`).
395
-
396
- Shrinking doesn't destroy information, and if you expand again (with `preserveCurrentPeak=false`), you will get the same output as before shrinking. Expanding when `preserveCurrentPeak` is enabled is destructive, re-writing its history such that the current output value is unchanged.*/
397
- void set(int newSize, bool preserveCurrentPeak=false) {
398
- while (size() < newSize) {
399
- Sample &backPrev = buffer[backIndex&bufferMask];
400
- --backIndex;
401
- Sample &back = buffer[backIndex&bufferMask];
402
- back = preserveCurrentPeak ? backPrev : std::max(back, backPrev);
403
- }
404
- while (size() > newSize) {
405
- pop();
406
- }
407
- }
408
-
409
- void push(Sample v) {
410
- buffer[frontIndex&bufferMask] = v;
411
- ++frontIndex;
412
- frontMax = std::max(frontMax, v);
413
- }
414
- void pop() {
415
- if (backIndex == middleStart) {
416
- // Move along the maximums
417
- workingMax = lowest;
418
- middleMax = frontMax;
419
- frontMax = lowest;
420
-
421
- int prevFrontLength = frontIndex - middleEnd;
422
- int prevMiddleLength = middleEnd - middleStart;
423
- if (prevFrontLength <= prevMiddleLength + 1) {
424
- // Swap over simply
425
- middleStart = middleEnd;
426
- middleEnd = frontIndex;
427
- workingIndex = middleEnd;
428
- } else {
429
- // The front is longer than the middle - only happens if unbalanced
430
- // We don't move *all* of the front over, keeping half the surplus in the front
431
- int middleLength = (frontIndex - middleStart)/2;
432
- middleStart = middleEnd;
433
- middleEnd += middleLength;
434
-
435
- // Working index is close enough that it will be finished by the time the back is empty
436
- int backLength = middleStart - backIndex;
437
- int workingLength = std::min(backLength, middleEnd - middleStart);
438
- workingIndex = middleStart + workingLength;
439
-
440
- // Since the front was not completely consumed, we re-calculate the front's maximum
441
- for (int i = middleEnd; i != frontIndex; ++i) {
442
- frontMax = std::max(frontMax, buffer[i&bufferMask]);
443
- }
444
- // The index might not start at the end of the working block - compute the last bit immediately
445
- for (int i = middleEnd - 1; i != workingIndex - 1; --i) {
446
- buffer[i&bufferMask] = workingMax = std::max(workingMax, buffer[i&bufferMask]);
447
- }
448
- }
449
-
450
- // Is the new back (previous middle) empty? Only happens if unbalanced
451
- if (backIndex == middleStart) {
452
- // swap over again (front's empty, no change)
453
- workingMax = lowest;
454
- middleMax = frontMax;
455
- frontMax = lowest;
456
- middleStart = workingIndex = middleEnd;
457
-
458
- if (backIndex == middleStart) {
459
- --backIndex; // Only happens if you pop from an empty list - fail nicely
460
- }
461
- }
462
-
463
- buffer[frontIndex&bufferMask] = lowest; // In case of length 0, when everything points at this value
464
- }
465
-
466
- ++backIndex;
467
- if (workingIndex != middleStart) {
468
- --workingIndex;
469
- buffer[workingIndex&bufferMask] = workingMax = std::max(workingMax, buffer[workingIndex&bufferMask]);
470
- }
471
- }
472
- Sample read() {
473
- Sample backMax = buffer[backIndex&bufferMask];
474
- return std::max(backMax, std::max(middleMax, frontMax));
475
- }
476
-
477
- // For simple use as a constant-length filter
478
- Sample operator ()(Sample v) {
479
- push(v);
480
- pop();
481
- return read();
482
- }
483
- };
484
-
485
- /** Peak-decay filter with a linear shape and fixed-time return to constant value.
486
- \diagram{peak-decay-linear.svg}
487
- This is equivalent to a `BoxFilter` which resets itself whenever the output would be less than the input.
488
- */
489
- template<typename Sample=double>
490
- class PeakDecayLinear {
491
- static constexpr Sample lowest = std::numeric_limits<Sample>::lowest();
492
- PeakHold<Sample> peakHold;
493
- Sample value = lowest;
494
- Sample stepMultiplier = 1;
495
- public:
496
- PeakDecayLinear(int maxLength) : peakHold(maxLength) {
497
- set(maxLength);
498
- }
499
- void resize(int maxLength) {
500
- peakHold.resize(maxLength);
501
- reset();
502
- }
503
- void set(double length) {
504
- peakHold.set(std::ceil(length));
505
- // Overshoot slightly but don't exceed 1
506
- stepMultiplier = Sample(1.0001)/std::max(1.0001, length);
507
- }
508
- void reset(Sample start=lowest) {
509
- peakHold.reset(start);
510
- set(peakHold.size());
511
- value = start;
512
- }
513
-
514
- Sample operator ()(Sample v) {
515
- Sample peak = peakHold.read();
516
- peakHold(v);
517
- return value = std::max<Sample>(v, value + (v - peak)*stepMultiplier);
518
- }
519
- };
520
-
521
- /** @} */
522
- }} // signalsmith::envelopes::
523
- #endif // include guard