react-native-audio-api 0.4.11 → 0.4.12-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/common/cpp/HostObjects/AudioBufferSourceNodeHostObject.h +1 -2
- package/common/cpp/HostObjects/BaseAudioContextHostObject.h +8 -0
- package/common/cpp/HostObjects/GainNodeHostObject.h +2 -2
- package/common/cpp/HostObjects/StretcherNodeHostObject.h +35 -0
- package/common/cpp/core/AudioBus.cpp +8 -0
- package/common/cpp/core/AudioBus.h +3 -0
- package/common/cpp/core/AudioDestinationNode.cpp +1 -1
- package/common/cpp/core/AudioNode.cpp +9 -5
- package/common/cpp/core/AudioNode.h +4 -2
- package/common/cpp/core/BaseAudioContext.cpp +7 -0
- package/common/cpp/core/BaseAudioContext.h +2 -0
- package/common/cpp/core/StretcherNode.cpp +96 -0
- package/common/cpp/core/StretcherNode.h +63 -0
- package/common/cpp/installer/AudioAPIModuleInstaller.h +4 -4
- package/common/cpp/libs/dsp/LICENSE.txt +21 -0
- package/common/cpp/libs/dsp/README.md +40 -0
- package/common/cpp/libs/dsp/common.h +47 -0
- package/common/cpp/libs/dsp/curves.h +371 -0
- package/common/cpp/libs/dsp/delay.h +717 -0
- package/common/cpp/libs/dsp/envelopes.h +523 -0
- package/common/cpp/libs/dsp/fft.h +523 -0
- package/common/cpp/libs/dsp/filters.h +436 -0
- package/common/cpp/libs/dsp/mix.h +218 -0
- package/common/cpp/libs/dsp/perf.h +84 -0
- package/common/cpp/libs/dsp/rates.h +184 -0
- package/common/cpp/libs/dsp/spectral.h +496 -0
- package/common/cpp/libs/dsp/windows.h +219 -0
- package/common/cpp/libs/signalsmith-stretch.h +637 -0
- package/common/cpp/types/TimeStretchType.h +6 -0
- package/ios/core/AudioPlayer.m +2 -2
- package/lib/module/core/BaseAudioContext.js +4 -0
- package/lib/module/core/BaseAudioContext.js.map +1 -1
- package/lib/module/core/StretcherNode.js +12 -0
- package/lib/module/core/StretcherNode.js.map +1 -0
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +1 -1
- package/lib/module/index.web.js.map +1 -1
- package/lib/typescript/core/BaseAudioContext.d.ts +2 -0
- package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/core/StretcherNode.d.ts +10 -0
- package/lib/typescript/core/StretcherNode.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +1 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/index.web.d.ts +1 -1
- package/lib/typescript/index.web.d.ts.map +1 -1
- package/lib/typescript/interfaces.d.ts +5 -0
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/BaseAudioContext.ts +5 -0
- package/src/core/StretcherNode.ts +15 -0
- package/src/index.ts +1 -0
- package/src/index.web.ts +1 -0
- package/src/interfaces.ts +6 -0
- package/common/cpp/installer/AudioAPIModuleInstaller.cpp +0 -49
|
@@ -23,8 +23,7 @@ class AudioBufferSourceNodeHostObject
|
|
|
23
23
|
JSI_EXPORT_PROPERTY_GETTER(AudioBufferSourceNodeHostObject, loopStart),
|
|
24
24
|
JSI_EXPORT_PROPERTY_GETTER(AudioBufferSourceNodeHostObject, loopEnd),
|
|
25
25
|
JSI_EXPORT_PROPERTY_GETTER(AudioBufferSourceNodeHostObject, detune),
|
|
26
|
-
JSI_EXPORT_PROPERTY_GETTER(
|
|
27
|
-
AudioBufferSourceNodeHostObject, playbackRate));
|
|
26
|
+
JSI_EXPORT_PROPERTY_GETTER(AudioBufferSourceNodeHostObject, playbackRate));
|
|
28
27
|
|
|
29
28
|
addSetters(
|
|
30
29
|
JSI_EXPORT_PROPERTY_SETTER(AudioBufferSourceNodeHostObject, loop),
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
#include "PeriodicWaveHostObject.h"
|
|
20
20
|
#include "StereoPannerNodeHostObject.h"
|
|
21
21
|
#include "AnalyserNodeHostObject.h"
|
|
22
|
+
#include "StretcherNodeHostObject.h"
|
|
22
23
|
|
|
23
24
|
namespace audioapi {
|
|
24
25
|
using namespace facebook;
|
|
@@ -44,6 +45,7 @@ class BaseAudioContextHostObject : public JsiHostObject {
|
|
|
44
45
|
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createBuffer),
|
|
45
46
|
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createPeriodicWave),
|
|
46
47
|
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createAnalyser),
|
|
48
|
+
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createStretcher),
|
|
47
49
|
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, decodeAudioDataSource));
|
|
48
50
|
}
|
|
49
51
|
|
|
@@ -140,6 +142,12 @@ class BaseAudioContextHostObject : public JsiHostObject {
|
|
|
140
142
|
return jsi::Object::createFromHostObject(runtime, analyserHostObject);
|
|
141
143
|
}
|
|
142
144
|
|
|
145
|
+
JSI_HOST_FUNCTION(createStretcher) {
|
|
146
|
+
auto stretcher = context_->createStretcher();
|
|
147
|
+
auto stretcherHostObject = std::make_shared<StretcherNodeHostObject>(stretcher);
|
|
148
|
+
return jsi::Object::createFromHostObject(runtime, stretcherHostObject);
|
|
149
|
+
}
|
|
150
|
+
|
|
143
151
|
JSI_HOST_FUNCTION(decodeAudioDataSource) {
|
|
144
152
|
auto sourcePath = args[0].getString(runtime).utf8(runtime);
|
|
145
153
|
|
|
@@ -19,9 +19,9 @@ class GainNodeHostObject : public AudioNodeHostObject {
|
|
|
19
19
|
|
|
20
20
|
JSI_PROPERTY_GETTER(gain) {
|
|
21
21
|
auto gainNode = std::static_pointer_cast<GainNode>(node_);
|
|
22
|
-
auto
|
|
22
|
+
auto gainParam =
|
|
23
23
|
std::make_shared<AudioParamHostObject>(gainNode->getGainParam());
|
|
24
|
-
return jsi::Object::createFromHostObject(runtime,
|
|
24
|
+
return jsi::Object::createFromHostObject(runtime, gainParam);
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
27
|
} // namespace audioapi
|
|
@@ -0,0 +1,35 @@
|
|
|
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
|
|
@@ -119,6 +119,14 @@ AudioArray *AudioBus::getChannelByType(int channelType) const {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
AudioArray &AudioBus::operator[](size_t index) {
|
|
123
|
+
return *channels_[index];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const AudioArray &AudioBus::operator[](size_t index) const {
|
|
127
|
+
return *channels_[index];
|
|
128
|
+
}
|
|
129
|
+
|
|
122
130
|
/**
|
|
123
131
|
* Public interfaces - audio processing and setters
|
|
124
132
|
*/
|
|
@@ -34,6 +34,9 @@ class AudioBus {
|
|
|
34
34
|
[[nodiscard]] AudioArray *getChannel(int index) const;
|
|
35
35
|
[[nodiscard]] AudioArray *getChannelByType(int channelType) const;
|
|
36
36
|
|
|
37
|
+
AudioArray &operator[](size_t index);
|
|
38
|
+
const AudioArray &operator[](size_t index) const;
|
|
39
|
+
|
|
37
40
|
void normalize();
|
|
38
41
|
void scale(float value);
|
|
39
42
|
[[nodiscard]] float maxAbsValue() const;
|
|
@@ -33,7 +33,7 @@ void AudioDestinationNode::renderAudio(
|
|
|
33
33
|
|
|
34
34
|
destinationBus->zero();
|
|
35
35
|
|
|
36
|
-
auto processedBus = processAudio(destinationBus, numFrames);
|
|
36
|
+
auto processedBus = processAudio(destinationBus, numFrames, true);
|
|
37
37
|
|
|
38
38
|
if (processedBus && processedBus != destinationBus) {
|
|
39
39
|
destinationBus->copy(processedBus.get());
|
|
@@ -99,17 +99,19 @@ std::string AudioNode::toString(ChannelInterpretation interpretation) {
|
|
|
99
99
|
|
|
100
100
|
std::shared_ptr<AudioBus> AudioNode::processAudio(
|
|
101
101
|
std::shared_ptr<AudioBus> outputBus,
|
|
102
|
-
int framesToProcess
|
|
102
|
+
int framesToProcess,
|
|
103
|
+
bool checkIsAlreadyProcessed) {
|
|
103
104
|
if (!isInitialized_) {
|
|
104
105
|
return outputBus;
|
|
105
106
|
}
|
|
106
107
|
|
|
107
|
-
if (isAlreadyProcessed()) {
|
|
108
|
+
if (checkIsAlreadyProcessed && isAlreadyProcessed()) {
|
|
108
109
|
return audioBus_;
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
// Process inputs and return the bus with the most channels.
|
|
112
|
-
auto processingBus =
|
|
113
|
+
auto processingBus =
|
|
114
|
+
processInputs(outputBus, framesToProcess, checkIsAlreadyProcessed);
|
|
113
115
|
|
|
114
116
|
// Apply channel count mode.
|
|
115
117
|
processingBus = applyChannelCountMode(processingBus);
|
|
@@ -142,7 +144,8 @@ bool AudioNode::isAlreadyProcessed() {
|
|
|
142
144
|
|
|
143
145
|
std::shared_ptr<AudioBus> AudioNode::processInputs(
|
|
144
146
|
const std::shared_ptr<AudioBus> &outputBus,
|
|
145
|
-
int framesToProcess
|
|
147
|
+
int framesToProcess,
|
|
148
|
+
bool checkIsAlreadyProcessed) {
|
|
146
149
|
auto processingBus = audioBus_;
|
|
147
150
|
processingBus->zero();
|
|
148
151
|
|
|
@@ -154,7 +157,8 @@ std::shared_ptr<AudioBus> AudioNode::processInputs(
|
|
|
154
157
|
continue;
|
|
155
158
|
}
|
|
156
159
|
|
|
157
|
-
auto inputBus = inputNode->processAudio(
|
|
160
|
+
auto inputBus = inputNode->processAudio(
|
|
161
|
+
outputBus, framesToProcess, checkIsAlreadyProcessed);
|
|
158
162
|
inputBuses_.push_back(inputBus);
|
|
159
163
|
|
|
160
164
|
if (maxNumberOfChannels < inputBus->getNumberOfChannels()) {
|
|
@@ -57,16 +57,18 @@ class AudioNode : public std::enable_shared_from_this<AudioNode> {
|
|
|
57
57
|
std::size_t lastRenderedFrame_{SIZE_MAX};
|
|
58
58
|
|
|
59
59
|
private:
|
|
60
|
+
friend class StretcherNode;
|
|
61
|
+
|
|
60
62
|
std::vector<std::shared_ptr<AudioBus>> inputBuses_ = {};
|
|
61
63
|
|
|
62
64
|
static std::string toString(ChannelCountMode mode);
|
|
63
65
|
static std::string toString(ChannelInterpretation interpretation);
|
|
64
66
|
|
|
65
|
-
std::shared_ptr<AudioBus> processAudio(std::shared_ptr<AudioBus> outputBus, int framesToProcess);
|
|
67
|
+
virtual std::shared_ptr<AudioBus> processAudio(std::shared_ptr<AudioBus> outputBus, int framesToProcess, bool checkIsAlreadyProcessed);
|
|
66
68
|
virtual void processNode(const std::shared_ptr<AudioBus>&, int) = 0;
|
|
67
69
|
|
|
68
70
|
bool isAlreadyProcessed();
|
|
69
|
-
std::shared_ptr<AudioBus> processInputs(const std::shared_ptr<AudioBus>& outputBus, int framesToProcess);
|
|
71
|
+
std::shared_ptr<AudioBus> processInputs(const std::shared_ptr<AudioBus>& outputBus, int framesToProcess, bool checkIsAlreadyProcessed);
|
|
70
72
|
std::shared_ptr<AudioBus> applyChannelCountMode(std::shared_ptr<AudioBus> processingBus);
|
|
71
73
|
void mixInputsBuses(const std::shared_ptr<AudioBus>& processingBus);
|
|
72
74
|
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
#include "GainNode.h"
|
|
15
15
|
#include "OscillatorNode.h"
|
|
16
16
|
#include "StereoPannerNode.h"
|
|
17
|
+
#include "StretcherNode.h"
|
|
17
18
|
|
|
18
19
|
namespace audioapi {
|
|
19
20
|
|
|
@@ -96,6 +97,12 @@ std::shared_ptr<AnalyserNode> BaseAudioContext::createAnalyser() {
|
|
|
96
97
|
return analyser;
|
|
97
98
|
}
|
|
98
99
|
|
|
100
|
+
std::shared_ptr<StretcherNode> BaseAudioContext::createStretcher() {
|
|
101
|
+
auto node = std::make_shared<StretcherNode>(this);
|
|
102
|
+
nodeManager_->addNode(node);
|
|
103
|
+
return node;
|
|
104
|
+
}
|
|
105
|
+
|
|
99
106
|
std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioDataSource(
|
|
100
107
|
const std::string &path) {
|
|
101
108
|
auto audioBus = audioDecoder_->decodeWithFilePath(path);
|
|
@@ -24,6 +24,7 @@ class AudioDestinationNode;
|
|
|
24
24
|
class AudioBufferSourceNode;
|
|
25
25
|
class AudioDecoder;
|
|
26
26
|
class AnalyserNode;
|
|
27
|
+
class StretcherNode;
|
|
27
28
|
|
|
28
29
|
class BaseAudioContext {
|
|
29
30
|
public:
|
|
@@ -49,6 +50,7 @@ class BaseAudioContext {
|
|
|
49
50
|
bool disableNormalization,
|
|
50
51
|
int length);
|
|
51
52
|
std::shared_ptr<AnalyserNode> createAnalyser();
|
|
53
|
+
std::shared_ptr<StretcherNode> createStretcher();
|
|
52
54
|
|
|
53
55
|
std::shared_ptr<AudioBuffer> decodeAudioDataSource(const std::string &path);
|
|
54
56
|
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#include <cassert>
|
|
2
|
+
|
|
3
|
+
#include "AudioArray.h"
|
|
4
|
+
#include "AudioBus.h"
|
|
5
|
+
#include "BaseAudioContext.h"
|
|
6
|
+
#include "StretcherNode.h"
|
|
7
|
+
|
|
8
|
+
namespace audioapi {
|
|
9
|
+
|
|
10
|
+
StretcherNode::StretcherNode(BaseAudioContext *context) : AudioNode(context) {
|
|
11
|
+
channelCountMode_ = ChannelCountMode::EXPLICIT;
|
|
12
|
+
rate_ = std::make_shared<AudioParam>(1.0, 0.0, 3.0);
|
|
13
|
+
semitones_ = std::make_shared<AudioParam>(0.0, -12.0, 12.0);
|
|
14
|
+
|
|
15
|
+
stretch_ =
|
|
16
|
+
std::make_shared<signalsmith::stretch::SignalsmithStretch<float>>();
|
|
17
|
+
stretch_->presetDefault(channelCount_, context->getSampleRate());
|
|
18
|
+
playbackRateBus_ = std::make_shared<AudioBus>(
|
|
19
|
+
RENDER_QUANTUM_SIZE * 3, channelCount_, context_->getSampleRate());
|
|
20
|
+
|
|
21
|
+
isInitialized_ = true;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
std::shared_ptr<AudioParam> StretcherNode::getRateParam() const {
|
|
25
|
+
return rate_;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
std::shared_ptr<AudioParam> StretcherNode::getSemitonesParam() const {
|
|
29
|
+
return semitones_;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
void StretcherNode::processNode(
|
|
33
|
+
const std::shared_ptr<AudioBus> &processingBus,
|
|
34
|
+
int framesToProcess) {
|
|
35
|
+
auto time = context_->getCurrentTime();
|
|
36
|
+
auto semitones = semitones_->getValueAtTime(time);
|
|
37
|
+
|
|
38
|
+
stretch_->setTransposeSemitones(semitones);
|
|
39
|
+
stretch_->process(
|
|
40
|
+
playbackRateBus_.get()[0],
|
|
41
|
+
framesNeededToStretch_,
|
|
42
|
+
audioBus_.get()[0],
|
|
43
|
+
framesToProcess);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
std::shared_ptr<AudioBus> StretcherNode::processAudio(
|
|
47
|
+
std::shared_ptr<AudioBus> outputBus,
|
|
48
|
+
int framesToProcess,
|
|
49
|
+
bool checkIsAlreadyProcessed) {
|
|
50
|
+
if (!isInitialized_) {
|
|
51
|
+
return outputBus;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (isAlreadyProcessed()) {
|
|
55
|
+
return audioBus_;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
auto time = context_->getCurrentTime();
|
|
59
|
+
|
|
60
|
+
auto rate = rate_->getValueAtTime(time);
|
|
61
|
+
framesNeededToStretch_ =
|
|
62
|
+
static_cast<int>(rate * static_cast<float>(framesToProcess));
|
|
63
|
+
|
|
64
|
+
playbackRateBus_->zero();
|
|
65
|
+
auto writeIndex = 0;
|
|
66
|
+
auto framesNeededToStretch = framesNeededToStretch_;
|
|
67
|
+
|
|
68
|
+
// Collecting frames needed to stretch
|
|
69
|
+
while (framesNeededToStretch > 0) {
|
|
70
|
+
auto framesToCopy = std::min(framesNeededToStretch, framesToProcess);
|
|
71
|
+
|
|
72
|
+
// Process inputs and return the bus with the most channels. We must not
|
|
73
|
+
// check if the node has already been processed, cause we need to process it
|
|
74
|
+
// multiple times in this case.
|
|
75
|
+
auto processingBus = processInputs(outputBus, framesToCopy, false);
|
|
76
|
+
|
|
77
|
+
// Apply channel count mode.
|
|
78
|
+
processingBus = applyChannelCountMode(processingBus);
|
|
79
|
+
|
|
80
|
+
// Mix all input buses into the processing bus.
|
|
81
|
+
mixInputsBuses(processingBus);
|
|
82
|
+
|
|
83
|
+
assert(processingBus != nullptr);
|
|
84
|
+
|
|
85
|
+
playbackRateBus_->copy(processingBus.get(), 0, writeIndex, framesToCopy);
|
|
86
|
+
|
|
87
|
+
writeIndex += framesToCopy;
|
|
88
|
+
framesNeededToStretch -= framesToCopy;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
processNode(audioBus_, framesToProcess);
|
|
92
|
+
|
|
93
|
+
return audioBus_;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
} // namespace audioapi
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <memory>
|
|
4
|
+
#include <string>
|
|
5
|
+
|
|
6
|
+
#include "signalsmith-stretch.h"
|
|
7
|
+
#include "TimeStretchType.h"
|
|
8
|
+
#include "AudioNode.h"
|
|
9
|
+
#include "AudioParam.h"
|
|
10
|
+
|
|
11
|
+
namespace audioapi {
|
|
12
|
+
class AudioBus;
|
|
13
|
+
|
|
14
|
+
class StretcherNode : public AudioNode {
|
|
15
|
+
public:
|
|
16
|
+
explicit StretcherNode(BaseAudioContext *context);
|
|
17
|
+
|
|
18
|
+
[[nodiscard]] std::shared_ptr<AudioParam> getRateParam() const;
|
|
19
|
+
[[nodiscard]] std::shared_ptr<AudioParam> getSemitonesParam() const;
|
|
20
|
+
|
|
21
|
+
protected:
|
|
22
|
+
void processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
|
|
23
|
+
std::shared_ptr<AudioBus> processAudio(std::shared_ptr<AudioBus> outputBus, int framesToProcess, bool checkIsAlreadyProcessed) override;
|
|
24
|
+
|
|
25
|
+
private:
|
|
26
|
+
// k-rate params
|
|
27
|
+
std::shared_ptr<AudioParam> rate_;
|
|
28
|
+
std::shared_ptr<AudioParam> semitones_;
|
|
29
|
+
|
|
30
|
+
std::shared_ptr<signalsmith::stretch::SignalsmithStretch<float>> stretch_;
|
|
31
|
+
std::shared_ptr<AudioBus> playbackRateBus_;
|
|
32
|
+
int framesNeededToStretch_ = RENDER_QUANTUM_SIZE;
|
|
33
|
+
|
|
34
|
+
static TimeStretchType fromString(const std::string &type) {
|
|
35
|
+
std::string lowerType = type;
|
|
36
|
+
std::transform(
|
|
37
|
+
lowerType.begin(), lowerType.end(), lowerType.begin(), ::tolower);
|
|
38
|
+
|
|
39
|
+
if (lowerType == "linear")
|
|
40
|
+
return TimeStretchType::LINEAR;
|
|
41
|
+
if (lowerType == "speech")
|
|
42
|
+
return TimeStretchType::SPEECH;
|
|
43
|
+
if (lowerType == "music")
|
|
44
|
+
return TimeStretchType::MUSIC;
|
|
45
|
+
|
|
46
|
+
throw std::invalid_argument("Unknown time stretch type: " + type);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static std::string toString(TimeStretchType type) {
|
|
50
|
+
switch (type) {
|
|
51
|
+
case TimeStretchType::LINEAR:
|
|
52
|
+
return "linear";
|
|
53
|
+
case TimeStretchType::SPEECH:
|
|
54
|
+
return "speech";
|
|
55
|
+
case TimeStretchType::MUSIC:
|
|
56
|
+
return "music";
|
|
57
|
+
default:
|
|
58
|
+
throw std::invalid_argument("Unknown time stretch type");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
} // namespace audioapi
|
|
@@ -9,14 +9,14 @@ namespace audioapi {
|
|
|
9
9
|
using namespace facebook;
|
|
10
10
|
|
|
11
11
|
class AudioAPIModuleInstaller {
|
|
12
|
-
public:
|
|
12
|
+
public:
|
|
13
13
|
static void injectJSIBindings(jsi::Runtime *jsiRuntime, const std::shared_ptr<react::CallInvoker> &jsCallInvoker) {
|
|
14
14
|
auto createAudioContext = getCreateAudioContextFunction(jsiRuntime, jsCallInvoker);
|
|
15
15
|
jsiRuntime->global().setProperty(
|
|
16
16
|
*jsiRuntime, "createAudioContext", createAudioContext);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
private:
|
|
19
|
+
private:
|
|
20
20
|
static jsi::Function getCreateAudioContextFunction(jsi::Runtime *jsiRuntime, const std::shared_ptr<react::CallInvoker> &jsCallInvoker) {
|
|
21
21
|
return jsi::Function::createFromHostFunction(
|
|
22
22
|
*jsiRuntime,
|
|
@@ -34,8 +34,8 @@ private:
|
|
|
34
34
|
auto sampleRate = static_cast<float>(args[0].getNumber());
|
|
35
35
|
audioContext = std::make_shared<AudioContext>(sampleRate);
|
|
36
36
|
}
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
|
|
38
|
+
auto promiseVendor = std::make_shared<PromiseVendor>(jsiRuntime, jsCallInvoker);
|
|
39
39
|
|
|
40
40
|
auto audioContextHostObject = std::make_shared<AudioContextHostObject>(
|
|
41
41
|
audioContext, promiseVendor);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Geraint Luff / Signalsmith Audio Ltd.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Signalsmith Audio's DSP Library
|
|
2
|
+
|
|
3
|
+
A C++11 header-only library, providing classes/templates for (mostly audio) signal-processing tasks.
|
|
4
|
+
|
|
5
|
+
More detail is in the [main project page](https://signalsmith-audio.co.uk/code/dsp/), and the [Doxygen docs](https://signalsmith-audio.co.uk/code/dsp/html/modules.html).
|
|
6
|
+
|
|
7
|
+
## Basic use
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
git clone https://signalsmith-audio.co.uk/code/dsp.git
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Just include the header file(s) you need, and start using classes:
|
|
14
|
+
|
|
15
|
+
```cpp
|
|
16
|
+
#include "dsp/delay.h"
|
|
17
|
+
|
|
18
|
+
using Delay = signalsmith::delay::Delay<float>;
|
|
19
|
+
Delay delayLine(1024);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
You can add a compile-time version-check to make sure you have a compatible version of the library:
|
|
23
|
+
```cpp
|
|
24
|
+
#include "dsp/envelopes.h"
|
|
25
|
+
SIGNALSMITH_DSP_VERSION_CHECK(1, 6, 1)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Development / contributing
|
|
29
|
+
|
|
30
|
+
Tests (and source-scripts for the above docs) are available in a separate repo:
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
git clone https://signalsmith-audio.co.uk/code/dsp-doc.git
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The goal (where possible) is to measure/test the actual audio characteristics of the tools (e.g. frequency responses and aliasing levels).
|
|
37
|
+
|
|
38
|
+
### License
|
|
39
|
+
|
|
40
|
+
This code is [MIT licensed](LICENSE.txt). If you'd prefer something else, get in touch.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#ifndef SIGNALSMITH_DSP_COMMON_H
|
|
2
|
+
#define SIGNALSMITH_DSP_COMMON_H
|
|
3
|
+
|
|
4
|
+
#if defined(__FAST_MATH__) && (__apple_build_version__ >= 16000000) && (__apple_build_version__ <= 16000099)
|
|
5
|
+
# error Apple Clang 16.0.0 generates incorrect SIMD for ARM. If you HAVE to use this version of Clang, turn off -ffast-math.
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
#ifndef M_PI
|
|
9
|
+
#define M_PI 3.14159265358979323846264338327950288
|
|
10
|
+
#endif
|
|
11
|
+
|
|
12
|
+
namespace signalsmith {
|
|
13
|
+
/** @defgroup Common Common
|
|
14
|
+
@brief Definitions and helper classes used by the rest of the library
|
|
15
|
+
|
|
16
|
+
@{
|
|
17
|
+
@file
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
#define SIGNALSMITH_DSP_VERSION_MAJOR 1
|
|
21
|
+
#define SIGNALSMITH_DSP_VERSION_MINOR 6
|
|
22
|
+
#define SIGNALSMITH_DSP_VERSION_PATCH 1
|
|
23
|
+
#define SIGNALSMITH_DSP_VERSION_STRING "1.6.1"
|
|
24
|
+
|
|
25
|
+
/** Version compatability check.
|
|
26
|
+
\code{.cpp}
|
|
27
|
+
static_assert(signalsmith::version(1, 4, 1), "version check");
|
|
28
|
+
\endcode
|
|
29
|
+
... or use the equivalent `SIGNALSMITH_DSP_VERSION_CHECK`.
|
|
30
|
+
Major versions are not compatible with each other. Minor and patch versions are backwards-compatible.
|
|
31
|
+
*/
|
|
32
|
+
constexpr bool versionCheck(int major, int minor, int patch=0) {
|
|
33
|
+
return major == SIGNALSMITH_DSP_VERSION_MAJOR
|
|
34
|
+
&& (SIGNALSMITH_DSP_VERSION_MINOR > minor
|
|
35
|
+
|| (SIGNALSMITH_DSP_VERSION_MINOR == minor && SIGNALSMITH_DSP_VERSION_PATCH >= patch));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/// Check the library version is compatible (semver).
|
|
39
|
+
#define SIGNALSMITH_DSP_VERSION_CHECK(major, minor, patch) \
|
|
40
|
+
static_assert(::signalsmith::versionCheck(major, minor, patch), "signalsmith library version is " SIGNALSMITH_DSP_VERSION_STRING);
|
|
41
|
+
|
|
42
|
+
/** @} */
|
|
43
|
+
} // signalsmith::
|
|
44
|
+
#else
|
|
45
|
+
// If we've already included it, check it's the same version
|
|
46
|
+
static_assert(SIGNALSMITH_DSP_VERSION_MAJOR == 1 && SIGNALSMITH_DSP_VERSION_MINOR == 6 && SIGNALSMITH_DSP_VERSION_PATCH == 1, "multiple versions of the Signalsmith DSP library");
|
|
47
|
+
#endif // include guard
|