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.
- package/RNAudioAPI.podspec +14 -4
- package/android/CMakeLists.txt +9 -48
- package/android/src/main/cpp/audioapi/CMakeLists.txt +44 -0
- package/android/src/main/cpp/{AudioAPIModule.cpp → audioapi/android/AudioAPIModule.cpp} +1 -4
- package/android/src/main/cpp/{AudioAPIModule.h → audioapi/android/AudioAPIModule.h} +2 -1
- package/android/src/main/cpp/{OnLoad.cpp → audioapi/android/OnLoad.cpp} +2 -1
- package/android/src/main/cpp/{core → audioapi/android/core}/AudioDecoder.cpp +5 -5
- package/android/src/main/cpp/{core → audioapi/android/core}/AudioPlayer.cpp +5 -7
- package/android/src/main/cpp/{core → audioapi/android/core}/AudioPlayer.h +1 -0
- package/android/src/main/cpp/{libs → audioapi/android/libs}/pffft.c +2 -2
- package/android/src/main/java/com/swmansion/audioapi/AudioAPIPackage.kt +1 -0
- package/common/cpp/{installer → audioapi}/AudioAPIModuleInstaller.h +5 -3
- package/common/cpp/{HostObjects → audioapi/HostObjects}/AnalyserNodeHostObject.h +3 -3
- package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioBufferHostObject.h +3 -3
- package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioBufferSourceNodeHostObject.h +5 -5
- package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioContextHostObject.h +3 -3
- package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioDestinationNodeHostObject.h +3 -3
- package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioNodeHostObject.h +3 -3
- package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioParamHostObject.h +3 -3
- package/common/cpp/{HostObjects → audioapi/HostObjects}/AudioScheduledSourceNodeHostObject.h +3 -3
- package/common/cpp/{HostObjects → audioapi/HostObjects}/BaseAudioContextHostObject.h +14 -15
- package/common/cpp/{HostObjects → audioapi/HostObjects}/BiquadFilterNodeHostObject.h +4 -4
- package/common/cpp/{HostObjects → audioapi/HostObjects}/GainNodeHostObject.h +4 -4
- package/common/cpp/{HostObjects → audioapi/HostObjects}/OscillatorNodeHostObject.h +5 -5
- package/common/cpp/{HostObjects → audioapi/HostObjects}/PeriodicWaveHostObject.h +2 -2
- package/common/cpp/{HostObjects → audioapi/HostObjects}/StereoPannerNodeHostObject.h +4 -4
- package/common/cpp/audioapi/HostObjects/StretcherNodeHostObject.h +35 -0
- package/common/cpp/{core → audioapi/core}/AudioContext.cpp +6 -6
- package/common/cpp/{core → audioapi/core}/AudioContext.h +2 -2
- package/common/cpp/{core → audioapi/core}/AudioNode.cpp +5 -7
- package/common/cpp/{core → audioapi/core}/AudioNode.h +5 -4
- package/common/cpp/{core → audioapi/core}/AudioParam.cpp +3 -4
- package/common/cpp/{core → audioapi/core}/AudioParam.h +3 -3
- package/common/cpp/{core → audioapi/core}/BaseAudioContext.cpp +14 -17
- package/common/cpp/{core → audioapi/core}/BaseAudioContext.h +4 -3
- package/common/cpp/{core → audioapi/core/analysis}/AnalyserNode.cpp +6 -10
- package/common/cpp/{core → audioapi/core/analysis}/AnalyserNode.h +4 -3
- package/common/cpp/{core → audioapi/core/destinations}/AudioDestinationNode.cpp +5 -5
- package/common/cpp/{core → audioapi/core/destinations}/AudioDestinationNode.h +2 -2
- package/common/cpp/{core → audioapi/core/effects}/BiquadFilterNode.cpp +4 -4
- package/common/cpp/{core → audioapi/core/effects}/BiquadFilterNode.h +4 -4
- package/common/cpp/{core → audioapi/core/effects}/GainNode.cpp +4 -4
- package/common/cpp/{core → audioapi/core/effects}/GainNode.h +3 -3
- package/common/cpp/{core → audioapi/core/effects}/PeriodicWave.cpp +4 -2
- package/common/cpp/{core → audioapi/core/effects}/PeriodicWave.h +2 -4
- package/common/cpp/{core → audioapi/core/effects}/StereoPannerNode.cpp +5 -7
- package/common/cpp/{core → audioapi/core/effects}/StereoPannerNode.h +4 -3
- package/common/cpp/{core → audioapi/core/effects}/StretcherNode.cpp +4 -6
- package/common/cpp/audioapi/core/effects/StretcherNode.h +35 -0
- package/common/cpp/{core → audioapi/core/sources}/AudioBuffer.cpp +3 -3
- package/common/cpp/{core → audioapi/core/sources}/AudioBufferSourceNode.cpp +8 -11
- package/common/cpp/{core → audioapi/core/sources}/AudioBufferSourceNode.h +5 -3
- package/common/cpp/{core → audioapi/core/sources}/AudioScheduledSourceNode.cpp +6 -8
- package/common/cpp/{core → audioapi/core/sources}/AudioScheduledSourceNode.h +3 -2
- package/common/cpp/{core → audioapi/core/sources}/OscillatorNode.cpp +4 -4
- package/common/cpp/{core → audioapi/core/sources}/OscillatorNode.h +5 -5
- package/common/cpp/{core → audioapi/core/utils}/AudioArray.cpp +2 -4
- package/common/cpp/{core → audioapi/core/utils}/AudioBus.cpp +4 -7
- package/common/cpp/{core → audioapi/core/utils}/AudioBus.h +2 -2
- package/common/cpp/{core → audioapi/core/utils}/AudioNodeManager.cpp +3 -4
- package/common/cpp/{core → audioapi/core/utils}/ParamChangeEvent.cpp +1 -3
- package/common/cpp/{core → audioapi/core/utils}/ParamChangeEvent.h +3 -1
- package/common/cpp/{utils → audioapi/dsp}/AudioUtils.cpp +1 -1
- package/common/cpp/{utils → audioapi/dsp}/FFTFrame.cpp +1 -10
- package/common/cpp/{utils → audioapi/dsp}/FFTFrame.h +4 -3
- package/common/cpp/{utils → audioapi/dsp}/VectorMath.cpp +2 -5
- package/common/cpp/{utils → audioapi/dsp}/VectorMath.h +2 -0
- package/common/cpp/{jsi → audioapi/jsi}/JsiHostObject.cpp +1 -1
- package/common/cpp/{jsi → audioapi/jsi}/JsiHostObject.h +2 -2
- package/common/cpp/{jsi → audioapi/jsi}/JsiPromise.cpp +2 -6
- package/common/cpp/{jsi → audioapi/jsi}/RuntimeAwareCache.h +2 -3
- package/common/cpp/{jsi → audioapi/jsi}/RuntimeLifecycleMonitor.cpp +1 -5
- package/common/cpp/{jsi → audioapi/jsi}/RuntimeLifecycleMonitor.h +3 -0
- package/common/cpp/{libs → audioapi/libs}/dsp/delay.h +35 -35
- package/common/cpp/{libs → audioapi/libs}/dsp/fft.h +21 -21
- package/common/cpp/{libs → audioapi/libs}/dsp/perf.h +3 -3
- package/common/cpp/{libs → audioapi/libs}/dsp/spectral.h +39 -39
- package/common/cpp/{libs → audioapi/libs}/dsp/windows.h +11 -11
- package/common/cpp/{libs → audioapi/libs}/signalsmith-stretch.h +30 -30
- package/ios/{AudioAPIModule.mm → audioapi/ios/AudioAPIModule.mm} +15 -8
- package/ios/{core → audioapi/ios/core}/AudioDecoder.mm +4 -4
- package/ios/{core → audioapi/ios/core}/AudioPlayer.m +1 -1
- package/ios/{core → audioapi/ios/core}/IOSAudioPlayer.mm +4 -4
- package/package.json +6 -6
- package/common/cpp/HostObjects/StretcherNodeHostObject.h +0 -35
- package/common/cpp/core/StretcherNode.h +0 -63
- package/common/cpp/libs/dsp/LICENSE.txt +0 -21
- package/common/cpp/libs/dsp/README.md +0 -40
- package/common/cpp/libs/dsp/curves.h +0 -371
- package/common/cpp/libs/dsp/envelopes.h +0 -523
- package/common/cpp/libs/dsp/filters.h +0 -436
- package/common/cpp/libs/dsp/mix.h +0 -218
- package/common/cpp/libs/dsp/rates.h +0 -184
- package/common/cpp/types/TimeStretchType.h +0 -6
- /package/android/src/main/cpp/{libs → audioapi/android/libs}/pffft.h +0 -0
- /package/common/cpp/{core → audioapi/core}/Constants.h +0 -0
- /package/common/cpp/{core → audioapi/core/sources}/AudioBuffer.h +0 -0
- /package/common/cpp/{types → audioapi/core/types}/BiquadFilterType.h +0 -0
- /package/common/cpp/{types → audioapi/core/types}/ChannelCountMode.h +0 -0
- /package/common/cpp/{types → audioapi/core/types}/ChannelInterpretation.h +0 -0
- /package/common/cpp/{types → audioapi/core/types}/ContextState.h +0 -0
- /package/common/cpp/{types → audioapi/core/types}/OscillatorType.h +0 -0
- /package/common/cpp/{types → audioapi/core/types}/ParamChangeEventType.h +0 -0
- /package/common/cpp/{core → audioapi/core/utils}/AudioArray.h +0 -0
- /package/common/cpp/{core → audioapi/core/utils}/AudioDecoder.h +0 -0
- /package/common/cpp/{core → audioapi/core/utils}/AudioNodeManager.h +0 -0
- /package/common/cpp/{utils → audioapi/core/utils}/Locker.h +0 -0
- /package/common/cpp/{utils → audioapi/dsp}/AudioUtils.h +0 -0
- /package/common/cpp/{jsi → audioapi/jsi}/JsiPromise.h +0 -0
- /package/common/cpp/{libs → audioapi/libs}/dsp/common.h +0 -0
- /package/common/cpp/{libs → audioapi/libs}/miniaudio.h +0 -0
- /package/ios/{AudioAPIModule.h → audioapi/ios/AudioAPIModule.h} +0 -0
- /package/ios/{core → audioapi/ios/core}/AudioPlayer.h +0 -0
- /package/ios/{core → audioapi/ios/core}/IOSAudioPlayer.h +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
#include
|
|
1
|
+
#include <audioapi/libs/dsp/common.h>
|
|
2
2
|
|
|
3
3
|
#ifndef SIGNALSMITH_DSP_SPECTRAL_H
|
|
4
4
|
#define SIGNALSMITH_DSP_SPECTRAL_H
|
|
5
5
|
|
|
6
|
-
#include
|
|
7
|
-
#include
|
|
8
|
-
#include
|
|
9
|
-
#include
|
|
6
|
+
#include <audioapi/libs/dsp/perf.h>
|
|
7
|
+
#include <audioapi/libs/dsp/fft.h>
|
|
8
|
+
#include <audioapi/libs/dsp/windows.h>
|
|
9
|
+
#include <audioapi/libs/dsp/delay.h>
|
|
10
10
|
|
|
11
11
|
#include <cmath>
|
|
12
12
|
|
|
@@ -14,15 +14,15 @@ namespace signalsmith {
|
|
|
14
14
|
namespace spectral {
|
|
15
15
|
/** @defgroup Spectral Spectral Processing
|
|
16
16
|
@brief Tools for frequency-domain manipulation of audio signals
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
@{
|
|
19
19
|
@file
|
|
20
20
|
*/
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
/** @brief An FFT with built-in windowing and round-trip scaling
|
|
23
|
-
|
|
23
|
+
|
|
24
24
|
This uses a Modified Real FFT, which applies half-bin shift before the transform. The result therefore has `N/2` bins, centred at the frequencies: `(i + 0.5)/N`.
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
This avoids the awkward (real-valued) bands for DC-offset and Nyquist.
|
|
27
27
|
*/
|
|
28
28
|
template<typename Sample>
|
|
@@ -66,7 +66,7 @@ namespace spectral {
|
|
|
66
66
|
template<class WindowFn>
|
|
67
67
|
void setSize(int size, WindowFn fn, Sample windowOffset=0.5, int rotateSamples=0) {
|
|
68
68
|
setSizeWindow(size, rotateSamples);
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
Sample invSize = 1/(Sample)size;
|
|
71
71
|
for (int i = 0; i < size; ++i) {
|
|
72
72
|
Sample r = (i + windowOffset)*invSize;
|
|
@@ -88,7 +88,7 @@ namespace spectral {
|
|
|
88
88
|
int size() const {
|
|
89
89
|
return mrfft.size();
|
|
90
90
|
}
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
/// Performs an FFT, with windowing and rotation (if enabled)
|
|
93
93
|
template<bool withWindow=true, bool withScaling=false, class Input, class Output>
|
|
94
94
|
void fft(Input &&input, Output &&output) {
|
|
@@ -130,17 +130,17 @@ namespace spectral {
|
|
|
130
130
|
mrfft.ifft(input, output);
|
|
131
131
|
}
|
|
132
132
|
};
|
|
133
|
-
|
|
133
|
+
|
|
134
134
|
/** STFT synthesis, built on a `MultiBuffer`.
|
|
135
|
-
|
|
135
|
+
|
|
136
136
|
Any window length and block interval is supported, but the FFT size may be rounded up to a faster size (by zero-padding). It uses a heuristically-optimal Kaiser window modified for perfect-reconstruction.
|
|
137
|
-
|
|
137
|
+
|
|
138
138
|
\diagram{stft-aliasing-simulated.svg,Simulated bad-case aliasing (random phase-shift for each band) for overlapping ratios}
|
|
139
139
|
|
|
140
140
|
There is a "latest valid index", and you can read the output up to one `historyLength` behind this (see `.resize()`). You can read up to one window-length _ahead_ to get partially-summed future output.
|
|
141
|
-
|
|
141
|
+
|
|
142
142
|
\diagram{stft-buffer-validity.svg}
|
|
143
|
-
|
|
143
|
+
|
|
144
144
|
You move the valid index along using `.ensureValid()`, passing in a functor which provides spectra (using `.analyse()` and/or direct modification through `.spectrum[c]`):
|
|
145
145
|
|
|
146
146
|
\code
|
|
@@ -165,7 +165,7 @@ namespace spectral {
|
|
|
165
165
|
stft += blockSize;
|
|
166
166
|
}
|
|
167
167
|
\endcode
|
|
168
|
-
|
|
168
|
+
|
|
169
169
|
The index passed to this functor will be greater than the previous valid index, and `<=` the index you pass in. Therefore, if you call `.ensureValid()` every sample, it can only ever be `0`.
|
|
170
170
|
*/
|
|
171
171
|
template<typename Sample>
|
|
@@ -183,17 +183,17 @@ namespace spectral {
|
|
|
183
183
|
public:
|
|
184
184
|
MultiSpectrum() : MultiSpectrum(0, 0) {}
|
|
185
185
|
MultiSpectrum(int channels, int bands) : channels(channels), stride(bands), buffer(channels*bands, 0) {}
|
|
186
|
-
|
|
186
|
+
|
|
187
187
|
void resize(int nChannels, int nBands) {
|
|
188
188
|
channels = nChannels;
|
|
189
189
|
stride = nBands;
|
|
190
190
|
buffer.assign(channels*stride, 0);
|
|
191
191
|
}
|
|
192
|
-
|
|
192
|
+
|
|
193
193
|
void reset() {
|
|
194
194
|
buffer.assign(buffer.size(), 0);
|
|
195
195
|
}
|
|
196
|
-
|
|
196
|
+
|
|
197
197
|
void swap(MultiSpectrum &other) {
|
|
198
198
|
using std::swap;
|
|
199
199
|
swap(buffer, other.buffer);
|
|
@@ -222,7 +222,7 @@ namespace spectral {
|
|
|
222
222
|
this->_fftSize = fftSize;
|
|
223
223
|
this->_interval = newInterval;
|
|
224
224
|
validUntilIndex = -1;
|
|
225
|
-
|
|
225
|
+
|
|
226
226
|
setWindow(windowShape, rotate);
|
|
227
227
|
|
|
228
228
|
spectrum.resize(channels, fftSize/2);
|
|
@@ -235,7 +235,7 @@ namespace spectral {
|
|
|
235
235
|
// for convenience
|
|
236
236
|
static constexpr Window kaiser = Window::kaiser;
|
|
237
237
|
static constexpr Window acg = Window::acg;
|
|
238
|
-
|
|
238
|
+
|
|
239
239
|
/** Swaps between the default (Kaiser) shape and Approximate Confined Gaussian (ACG).
|
|
240
240
|
\diagram{stft-windows.svg,Default (Kaiser) windows and partial cumulative sum}
|
|
241
241
|
The ACG has better rolloff since its edges go to 0:
|
|
@@ -251,25 +251,25 @@ namespace spectral {
|
|
|
251
251
|
if (windowShape == Window::kaiser) {
|
|
252
252
|
using Kaiser = ::signalsmith::windows::Kaiser;
|
|
253
253
|
/// Roughly optimal Kaiser for STFT analysis (forced to perfect reconstruction)
|
|
254
|
-
auto
|
|
255
|
-
|
|
254
|
+
auto kaiser_ = Kaiser::withBandwidth(_windowSize/double(_interval), true);
|
|
255
|
+
kaiser_.fill(window, _windowSize);
|
|
256
256
|
} else {
|
|
257
257
|
using Confined = ::signalsmith::windows::ApproximateConfinedGaussian;
|
|
258
258
|
auto confined = Confined::withBandwidth(_windowSize/double(_interval));
|
|
259
259
|
confined.fill(window, _windowSize);
|
|
260
260
|
}
|
|
261
261
|
::signalsmith::windows::forcePerfectReconstruction(window, _windowSize, _interval);
|
|
262
|
-
|
|
262
|
+
|
|
263
263
|
// TODO: fill extra bits of an input buffer with NaN/Infinity, to break this, and then fix by adding zero-padding to WindowedFFT (as opposed to zero-valued window sections)
|
|
264
264
|
for (int i = _windowSize; i < _fftSize; ++i) {
|
|
265
265
|
window[i] = 0;
|
|
266
266
|
}
|
|
267
267
|
}
|
|
268
|
-
|
|
268
|
+
|
|
269
269
|
using Spectrum = MultiSpectrum;
|
|
270
270
|
Spectrum spectrum;
|
|
271
271
|
WindowedFFT<Sample> fft;
|
|
272
|
-
|
|
272
|
+
|
|
273
273
|
STFT() {}
|
|
274
274
|
/// Parameters passed straight to `.resize()`
|
|
275
275
|
STFT(int channels, int windowSize, int interval, int historyLength=0, int zeroPadding=0) {
|
|
@@ -280,7 +280,7 @@ namespace spectral {
|
|
|
280
280
|
void resize(int nChannels, int windowSize, int interval, int historyLength=0, int zeroPadding=0) {
|
|
281
281
|
resizeInternal(nChannels, windowSize, interval, historyLength, zeroPadding);
|
|
282
282
|
}
|
|
283
|
-
|
|
283
|
+
|
|
284
284
|
int windowSize() const {
|
|
285
285
|
return _windowSize;
|
|
286
286
|
}
|
|
@@ -307,18 +307,18 @@ namespace spectral {
|
|
|
307
307
|
}
|
|
308
308
|
return result;
|
|
309
309
|
}
|
|
310
|
-
|
|
310
|
+
|
|
311
311
|
/// Resets everything - since we clear the output sum, it will take `windowSize` samples to get proper output.
|
|
312
312
|
void reset() {
|
|
313
313
|
Super::reset();
|
|
314
314
|
spectrum.reset();
|
|
315
315
|
validUntilIndex = -1;
|
|
316
316
|
}
|
|
317
|
-
|
|
317
|
+
|
|
318
318
|
/** Generates valid output up to the specified index (or 0), using the callback as many times as needed.
|
|
319
|
-
|
|
319
|
+
|
|
320
320
|
The callback should be a functor accepting a single integer argument, which is the index for which a spectrum is required.
|
|
321
|
-
|
|
321
|
+
|
|
322
322
|
The block created from these spectra will start at this index in the output, plus `.latency()`.
|
|
323
323
|
*/
|
|
324
324
|
template<class AnalysisFn>
|
|
@@ -354,9 +354,9 @@ namespace spectral {
|
|
|
354
354
|
int nextInvalid() const {
|
|
355
355
|
return validUntilIndex + 1;
|
|
356
356
|
}
|
|
357
|
-
|
|
357
|
+
|
|
358
358
|
/** Analyse a multi-channel input, for any type where `data[channel][index]` returns samples
|
|
359
|
-
|
|
359
|
+
|
|
360
360
|
Results can be read/edited using `.spectrum`. */
|
|
361
361
|
template<class Data>
|
|
362
362
|
void analyse(Data &&data) {
|
|
@@ -385,12 +385,12 @@ namespace spectral {
|
|
|
385
385
|
}
|
|
386
386
|
|
|
387
387
|
/** Internal latency (between the block-index requested in `.ensureValid()` and its position in the output)
|
|
388
|
-
|
|
388
|
+
|
|
389
389
|
Currently unused, but it's in here to allow for a future implementation which spreads the FFT calculations out across each interval.*/
|
|
390
390
|
int latency() {
|
|
391
391
|
return 0;
|
|
392
392
|
}
|
|
393
|
-
|
|
393
|
+
|
|
394
394
|
// @name Shift the underlying buffer (moving the "valid" index accordingly)
|
|
395
395
|
// @{
|
|
396
396
|
STFT & operator ++() {
|
|
@@ -435,7 +435,7 @@ namespace spectral {
|
|
|
435
435
|
using Super = STFT<Sample>;
|
|
436
436
|
public:
|
|
437
437
|
signalsmith::delay::MultiBuffer<Sample> input;
|
|
438
|
-
|
|
438
|
+
|
|
439
439
|
ProcessSTFT(int inChannels, int outChannels, int windowSize, int interval, int historyLength=0) {
|
|
440
440
|
resize(inChannels, outChannels, windowSize, interval, historyLength);
|
|
441
441
|
}
|
|
@@ -443,7 +443,7 @@ namespace spectral {
|
|
|
443
443
|
/** Alter the spectrum, using input up to this point, for the output block starting from this point.
|
|
444
444
|
Sub-classes should replace this with whatever processing is desired. */
|
|
445
445
|
virtual void processSpectrum(int /*blockIndex*/) {}
|
|
446
|
-
|
|
446
|
+
|
|
447
447
|
/// Sets the input/output channels, FFT size and interval.
|
|
448
448
|
void resize(int inChannels, int outChannels, int windowSize, int interval, int historyLength=0) {
|
|
449
449
|
Super::resize(outChannels, windowSize, interval, historyLength);
|
|
@@ -458,7 +458,7 @@ namespace spectral {
|
|
|
458
458
|
int latency() {
|
|
459
459
|
return Super::latency() + (this->windowSize() - 1);
|
|
460
460
|
}
|
|
461
|
-
|
|
461
|
+
|
|
462
462
|
void ensureValid(int i=0) {
|
|
463
463
|
Super::ensureValid(i, [&](int blockIndex) {
|
|
464
464
|
this->analyse(input.view(blockIndex - this->windowSize() + 1));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#include
|
|
1
|
+
#include <audioapi/libs/dsp/common.h>
|
|
2
2
|
|
|
3
3
|
#ifndef SIGNALSMITH_DSP_WINDOWS_H
|
|
4
4
|
#define SIGNALSMITH_DSP_WINDOWS_H
|
|
@@ -10,15 +10,15 @@ namespace signalsmith {
|
|
|
10
10
|
namespace windows {
|
|
11
11
|
/** @defgroup Windows Window functions
|
|
12
12
|
@brief Windows for spectral analysis
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
These are generally double-precision, because they are mostly calculated during setup/reconfiguring, not real-time code.
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
@{
|
|
17
17
|
@file
|
|
18
18
|
*/
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
/** @brief The Kaiser window (almost) maximises the energy in the main-lobe compared to the side-lobes.
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
Kaiser windows can be constructing using the shape-parameter (beta) or using the static `with???()` methods.*/
|
|
23
23
|
class Kaiser {
|
|
24
24
|
// I_0(x)=\sum_{k=0}^{N}\frac{x^{2k}}{(k!)^2\cdot4^k}
|
|
@@ -37,7 +37,7 @@ namespace windows {
|
|
|
37
37
|
}
|
|
38
38
|
double beta;
|
|
39
39
|
double invB0;
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
static double heuristicBandwidth(double bandwidth) {
|
|
42
42
|
// Good peaks
|
|
43
43
|
//return bandwidth + 8/((bandwidth + 3)*(bandwidth + 3));
|
|
@@ -68,7 +68,7 @@ namespace windows {
|
|
|
68
68
|
double alpha = std::sqrt(bandwidth*bandwidth*0.25 - 1);
|
|
69
69
|
return alpha*M_PI;
|
|
70
70
|
}
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
static double betaToBandwidth(double beta) {
|
|
73
73
|
double alpha = beta*(1.0/M_PI);
|
|
74
74
|
return 2*std::sqrt(alpha*alpha + 1);
|
|
@@ -150,7 +150,7 @@ namespace windows {
|
|
|
150
150
|
double arg = std::sqrt(1 - r*r);
|
|
151
151
|
return bessel0(beta*arg)*invB0;
|
|
152
152
|
}
|
|
153
|
-
|
|
153
|
+
|
|
154
154
|
/// Fills an arbitrary container with a Kaiser window
|
|
155
155
|
template<typename Data>
|
|
156
156
|
void fill(Data &&data, int size) const {
|
|
@@ -164,11 +164,11 @@ namespace windows {
|
|
|
164
164
|
};
|
|
165
165
|
|
|
166
166
|
/** @brief The Approximate Confined Gaussian window is (almost) optimal
|
|
167
|
-
|
|
167
|
+
|
|
168
168
|
ACG windows can be constructing using the shape-parameter (sigma) or using the static `with???()` methods.*/
|
|
169
169
|
class ApproximateConfinedGaussian {
|
|
170
170
|
double gaussianFactor;
|
|
171
|
-
|
|
171
|
+
|
|
172
172
|
double gaussian(double x) const {
|
|
173
173
|
return std::exp(-x*x*gaussianFactor);
|
|
174
174
|
}
|
|
@@ -182,7 +182,7 @@ namespace windows {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
ApproximateConfinedGaussian(double sigma) : gaussianFactor(0.0625/(sigma*sigma)) {}
|
|
185
|
-
|
|
185
|
+
|
|
186
186
|
/// Fills an arbitrary container
|
|
187
187
|
template<typename Data>
|
|
188
188
|
void fill(Data &&data, int size) const {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#ifndef SIGNALSMITH_STRETCH_H
|
|
2
2
|
#define SIGNALSMITH_STRETCH_H
|
|
3
3
|
|
|
4
|
-
#include
|
|
5
|
-
#include
|
|
6
|
-
#include
|
|
4
|
+
#include <audioapi/libs/dsp/spectral.h>
|
|
5
|
+
#include <audioapi/libs/dsp/delay.h>
|
|
6
|
+
#include <audioapi/libs/dsp/perf.h>
|
|
7
7
|
SIGNALSMITH_DSP_VERSION_CHECK(1, 6, 0); // Check version is compatible
|
|
8
8
|
#include <vector>
|
|
9
9
|
#include <algorithm>
|
|
@@ -31,7 +31,7 @@ struct SignalsmithStretch {
|
|
|
31
31
|
int outputLatency() const {
|
|
32
32
|
return stft.windowSize() - inputLatency();
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
void reset() {
|
|
36
36
|
stft.reset();
|
|
37
37
|
inputBuffer.reset();
|
|
@@ -59,7 +59,7 @@ struct SignalsmithStretch {
|
|
|
59
59
|
inputBuffer.resize(channels, blockSamples + intervalSamples + 1);
|
|
60
60
|
timeBuffer.assign(stft.fftSize(), 0);
|
|
61
61
|
channelBands.assign(bands*channels, Band());
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
peaks.reserve(bands/2);
|
|
64
64
|
energy.resize(bands);
|
|
65
65
|
smoothedEnergy.resize(bands);
|
|
@@ -129,7 +129,7 @@ struct SignalsmithStretch {
|
|
|
129
129
|
b.inputEnergy = 0;
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
|
-
|
|
132
|
+
|
|
133
133
|
if (inputSamples > 0) {
|
|
134
134
|
// copy from the input, wrapping around if needed
|
|
135
135
|
for (int outputIndex = 0; outputIndex < outputSamples; ++outputIndex) {
|
|
@@ -191,10 +191,10 @@ struct SignalsmithStretch {
|
|
|
191
191
|
flushed = false; // TODO: first block after a flush should be gain-compensated
|
|
192
192
|
|
|
193
193
|
for (int c = 0; c < channels; ++c) {
|
|
194
|
-
auto
|
|
194
|
+
auto channelBands_ = bandsForChannel(c);
|
|
195
195
|
auto &&spectrumBands = stft.spectrum[c];
|
|
196
196
|
for (int b = 0; b < bands; ++b) {
|
|
197
|
-
|
|
197
|
+
channelBands_[b].input = spectrumBands[b];
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
|
|
@@ -214,24 +214,24 @@ struct SignalsmithStretch {
|
|
|
214
214
|
stft.analyse(c, timeBuffer);
|
|
215
215
|
}
|
|
216
216
|
for (int c = 0; c < channels; ++c) {
|
|
217
|
-
auto
|
|
217
|
+
auto channelBands_ = bandsForChannel(c);
|
|
218
218
|
auto &&spectrumBands = stft.spectrum[c];
|
|
219
219
|
for (int b = 0; b < bands; ++b) {
|
|
220
|
-
|
|
220
|
+
channelBands_[b].prevInput = spectrumBands[b];
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
|
-
|
|
225
|
+
|
|
226
226
|
Sample timeFactor = didSeek ? seekTimeFactor : stft.interval()/std::max<Sample>(1, inputInterval);
|
|
227
227
|
processSpectrum(newSpectrum, timeFactor);
|
|
228
228
|
didSeek = false;
|
|
229
229
|
|
|
230
230
|
for (int c = 0; c < channels; ++c) {
|
|
231
|
-
auto
|
|
231
|
+
auto channelBands_ = bandsForChannel(c);
|
|
232
232
|
auto &&spectrumBands = stft.spectrum[c];
|
|
233
233
|
for (int b = 0; b < bands; ++b) {
|
|
234
|
-
spectrumBands[b] =
|
|
234
|
+
spectrumBands[b] = channelBands_[b].output;
|
|
235
235
|
}
|
|
236
236
|
}
|
|
237
237
|
});
|
|
@@ -280,9 +280,9 @@ struct SignalsmithStretch {
|
|
|
280
280
|
stft += plainOutput + foldedBackOutput;
|
|
281
281
|
// Reset the phase-vocoder stuff, so the next block gets a fresh start
|
|
282
282
|
for (int c = 0; c < channels; ++c) {
|
|
283
|
-
auto
|
|
283
|
+
auto channelBands_ = bandsForChannel(c);
|
|
284
284
|
for (int b = 0; b < bands; ++b) {
|
|
285
|
-
|
|
285
|
+
channelBands_[b].prevInput = channelBands_[b].output = 0;
|
|
286
286
|
}
|
|
287
287
|
}
|
|
288
288
|
flushed = true;
|
|
@@ -311,7 +311,7 @@ private:
|
|
|
311
311
|
Sample freqToBand(Sample f) const {
|
|
312
312
|
return f*stft.fftSize() - Sample(0.5);
|
|
313
313
|
}
|
|
314
|
-
|
|
314
|
+
|
|
315
315
|
struct Band {
|
|
316
316
|
Complex input, prevInput{0};
|
|
317
317
|
Complex output{0};
|
|
@@ -365,7 +365,7 @@ private:
|
|
|
365
365
|
Sample inputBin, freqGrad;
|
|
366
366
|
};
|
|
367
367
|
std::vector<PitchMapPoint> outputMap;
|
|
368
|
-
|
|
368
|
+
|
|
369
369
|
struct Prediction {
|
|
370
370
|
Sample energy = 0;
|
|
371
371
|
Complex input;
|
|
@@ -390,7 +390,7 @@ private:
|
|
|
390
390
|
timeFactor = std::max<Sample>(timeFactor, 1/maxCleanStretch);
|
|
391
391
|
bool randomTimeFactor = (timeFactor > maxCleanStretch);
|
|
392
392
|
std::uniform_real_distribution<Sample> timeFactorDist(maxCleanStretch*2*randomTimeFactor - timeFactor, timeFactor);
|
|
393
|
-
|
|
393
|
+
|
|
394
394
|
if (newSpectrum) {
|
|
395
395
|
for (int c = 0; c < channels; ++c) {
|
|
396
396
|
auto bins = bandsForChannel(c);
|
|
@@ -398,7 +398,7 @@ private:
|
|
|
398
398
|
Complex rot = std::polar(Sample(1), bandToFreq(0)*stft.interval()*Sample(2*M_PI));
|
|
399
399
|
Sample freqStep = bandToFreq(1) - bandToFreq(0);
|
|
400
400
|
Complex rotStep = std::polar(Sample(1), freqStep*stft.interval()*Sample(2*M_PI));
|
|
401
|
-
|
|
401
|
+
|
|
402
402
|
for (int b = 0; b < bands; ++b) {
|
|
403
403
|
auto &bin = bins[b];
|
|
404
404
|
bin.output = signalsmith::perf::mul(bin.output, rot);
|
|
@@ -477,7 +477,7 @@ private:
|
|
|
477
477
|
|
|
478
478
|
auto &downBin = bins[b - 1];
|
|
479
479
|
phase += signalsmith::perf::mul(downBin.output, shortVerticalTwist);
|
|
480
|
-
|
|
480
|
+
|
|
481
481
|
if (b >= longVerticalStep) {
|
|
482
482
|
Complex longDownInput = getFractional<&Band::input>(maxChannel, mapPoint.inputBin - longVerticalStep*binTimeFactor);
|
|
483
483
|
Complex longVerticalTwist = signalsmith::perf::mul<true>(prediction.input, longDownInput);
|
|
@@ -497,7 +497,7 @@ private:
|
|
|
497
497
|
|
|
498
498
|
auto &upBin = bins[b + 1];
|
|
499
499
|
phase += signalsmith::perf::mul<true>(upBin.output, shortVerticalTwist);
|
|
500
|
-
|
|
500
|
+
|
|
501
501
|
if (b < bands - longVerticalStep) {
|
|
502
502
|
auto &longUpPrediction = predictions[b + longVerticalStep];
|
|
503
503
|
auto &longUpMapPoint = outputMap[b + longVerticalStep];
|
|
@@ -511,13 +511,13 @@ private:
|
|
|
511
511
|
}
|
|
512
512
|
|
|
513
513
|
outputBin.output = prediction.makeOutput(phase);
|
|
514
|
-
|
|
514
|
+
|
|
515
515
|
// All other bins are locked in phase
|
|
516
516
|
for (int c = 0; c < channels; ++c) {
|
|
517
517
|
if (c != maxChannel) {
|
|
518
518
|
auto &channelBin = bandsForChannel(c)[b];
|
|
519
519
|
auto &channelPrediction = predictionsForChannel(c)[b];
|
|
520
|
-
|
|
520
|
+
|
|
521
521
|
Complex channelTwist = signalsmith::perf::mul<true>(channelPrediction.input, prediction.input);
|
|
522
522
|
Complex channelPhase = signalsmith::perf::mul(outputBin.output, channelTwist);
|
|
523
523
|
channelBin.output = channelPrediction.makeOutput(channelPhase);
|
|
@@ -531,7 +531,7 @@ private:
|
|
|
531
531
|
}
|
|
532
532
|
}
|
|
533
533
|
}
|
|
534
|
-
|
|
534
|
+
|
|
535
535
|
// Produces smoothed energy across all channels
|
|
536
536
|
void smoothEnergy(Sample smoothingBins) {
|
|
537
537
|
Sample smoothingSlew = 1/(1 + smoothingBins*Sample(0.5));
|
|
@@ -559,7 +559,7 @@ private:
|
|
|
559
559
|
}
|
|
560
560
|
}
|
|
561
561
|
}
|
|
562
|
-
|
|
562
|
+
|
|
563
563
|
Sample mapFreq(Sample freq) const {
|
|
564
564
|
if (customFreqMap) return customFreqMap(freq);
|
|
565
565
|
if (freq > freqTonalityLimit) {
|
|
@@ -568,13 +568,13 @@ private:
|
|
|
568
568
|
}
|
|
569
569
|
return freq*freqMultiplier;
|
|
570
570
|
}
|
|
571
|
-
|
|
571
|
+
|
|
572
572
|
// Identifies spectral peaks using energy across all channels
|
|
573
573
|
void findPeaks(Sample smoothingBins) {
|
|
574
574
|
smoothEnergy(smoothingBins);
|
|
575
575
|
|
|
576
576
|
peaks.resize(0);
|
|
577
|
-
|
|
577
|
+
|
|
578
578
|
int start = 0;
|
|
579
579
|
while (start < bands) {
|
|
580
580
|
if (energy[start] > smoothedEnergy[start]) {
|
|
@@ -594,7 +594,7 @@ private:
|
|
|
594
594
|
++start;
|
|
595
595
|
}
|
|
596
596
|
}
|
|
597
|
-
|
|
597
|
+
|
|
598
598
|
void updateOutputMap() {
|
|
599
599
|
if (peaks.empty()) {
|
|
600
600
|
for (int b = 0; b < bands; ++b) {
|
|
@@ -619,10 +619,10 @@ private:
|
|
|
619
619
|
Sample r = (b - prev.output)*rangeScale;
|
|
620
620
|
Sample h = r*r*(3 - 2*r);
|
|
621
621
|
Sample outB = b + outOffset + h*outScale;
|
|
622
|
-
|
|
622
|
+
|
|
623
623
|
Sample gradH = 6*r*(1 - r);
|
|
624
624
|
Sample gradB = 1 + gradH*gradScale;
|
|
625
|
-
|
|
625
|
+
|
|
626
626
|
outputMap[b] = {outB, gradB};
|
|
627
627
|
}
|
|
628
628
|
}
|
|
@@ -1,34 +1,41 @@
|
|
|
1
1
|
#import "AudioAPIModule.h"
|
|
2
2
|
|
|
3
|
-
#ifdef RCT_NEW_ARCH_ENABLED
|
|
4
3
|
#import <React/RCTBridge+Private.h>
|
|
4
|
+
|
|
5
|
+
#ifdef RCT_NEW_ARCH_ENABLED
|
|
5
6
|
#import <React/RCTCallInvoker.h>
|
|
6
7
|
#import <ReactCommon/RCTTurboModule.h>
|
|
7
8
|
#endif // RCT_NEW_ARCH_ENABLED
|
|
8
9
|
|
|
9
|
-
#include
|
|
10
|
+
#include <audioapi/AudioAPIModuleInstaller.h>
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
using namespace audioapi;
|
|
13
|
+
using namespace facebook::react;
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
@interface RCTBridge (JSIRuntime)
|
|
16
|
+
- (void *)runtime;
|
|
17
|
+
@end
|
|
18
|
+
|
|
19
|
+
#if defined(RCT_NEW_ARCH_ENABLED) && REACT_NATIVE_MINOR_VERSION >= 75
|
|
14
20
|
// nothing
|
|
15
|
-
#else // defined(RCT_NEW_ARCH_ENABLED)
|
|
21
|
+
#else // defined(RCT_NEW_ARCH_ENABLED) && REACT_NATIVE_MINOR_VERSION >= 75
|
|
16
22
|
@interface RCTBridge (RCTTurboModule)
|
|
17
23
|
- (std::shared_ptr<facebook::react::CallInvoker>)jsCallInvoker;
|
|
18
24
|
- (void)_tryAndHandleError:(dispatch_block_t)block;
|
|
19
25
|
@end
|
|
20
26
|
#endif // RCT_NEW_ARCH_ENABLED
|
|
21
27
|
|
|
28
|
+
@implementation AudioAPIModule
|
|
29
|
+
|
|
22
30
|
#if defined(RCT_NEW_ARCH_ENABLED)
|
|
23
31
|
@synthesize callInvoker = _callInvoker;
|
|
24
32
|
#endif // defined(RCT_NEW_ARCH_ENABLED)
|
|
25
33
|
|
|
26
|
-
RCT_EXPORT_MODULE(AudioAPIModule)
|
|
34
|
+
RCT_EXPORT_MODULE(AudioAPIModule);
|
|
27
35
|
|
|
28
36
|
RCT_EXPORT_BLOCKING_SYNCHRONOUS_METHOD(install)
|
|
29
37
|
{
|
|
30
|
-
auto
|
|
31
|
-
auto jsiRuntime = reinterpret_cast<facebook::jsi::Runtime *>(cxxBridge.runtime);
|
|
38
|
+
auto jsiRuntime = reinterpret_cast<facebook::jsi::Runtime *>(self.bridge.runtime);
|
|
32
39
|
|
|
33
40
|
#if defined(RCT_NEW_ARCH_ENABLED)
|
|
34
41
|
auto jsCallInvoker = _callInvoker.callInvoker;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#define MINIAUDIO_IMPLEMENTATION
|
|
2
|
-
#import <miniaudio.h>
|
|
2
|
+
#import <audioapi/libs/miniaudio.h>
|
|
3
3
|
|
|
4
|
-
#include <AudioArray.h>
|
|
5
|
-
#include <AudioBus.h>
|
|
6
|
-
#include <AudioDecoder.h>
|
|
4
|
+
#include <audioapi/core/utils/AudioArray.h>
|
|
5
|
+
#include <audioapi/core/utils/AudioBus.h>
|
|
6
|
+
#include <audioapi/core/utils/AudioDecoder.h>
|
|
7
7
|
|
|
8
8
|
namespace audioapi {
|
|
9
9
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#import <AVFoundation/AVFoundation.h>
|
|
2
2
|
|
|
3
|
-
#include <
|
|
4
|
-
#include <
|
|
5
|
-
#include <
|
|
6
|
-
#include <IOSAudioPlayer.h>
|
|
3
|
+
#include <audioapi/core/Constants.h>
|
|
4
|
+
#include <audioapi/core/utils/AudioArray.h>
|
|
5
|
+
#include <audioapi/core/utils/AudioBus.h>
|
|
6
|
+
#include <audioapi/ios/core/IOSAudioPlayer.h>
|
|
7
7
|
|
|
8
8
|
namespace audioapi {
|
|
9
9
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-audio-api",
|
|
3
|
-
"version": "0.4.12-beta.
|
|
3
|
+
"version": "0.4.12-beta.3",
|
|
4
4
|
"description": "react-native-audio-api provides system for controlling audio in React Native environment compatible with Web Audio API specification",
|
|
5
5
|
"main": "lib/commonjs/index",
|
|
6
6
|
"module": "lib/module/index",
|
|
@@ -36,17 +36,17 @@
|
|
|
36
36
|
"scripts": {
|
|
37
37
|
"test": "jest",
|
|
38
38
|
"typecheck": "tsc --noEmit",
|
|
39
|
-
"lint": "yarn lint:js && yarn lint:cpp
|
|
39
|
+
"lint": "yarn lint:js && yarn lint:cpp && yarn lint:ios && yarn lint:kotlin",
|
|
40
40
|
"lint:js": "eslint src && yarn prettier --check src",
|
|
41
41
|
"lint:cpp": "./scripts/cpplint.sh",
|
|
42
42
|
"lint:ios": "yarn format:ios --dry-run -Werror",
|
|
43
|
-
"lint:kotlin": "ktlint 'android/src/main/java
|
|
43
|
+
"lint:kotlin": "ktlint 'android/src/main/java/**/*.kt'",
|
|
44
44
|
"format": "yarn format:js && yarn format:android:cpp && yarn format:android:kotlin && yarn format:ios && yarn format:common",
|
|
45
45
|
"format:js": "prettier --write --list-different src",
|
|
46
|
-
"format:android:cpp": "find android/src/ -path android/src/cpp/libs -iname \"*.h\" -o -iname \"*.cpp\" | xargs clang-format -i",
|
|
47
|
-
"format:android:kotlin": "ktlint -F 'android/src/main/java
|
|
46
|
+
"format:android:cpp": "find android/src/ -path android/src/main/cpp/audioapi/android/libs -iname \"*.h\" -o -iname \"*.cpp\" | xargs clang-format -i",
|
|
47
|
+
"format:android:kotlin": "ktlint -F 'android/src/main/java/**/*.kt'",
|
|
48
48
|
"format:ios": "find ios/ -iname \"*.h\" -o -iname \"*.m\" -o -iname \"*.mm\" -o -iname \"*.cpp\" | xargs clang-format -i",
|
|
49
|
-
"format:common": "find common/cpp/ -path 'common/cpp/libs' -prune -iname \"*.h\" -o -iname \"*.cpp\" | xargs clang-format -i",
|
|
49
|
+
"format:common": "find common/cpp/ -path 'common/cpp/audioapi/libs' -prune -iname \"*.h\" -o -iname \"*.cpp\" | xargs clang-format -i",
|
|
50
50
|
"build": "bob build",
|
|
51
51
|
"prepack": "cp ../../README.md ./README.md",
|
|
52
52
|
"postpack": "rm ./README.md"
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include <memory>
|
|
4
|
-
#include <vector>
|
|
5
|
-
|
|
6
|
-
#include "AudioNodeHostObject.h"
|
|
7
|
-
#include "AudioParamHostObject.h"
|
|
8
|
-
#include "StretcherNode.h"
|
|
9
|
-
|
|
10
|
-
namespace audioapi {
|
|
11
|
-
using namespace facebook;
|
|
12
|
-
|
|
13
|
-
class StretcherNodeHostObject : public AudioNodeHostObject {
|
|
14
|
-
public:
|
|
15
|
-
explicit StretcherNodeHostObject(const std::shared_ptr<StretcherNode> &node)
|
|
16
|
-
: AudioNodeHostObject(node) {
|
|
17
|
-
addGetters(JSI_EXPORT_PROPERTY_GETTER(StretcherNodeHostObject, rate),
|
|
18
|
-
JSI_EXPORT_PROPERTY_GETTER(StretcherNodeHostObject, semitones));
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
JSI_PROPERTY_GETTER(rate) {
|
|
22
|
-
auto stretcherNode = std::static_pointer_cast<StretcherNode>(node_);
|
|
23
|
-
auto rateParam =
|
|
24
|
-
std::make_shared<AudioParamHostObject>(stretcherNode->getRateParam());
|
|
25
|
-
return jsi::Object::createFromHostObject(runtime, rateParam);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
JSI_PROPERTY_GETTER(semitones) {
|
|
29
|
-
auto stretcherNode = std::static_pointer_cast<StretcherNode>(node_);
|
|
30
|
-
auto semitonesParam =
|
|
31
|
-
std::make_shared<AudioParamHostObject>(stretcherNode->getSemitonesParam());
|
|
32
|
-
return jsi::Object::createFromHostObject(runtime, semitonesParam);
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
} // namespace audioapi
|