react-native-audio-api 0.1.0 → 0.2.0
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/README.md +10 -8
- package/RNAudioAPI.podspec +5 -0
- package/android/CMakeLists.txt +21 -10
- package/android/libs/fftw3/arm64-v8a/libfftw3.a +0 -0
- package/android/libs/fftw3/armeabi-v7a/libfftw3.a +0 -0
- package/android/libs/fftw3/x86/libfftw3.a +0 -0
- package/android/libs/fftw3/x86_64/libfftw3.a +0 -0
- package/android/libs/include/fftw3/fftw3.h +413 -0
- package/android/src/main/cpp/AudioPlayer/AudioPlayer.cpp +23 -2
- package/android/src/main/cpp/AudioPlayer/AudioPlayer.h +5 -2
- package/common/cpp/HostObjects/AudioBufferSourceNodeHostObject.cpp +13 -1
- package/common/cpp/HostObjects/AudioContextHostObject.cpp +11 -148
- package/common/cpp/HostObjects/AudioContextHostObject.h +4 -11
- package/common/cpp/HostObjects/AudioNodeHostObject.cpp +0 -6
- package/common/cpp/HostObjects/BaseAudioContextHostObject.cpp +214 -0
- package/common/cpp/HostObjects/BaseAudioContextHostObject.h +39 -0
- package/common/cpp/HostObjects/BiquadFilterNodeHostObject.cpp +44 -0
- package/common/cpp/HostObjects/OscillatorNodeHostObject.cpp +21 -0
- package/common/cpp/HostObjects/OscillatorNodeHostObject.h +1 -0
- package/common/cpp/HostObjects/PeriodicWaveHostObject.cpp +33 -0
- package/common/cpp/HostObjects/PeriodicWaveHostObject.h +33 -0
- package/common/cpp/core/AudioArray.cpp +103 -0
- package/common/cpp/core/AudioArray.h +42 -0
- package/common/cpp/core/AudioBuffer.cpp +23 -83
- package/common/cpp/core/AudioBuffer.h +11 -13
- package/common/cpp/core/AudioBufferSourceNode.cpp +102 -25
- package/common/cpp/core/AudioBufferSourceNode.h +10 -6
- package/common/cpp/core/AudioBus.cpp +357 -0
- package/common/cpp/core/AudioBus.h +63 -0
- package/common/cpp/core/AudioContext.cpp +6 -72
- package/common/cpp/core/AudioContext.h +3 -60
- package/common/cpp/core/AudioDestinationNode.cpp +25 -15
- package/common/cpp/core/AudioDestinationNode.h +15 -7
- package/common/cpp/core/AudioNode.cpp +176 -22
- package/common/cpp/core/AudioNode.h +37 -37
- package/common/cpp/core/AudioNodeManager.cpp +72 -0
- package/common/cpp/core/AudioNodeManager.h +35 -0
- package/common/cpp/core/AudioParam.cpp +8 -11
- package/common/cpp/core/AudioParam.h +8 -8
- package/common/cpp/core/AudioScheduledSourceNode.cpp +19 -5
- package/common/cpp/core/AudioScheduledSourceNode.h +6 -2
- package/common/cpp/core/BaseAudioContext.cpp +157 -0
- package/common/cpp/core/BaseAudioContext.h +80 -0
- package/common/cpp/core/BiquadFilterNode.cpp +90 -69
- package/common/cpp/core/BiquadFilterNode.h +53 -57
- package/common/cpp/core/GainNode.cpp +12 -12
- package/common/cpp/core/GainNode.h +5 -3
- package/common/cpp/core/OscillatorNode.cpp +38 -29
- package/common/cpp/core/OscillatorNode.h +29 -69
- package/common/cpp/core/ParamChange.h +6 -6
- package/common/cpp/core/PeriodicWave.cpp +362 -0
- package/common/cpp/core/PeriodicWave.h +119 -0
- package/common/cpp/core/StereoPannerNode.cpp +28 -30
- package/common/cpp/core/StereoPannerNode.h +6 -6
- package/common/cpp/types/BiquadFilterType.h +19 -0
- package/common/cpp/types/ChannelCountMode.h +10 -0
- package/common/cpp/types/ChannelInterpretation.h +10 -0
- package/common/cpp/types/ContextState.h +10 -0
- package/common/cpp/types/OscillatorType.h +11 -0
- package/common/cpp/utils/FFTFrame.h +63 -0
- package/common/cpp/utils/Locker.h +47 -0
- package/common/cpp/utils/VectorMath.cpp +72 -3
- package/common/cpp/utils/VectorMath.h +7 -1
- package/common/cpp/utils/android/FFTFrame.cpp +22 -0
- package/common/cpp/utils/ios/FFTFrame.cpp +24 -0
- package/common/cpp/wrappers/AudioBufferSourceNodeWrapper.cpp +10 -0
- package/common/cpp/wrappers/AudioBufferSourceNodeWrapper.h +3 -2
- package/common/cpp/wrappers/AudioBufferWrapper.h +5 -5
- package/common/cpp/wrappers/AudioContextWrapper.cpp +7 -60
- package/common/cpp/wrappers/AudioContextWrapper.h +5 -26
- package/common/cpp/wrappers/AudioNodeWrapper.h +5 -5
- package/common/cpp/wrappers/AudioParamWrapper.h +4 -4
- package/common/cpp/wrappers/BaseAudioContextWrapper.cpp +76 -0
- package/common/cpp/wrappers/BaseAudioContextWrapper.h +49 -0
- package/common/cpp/wrappers/BiquadFilterNodeWrapper.cpp +9 -0
- package/common/cpp/wrappers/BiquadFilterNodeWrapper.h +9 -4
- package/common/cpp/wrappers/GainNodeWrapper.h +1 -1
- package/common/cpp/wrappers/OscillatorNodeWrapper.cpp +6 -0
- package/common/cpp/wrappers/OscillatorNodeWrapper.h +5 -2
- package/common/cpp/wrappers/PeriodicWaveWrapper.h +17 -0
- package/common/cpp/wrappers/StereoPannerNodeWrapper.h +1 -1
- package/ios/AudioAPIModule.h +20 -1
- package/ios/AudioAPIModule.mm +3 -3
- package/ios/AudioPlayer/AudioPlayer.h +3 -2
- package/ios/AudioPlayer/AudioPlayer.m +15 -17
- package/ios/AudioPlayer/IOSAudioPlayer.h +8 -4
- package/ios/AudioPlayer/IOSAudioPlayer.mm +30 -7
- package/lib/module/core/AudioBuffer.js +37 -0
- package/lib/module/core/AudioBuffer.js.map +1 -0
- package/lib/module/core/AudioBufferSourceNode.js +28 -0
- package/lib/module/core/AudioBufferSourceNode.js.map +1 -0
- package/lib/module/core/AudioContext.js +10 -0
- package/lib/module/core/AudioContext.js.map +1 -0
- package/lib/module/core/AudioDestinationNode.js +7 -0
- package/lib/module/core/AudioDestinationNode.js.map +1 -0
- package/lib/module/core/AudioNode.js +22 -0
- package/lib/module/core/AudioNode.js.map +1 -0
- package/lib/module/core/AudioParam.js +35 -0
- package/lib/module/core/AudioParam.js.map +1 -0
- package/lib/module/core/AudioScheduledSourceNode.js +28 -0
- package/lib/module/core/AudioScheduledSourceNode.js.map +1 -0
- package/lib/module/core/BaseAudioContext.js +57 -0
- package/lib/module/core/BaseAudioContext.js.map +1 -0
- package/lib/module/core/BiquadFilterNode.js +25 -0
- package/lib/module/core/BiquadFilterNode.js.map +1 -0
- package/lib/module/core/GainNode.js +9 -0
- package/lib/module/core/GainNode.js.map +1 -0
- package/lib/module/core/OscillatorNode.js +24 -0
- package/lib/module/core/OscillatorNode.js.map +1 -0
- package/lib/module/core/PeriodicWave.js +8 -0
- package/lib/module/core/PeriodicWave.js.map +1 -0
- package/lib/module/core/StereoPannerNode.js +9 -0
- package/lib/module/core/StereoPannerNode.js.map +1 -0
- package/lib/module/core/types.js.map +1 -0
- package/lib/module/errors/IndexSizeError.js +8 -0
- package/lib/module/errors/IndexSizeError.js.map +1 -0
- package/lib/module/errors/InvalidAccessError.js +8 -0
- package/lib/module/errors/InvalidAccessError.js.map +1 -0
- package/lib/module/errors/InvalidStateError.js +8 -0
- package/lib/module/errors/InvalidStateError.js.map +1 -0
- package/lib/module/errors/RangeError.js +8 -0
- package/lib/module/errors/RangeError.js.map +1 -0
- package/lib/module/errors/index.js +5 -0
- package/lib/module/errors/index.js.map +1 -0
- package/lib/module/index.js +13 -34
- package/lib/module/index.js.map +1 -1
- package/lib/module/interfaces.js +2 -0
- package/lib/module/interfaces.js.map +1 -0
- package/lib/typescript/core/AudioBuffer.d.ts +12 -0
- package/lib/typescript/core/AudioBuffer.d.ts.map +1 -0
- package/lib/typescript/core/AudioBufferSourceNode.d.ts +12 -0
- package/lib/typescript/core/AudioBufferSourceNode.d.ts.map +1 -0
- package/lib/typescript/core/AudioContext.d.ts +6 -0
- package/lib/typescript/core/AudioContext.d.ts.map +1 -0
- package/lib/typescript/core/AudioDestinationNode.d.ts +7 -0
- package/lib/typescript/core/AudioDestinationNode.d.ts.map +1 -0
- package/lib/typescript/core/AudioNode.d.ts +16 -0
- package/lib/typescript/core/AudioNode.d.ts.map +1 -0
- package/lib/typescript/core/AudioParam.d.ts +14 -0
- package/lib/typescript/core/AudioParam.d.ts.map +1 -0
- package/lib/typescript/core/AudioScheduledSourceNode.d.ts +10 -0
- package/lib/typescript/core/AudioScheduledSourceNode.d.ts.map +1 -0
- package/lib/typescript/core/BaseAudioContext.d.ts +26 -0
- package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -0
- package/lib/typescript/core/BiquadFilterNode.d.ts +16 -0
- package/lib/typescript/core/BiquadFilterNode.d.ts.map +1 -0
- package/lib/typescript/core/GainNode.d.ts +9 -0
- package/lib/typescript/core/GainNode.d.ts.map +1 -0
- package/lib/typescript/core/OscillatorNode.d.ts +15 -0
- package/lib/typescript/core/OscillatorNode.d.ts.map +1 -0
- package/lib/typescript/core/PeriodicWave.d.ts +5 -0
- package/lib/typescript/core/PeriodicWave.d.ts.map +1 -0
- package/lib/typescript/core/StereoPannerNode.d.ts +9 -0
- package/lib/typescript/core/StereoPannerNode.d.ts.map +1 -0
- package/lib/typescript/core/types.d.ts +9 -0
- package/lib/typescript/core/types.d.ts.map +1 -0
- package/lib/typescript/errors/IndexSizeError.d.ts +5 -0
- package/lib/typescript/errors/IndexSizeError.d.ts.map +1 -0
- package/lib/typescript/errors/InvalidAccessError.d.ts +5 -0
- package/lib/typescript/errors/InvalidAccessError.d.ts.map +1 -0
- package/lib/typescript/errors/InvalidStateError.d.ts +5 -0
- package/lib/typescript/errors/InvalidStateError.d.ts.map +1 -0
- package/lib/typescript/errors/RangeError.d.ts +5 -0
- package/lib/typescript/errors/RangeError.d.ts.map +1 -0
- package/lib/typescript/errors/index.d.ts +5 -0
- package/lib/typescript/errors/index.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +13 -17
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/interfaces.d.ts +78 -0
- package/lib/typescript/interfaces.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/core/AudioBuffer.ts +68 -0
- package/src/core/AudioBufferSourceNode.ts +35 -0
- package/src/core/AudioContext.ts +12 -0
- package/src/core/AudioDestinationNode.ts +9 -0
- package/src/core/AudioNode.ts +38 -0
- package/src/core/AudioParam.ts +55 -0
- package/src/core/AudioScheduledSourceNode.ts +43 -0
- package/src/core/BaseAudioContext.ts +97 -0
- package/src/core/BiquadFilterNode.ts +49 -0
- package/src/core/GainNode.ts +13 -0
- package/src/core/OscillatorNode.ts +37 -0
- package/src/core/PeriodicWave.ts +10 -0
- package/src/core/StereoPannerNode.ts +13 -0
- package/src/core/types.ts +26 -0
- package/src/errors/IndexSizeError.ts +8 -0
- package/src/errors/InvalidAccessError.ts +8 -0
- package/src/errors/InvalidStateError.ts +8 -0
- package/src/errors/RangeError.ts +8 -0
- package/src/errors/index.ts +4 -0
- package/src/index.ts +19 -73
- package/src/interfaces.ts +120 -0
- package/src/modules/global.d.ts +3 -3
- package/lib/module/types.js.map +0 -1
- package/lib/typescript/types.d.ts +0 -76
- package/lib/typescript/types.d.ts.map +0 -1
- package/src/types.ts +0 -108
- /package/lib/module/{types.js → core/types.js} +0 -0
|
@@ -1,11 +1,18 @@
|
|
|
1
|
+
#include <memory>
|
|
2
|
+
|
|
3
|
+
#include "AudioBus.h"
|
|
1
4
|
#include "AudioNode.h"
|
|
2
|
-
#include "
|
|
5
|
+
#include "BaseAudioContext.h"
|
|
6
|
+
#include "AudioNodeManager.h"
|
|
3
7
|
|
|
4
8
|
namespace audioapi {
|
|
5
9
|
|
|
6
|
-
AudioNode::AudioNode(
|
|
10
|
+
AudioNode::AudioNode(BaseAudioContext *context) : context_(context) {
|
|
11
|
+
audioBus_ = std::make_shared<AudioBus>(context->getSampleRate(), context->getBufferSizeInFrames(), channelCount_);
|
|
12
|
+
}
|
|
7
13
|
|
|
8
14
|
AudioNode::~AudioNode() {
|
|
15
|
+
isInitialized_ = false;
|
|
9
16
|
cleanup();
|
|
10
17
|
}
|
|
11
18
|
|
|
@@ -30,39 +37,186 @@ std::string AudioNode::getChannelInterpretation() const {
|
|
|
30
37
|
}
|
|
31
38
|
|
|
32
39
|
void AudioNode::connect(const std::shared_ptr<AudioNode> &node) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
context_->getNodeManager()->addPendingConnection(shared_from_this(), node, AudioNodeManager::ConnectionType::CONNECT);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
void AudioNode::connectNode(const std::shared_ptr<AudioNode> &node) {
|
|
44
|
+
outputNodes_.push_back(node);
|
|
45
|
+
node->onInputConnected(this);
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
void AudioNode::disconnect(const std::shared_ptr<AudioNode> &node) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
context_->getNodeManager()->addPendingConnection(shared_from_this(), node, AudioNodeManager::ConnectionType::DISCONNECT);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
void AudioNode::disconnectNode(const std::shared_ptr<AudioNode> &node) {
|
|
53
|
+
node->onInputDisconnected(this);
|
|
54
|
+
|
|
55
|
+
auto position = std::find(outputNodes_.begin(), outputNodes_.end(), node);
|
|
56
|
+
|
|
57
|
+
if (position != outputNodes_.end()) {
|
|
58
|
+
outputNodes_.erase(position);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
bool AudioNode::isEnabled() const {
|
|
63
|
+
return isEnabled_;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
void AudioNode::enable() {
|
|
67
|
+
isEnabled_ = true;
|
|
68
|
+
|
|
69
|
+
for (auto it = outputNodes_.begin(); it != outputNodes_.end(); ++it) {
|
|
70
|
+
it->get()->onInputEnabled();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
void AudioNode::disable() {
|
|
75
|
+
isEnabled_ = false;
|
|
76
|
+
|
|
77
|
+
for (auto it = outputNodes_.begin(); it != outputNodes_.end(); ++it) {
|
|
78
|
+
it->get()->onInputDisabled();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
std::string AudioNode::toString(ChannelCountMode mode) {
|
|
83
|
+
switch (mode) {
|
|
84
|
+
case ChannelCountMode::MAX:
|
|
85
|
+
return "max";
|
|
86
|
+
case ChannelCountMode::CLAMPED_MAX:
|
|
87
|
+
return "clamped-max";
|
|
88
|
+
case ChannelCountMode::EXPLICIT:
|
|
89
|
+
return "explicit";
|
|
90
|
+
default:
|
|
91
|
+
throw std::invalid_argument("Unknown channel count mode");
|
|
49
92
|
}
|
|
50
93
|
}
|
|
51
94
|
|
|
95
|
+
std::string AudioNode::toString(ChannelInterpretation interpretation) {
|
|
96
|
+
switch (interpretation) {
|
|
97
|
+
case ChannelInterpretation::SPEAKERS:
|
|
98
|
+
return "speakers";
|
|
99
|
+
case ChannelInterpretation::DISCRETE:
|
|
100
|
+
return "discrete";
|
|
101
|
+
default:
|
|
102
|
+
throw std::invalid_argument("Unknown channel interpretation");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
AudioBus* AudioNode::processAudio(AudioBus* outputBus, int framesToProcess) {
|
|
107
|
+
if (!isInitialized_) {
|
|
108
|
+
return outputBus;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
std::size_t currentSampleFrame = context_->getCurrentSampleFrame();
|
|
112
|
+
|
|
113
|
+
// check if the node has already been processed for this rendering quantum
|
|
114
|
+
bool isAlreadyProcessed = currentSampleFrame == lastRenderedFrame_;
|
|
115
|
+
|
|
116
|
+
// Node can't use output bus if:
|
|
117
|
+
// - outputBus is not provided, which means that next node is doing a multi-node summing.
|
|
118
|
+
// - it has more than one input, which means that it has to sum all inputs using internal bus.
|
|
119
|
+
// - it has more than one output, so each output node can get the processed data without re-calculating the node.
|
|
120
|
+
bool canUseOutputBus = outputBus != 0 && inputNodes_.size() < 2 && outputNodes_.size() < 2;
|
|
121
|
+
|
|
122
|
+
if (isAlreadyProcessed) {
|
|
123
|
+
// If it was already processed in the rendering quantum, return it.
|
|
124
|
+
return audioBus_.get();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Update the last rendered frame before processing node and its inputs.
|
|
128
|
+
lastRenderedFrame_ = currentSampleFrame;
|
|
129
|
+
|
|
130
|
+
AudioBus* processingBus = canUseOutputBus ? outputBus : audioBus_.get();
|
|
131
|
+
|
|
132
|
+
if (!canUseOutputBus) {
|
|
133
|
+
// Clear the bus before summing all connected nodes.
|
|
134
|
+
processingBus->zero();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (inputNodes_.empty()) {
|
|
138
|
+
// If there are no connected inputs, process the node just to advance the audio params.
|
|
139
|
+
// The node will output silence anyway.
|
|
140
|
+
processNode(processingBus, framesToProcess);
|
|
141
|
+
return processingBus;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
for (auto it = inputNodes_.begin(); it != inputNodes_.end(); ++it) {
|
|
145
|
+
if (!(*it)->isEnabled()) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Process first connected node, it can be directly connected to the processingBus,
|
|
150
|
+
// resulting in one less summing operation.
|
|
151
|
+
if (it == inputNodes_.begin()) {
|
|
152
|
+
AudioBus* inputBus = (*it)->processAudio(processingBus, framesToProcess);
|
|
153
|
+
|
|
154
|
+
if (inputBus != processingBus) {
|
|
155
|
+
processingBus->sum(inputBus);
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
// Enforce the summing to be done using the internal bus.
|
|
159
|
+
AudioBus* inputBus = (*it)->processAudio(0, framesToProcess);
|
|
160
|
+
if (inputBus) {
|
|
161
|
+
processingBus->sum(inputBus);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Finally, process the node itself.
|
|
167
|
+
processNode(processingBus, framesToProcess);
|
|
168
|
+
|
|
169
|
+
return processingBus;
|
|
170
|
+
}
|
|
171
|
+
|
|
52
172
|
void AudioNode::cleanup() {
|
|
53
173
|
outputNodes_.clear();
|
|
54
174
|
inputNodes_.clear();
|
|
55
175
|
}
|
|
56
176
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
177
|
+
void AudioNode::onInputEnabled() {
|
|
178
|
+
numberOfEnabledInputNodes_ += 1;
|
|
179
|
+
|
|
180
|
+
if (!isEnabled()) {
|
|
181
|
+
enable();
|
|
63
182
|
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
void AudioNode::onInputDisabled() {
|
|
186
|
+
numberOfEnabledInputNodes_ -= 1;
|
|
64
187
|
|
|
65
|
-
|
|
188
|
+
if (isEnabled() && numberOfEnabledInputNodes_ == 0) {
|
|
189
|
+
disable();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
void AudioNode::onInputConnected(AudioNode *node) {
|
|
194
|
+
inputNodes_.push_back(node);
|
|
195
|
+
|
|
196
|
+
if (node->isEnabled()) {
|
|
197
|
+
onInputEnabled();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
void AudioNode::onInputDisconnected(AudioNode *node) {
|
|
202
|
+
auto position = std::find(inputNodes_.begin(), inputNodes_.end(), node);
|
|
203
|
+
|
|
204
|
+
if (position != inputNodes_.end()) {
|
|
205
|
+
inputNodes_.erase(position);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
if (inputNodes_.size() > 0) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (isEnabled()) {
|
|
214
|
+
node->onInputDisabled();
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
for (auto outputNode : outputNodes_) {
|
|
218
|
+
disconnectNode(outputNode);
|
|
219
|
+
}
|
|
66
220
|
}
|
|
67
221
|
|
|
68
222
|
} // namespace audioapi
|
|
@@ -3,17 +3,19 @@
|
|
|
3
3
|
#include <memory>
|
|
4
4
|
#include <string>
|
|
5
5
|
#include <vector>
|
|
6
|
-
#include "Constants.h"
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
#include "Constants.h"
|
|
8
|
+
#include "ChannelCountMode.h"
|
|
9
|
+
#include "ChannelInterpretation.h"
|
|
9
10
|
|
|
10
11
|
namespace audioapi {
|
|
11
12
|
|
|
12
|
-
class
|
|
13
|
+
class AudioBus;
|
|
14
|
+
class BaseAudioContext;
|
|
13
15
|
|
|
14
16
|
class AudioNode : public std::enable_shared_from_this<AudioNode> {
|
|
15
17
|
public:
|
|
16
|
-
explicit AudioNode(
|
|
18
|
+
explicit AudioNode(BaseAudioContext *context);
|
|
17
19
|
virtual ~AudioNode();
|
|
18
20
|
int getNumberOfInputs() const;
|
|
19
21
|
int getNumberOfOutputs() const;
|
|
@@ -23,52 +25,50 @@ class AudioNode : public std::enable_shared_from_this<AudioNode> {
|
|
|
23
25
|
void connect(const std::shared_ptr<AudioNode> &node);
|
|
24
26
|
void disconnect(const std::shared_ptr<AudioNode> &node);
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
bool isEnabled() const;
|
|
29
|
+
void enable();
|
|
30
|
+
void disable();
|
|
28
31
|
|
|
29
32
|
protected:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return "clamped-max";
|
|
38
|
-
case ChannelCountMode::EXPLICIT:
|
|
39
|
-
return "explicit";
|
|
40
|
-
default:
|
|
41
|
-
throw std::invalid_argument("Unknown channel count mode");
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
enum class ChannelInterpretation { SPEAKERS, DISCRETE };
|
|
46
|
-
|
|
47
|
-
static std::string toString(ChannelInterpretation interpretation) {
|
|
48
|
-
switch (interpretation) {
|
|
49
|
-
case ChannelInterpretation::SPEAKERS:
|
|
50
|
-
return "speakers";
|
|
51
|
-
case ChannelInterpretation::DISCRETE:
|
|
52
|
-
return "discrete";
|
|
53
|
-
default:
|
|
54
|
-
throw std::invalid_argument("Unknown channel interpretation");
|
|
55
|
-
}
|
|
56
|
-
}
|
|
33
|
+
friend class AudioNodeManager;
|
|
34
|
+
friend class AudioDestinationNode;
|
|
35
|
+
|
|
36
|
+
BaseAudioContext *context_;
|
|
37
|
+
std::shared_ptr<AudioBus> audioBus_;
|
|
38
|
+
|
|
39
|
+
int channelCount_ = CHANNEL_COUNT;
|
|
57
40
|
|
|
58
|
-
protected:
|
|
59
|
-
AudioContext *context_;
|
|
60
41
|
int numberOfInputs_ = 1;
|
|
61
42
|
int numberOfOutputs_ = 1;
|
|
62
|
-
int
|
|
43
|
+
int numberOfEnabledInputNodes_ = 0;
|
|
44
|
+
|
|
45
|
+
bool isInitialized_ = false;
|
|
46
|
+
bool isEnabled_ = true;
|
|
47
|
+
|
|
48
|
+
std::size_t lastRenderedFrame_ { SIZE_MAX };
|
|
49
|
+
|
|
63
50
|
ChannelCountMode channelCountMode_ = ChannelCountMode::MAX;
|
|
64
51
|
ChannelInterpretation channelInterpretation_ =
|
|
65
52
|
ChannelInterpretation::SPEAKERS;
|
|
66
53
|
|
|
67
|
-
std::vector<
|
|
54
|
+
std::vector<AudioNode*> inputNodes_ = {};
|
|
68
55
|
std::vector<std::shared_ptr<AudioNode>> outputNodes_ = {};
|
|
69
56
|
|
|
70
57
|
private:
|
|
58
|
+
static std::string toString(ChannelCountMode mode);
|
|
59
|
+
static std::string toString(ChannelInterpretation interpretation);
|
|
60
|
+
|
|
71
61
|
void cleanup();
|
|
62
|
+
AudioBus* processAudio(AudioBus* outputBus, int framesToProcess);
|
|
63
|
+
virtual void processNode(AudioBus* processingBus, int framesToProcess) = 0;
|
|
64
|
+
|
|
65
|
+
void connectNode(const std::shared_ptr<AudioNode> &node);
|
|
66
|
+
void disconnectNode(const std::shared_ptr<AudioNode> &node);
|
|
67
|
+
|
|
68
|
+
void onInputEnabled();
|
|
69
|
+
void onInputDisabled();
|
|
70
|
+
void onInputConnected(AudioNode *node);
|
|
71
|
+
void onInputDisconnected(AudioNode *node);
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
} // namespace audioapi
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
|
|
2
|
+
#include "Locker.h"
|
|
3
|
+
#include "AudioNode.h"
|
|
4
|
+
#include "AudioNodeManager.h"
|
|
5
|
+
|
|
6
|
+
namespace audioapi {
|
|
7
|
+
|
|
8
|
+
AudioNodeManager::AudioNodeManager() {}
|
|
9
|
+
|
|
10
|
+
AudioNodeManager::~AudioNodeManager() {
|
|
11
|
+
audioNodesToConnect_.clear();
|
|
12
|
+
sourceNodes_.clear();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
void AudioNodeManager::addPendingConnection(const std::shared_ptr<AudioNode> &from, const std::shared_ptr<AudioNode> &to, ConnectionType type) {
|
|
16
|
+
Locker lock(getGraphLock());
|
|
17
|
+
|
|
18
|
+
audioNodesToConnect_.push_back(std::make_tuple(from, to, type));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
void AudioNodeManager::addSourceNode(const std::shared_ptr<AudioNode> &node) {
|
|
22
|
+
Locker lock(getGraphLock());
|
|
23
|
+
|
|
24
|
+
sourceNodes_.push_back(node);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
void AudioNodeManager::preProcessGraph() {
|
|
28
|
+
if (!Locker::tryLock(getGraphLock())) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
settlePendingConnections();
|
|
33
|
+
removeFinishedSourceNodes();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
std::mutex& AudioNodeManager::getGraphLock() {
|
|
37
|
+
return graphLock_;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
void AudioNodeManager::settlePendingConnections() {
|
|
41
|
+
for (auto& connection : audioNodesToConnect_) {
|
|
42
|
+
std::shared_ptr<AudioNode> from = std::get<0>(connection);
|
|
43
|
+
std::shared_ptr<AudioNode> to = std::get<1>(connection);
|
|
44
|
+
ConnectionType type = std::get<2>(connection);
|
|
45
|
+
|
|
46
|
+
if (type == ConnectionType::CONNECT) {
|
|
47
|
+
from->connectNode(to);
|
|
48
|
+
} else {
|
|
49
|
+
from->disconnectNode(to);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
audioNodesToConnect_.clear();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
void AudioNodeManager::removeFinishedSourceNodes() {
|
|
57
|
+
for (auto it = sourceNodes_.begin(); it != sourceNodes_.end();) {
|
|
58
|
+
auto currentNode = it->get();
|
|
59
|
+
// Release the source node if use count is equal to 1 (this vector)
|
|
60
|
+
if (!currentNode->isEnabled() && it->use_count() == 1) {
|
|
61
|
+
for (auto& outputNode : currentNode->outputNodes_) {
|
|
62
|
+
currentNode->disconnectNode(outputNode);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
it = sourceNodes_.erase(it);
|
|
66
|
+
} else {
|
|
67
|
+
++it;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
} // namespace audioapi
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <mutex>
|
|
4
|
+
#include <tuple>
|
|
5
|
+
#include <memory>
|
|
6
|
+
#include <vector>
|
|
7
|
+
|
|
8
|
+
namespace audioapi {
|
|
9
|
+
|
|
10
|
+
class AudioNode;
|
|
11
|
+
|
|
12
|
+
class AudioNodeManager {
|
|
13
|
+
public:
|
|
14
|
+
enum class ConnectionType { CONNECT, DISCONNECT };
|
|
15
|
+
AudioNodeManager();
|
|
16
|
+
~AudioNodeManager();
|
|
17
|
+
|
|
18
|
+
void preProcessGraph();
|
|
19
|
+
void addPendingConnection(const std::shared_ptr<AudioNode> &from, const std::shared_ptr<AudioNode> &to, ConnectionType type);
|
|
20
|
+
|
|
21
|
+
void addSourceNode(const std::shared_ptr<AudioNode> &node);
|
|
22
|
+
|
|
23
|
+
std::mutex& getGraphLock();
|
|
24
|
+
|
|
25
|
+
private:
|
|
26
|
+
std::mutex graphLock_;
|
|
27
|
+
|
|
28
|
+
std::vector<std::shared_ptr<AudioNode>> sourceNodes_;
|
|
29
|
+
std::vector<std::tuple<std::shared_ptr<AudioNode>, std::shared_ptr<AudioNode>, ConnectionType>> audioNodesToConnect_;
|
|
30
|
+
|
|
31
|
+
void settlePendingConnections();
|
|
32
|
+
void removeFinishedSourceNodes();
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
} // namespace audioapi
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#include "AudioParam.h"
|
|
2
|
-
#include "
|
|
2
|
+
#include "BaseAudioContext.h"
|
|
3
3
|
|
|
4
4
|
namespace audioapi {
|
|
5
5
|
|
|
6
6
|
AudioParam::AudioParam(
|
|
7
|
-
|
|
7
|
+
BaseAudioContext *context,
|
|
8
8
|
float defaultValue,
|
|
9
9
|
float minValue,
|
|
10
10
|
float maxValue)
|
|
@@ -40,8 +40,7 @@ float AudioParam::getMaxValue() const {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
void AudioParam::setValue(float value) {
|
|
43
|
-
checkValue(value);
|
|
44
|
-
value_ = value;
|
|
43
|
+
value_ = checkValue(value);
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
float AudioParam::getValueAtTime(double time) {
|
|
@@ -66,7 +65,7 @@ float AudioParam::getValueAtTime(double time) {
|
|
|
66
65
|
}
|
|
67
66
|
|
|
68
67
|
void AudioParam::setValueAtTime(float value, double time) {
|
|
69
|
-
checkValue(value);
|
|
68
|
+
value = checkValue(value);
|
|
70
69
|
auto calculateValue = [](double, double, float, float endValue, double) {
|
|
71
70
|
return endValue;
|
|
72
71
|
};
|
|
@@ -76,7 +75,7 @@ void AudioParam::setValueAtTime(float value, double time) {
|
|
|
76
75
|
}
|
|
77
76
|
|
|
78
77
|
void AudioParam::linearRampToValueAtTime(float value, double time) {
|
|
79
|
-
checkValue(value);
|
|
78
|
+
value = checkValue(value);
|
|
80
79
|
auto calculateValue = [](double startTime,
|
|
81
80
|
double endTime,
|
|
82
81
|
float startValue,
|
|
@@ -94,7 +93,7 @@ void AudioParam::linearRampToValueAtTime(float value, double time) {
|
|
|
94
93
|
}
|
|
95
94
|
|
|
96
95
|
void AudioParam::exponentialRampToValueAtTime(float value, double time) {
|
|
97
|
-
checkValue(value);
|
|
96
|
+
value = checkValue(value);
|
|
98
97
|
auto calculateValue = [](double startTime,
|
|
99
98
|
double endTime,
|
|
100
99
|
float startValue,
|
|
@@ -111,10 +110,8 @@ void AudioParam::exponentialRampToValueAtTime(float value, double time) {
|
|
|
111
110
|
changesQueue_.emplace(paramChange);
|
|
112
111
|
}
|
|
113
112
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
throw std::invalid_argument("Value out of range");
|
|
117
|
-
}
|
|
113
|
+
float AudioParam::checkValue(float value) const {
|
|
114
|
+
return std::clamp(value, minValue_, maxValue_);
|
|
118
115
|
}
|
|
119
116
|
|
|
120
117
|
double AudioParam::getStartTime() {
|
|
@@ -8,22 +8,22 @@
|
|
|
8
8
|
|
|
9
9
|
namespace audioapi {
|
|
10
10
|
|
|
11
|
-
class
|
|
11
|
+
class BaseAudioContext;
|
|
12
12
|
|
|
13
13
|
class AudioParam {
|
|
14
14
|
public:
|
|
15
15
|
explicit AudioParam(
|
|
16
|
-
|
|
16
|
+
BaseAudioContext *context,
|
|
17
17
|
float defaultValue,
|
|
18
18
|
float minValue,
|
|
19
19
|
float maxValue);
|
|
20
20
|
|
|
21
|
-
float getValue() const;
|
|
21
|
+
[[nodiscard]] float getValue() const;
|
|
22
22
|
float getValueAtTime(double time);
|
|
23
23
|
void setValue(float value);
|
|
24
|
-
float getDefaultValue() const;
|
|
25
|
-
float getMinValue() const;
|
|
26
|
-
float getMaxValue() const;
|
|
24
|
+
[[nodiscard]] float getDefaultValue() const;
|
|
25
|
+
[[nodiscard]] float getMinValue() const;
|
|
26
|
+
[[nodiscard]] float getMaxValue() const;
|
|
27
27
|
void setValueAtTime(float value, double startTime);
|
|
28
28
|
void linearRampToValueAtTime(float value, double endTime);
|
|
29
29
|
void exponentialRampToValueAtTime(float value, double endTime);
|
|
@@ -33,7 +33,7 @@ class AudioParam {
|
|
|
33
33
|
float defaultValue_;
|
|
34
34
|
float minValue_;
|
|
35
35
|
float maxValue_;
|
|
36
|
-
|
|
36
|
+
BaseAudioContext *context_;
|
|
37
37
|
std::set<ParamChange> changesQueue_;
|
|
38
38
|
|
|
39
39
|
double startTime_;
|
|
@@ -42,7 +42,7 @@ class AudioParam {
|
|
|
42
42
|
float endValue_;
|
|
43
43
|
std::function<float(double, double, float, float, double)> calculateValue_;
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
float checkValue(float value) const;
|
|
46
46
|
double getStartTime();
|
|
47
47
|
float getStartValue();
|
|
48
48
|
};
|
|
@@ -1,14 +1,19 @@
|
|
|
1
|
+
#include "BaseAudioContext.h"
|
|
2
|
+
#include "AudioNodeManager.h"
|
|
1
3
|
#include "AudioScheduledSourceNode.h"
|
|
2
|
-
#include "AudioContext.h"
|
|
3
4
|
|
|
4
5
|
namespace audioapi {
|
|
5
6
|
|
|
6
|
-
AudioScheduledSourceNode::AudioScheduledSourceNode(
|
|
7
|
-
: AudioNode(context),
|
|
7
|
+
AudioScheduledSourceNode::AudioScheduledSourceNode(BaseAudioContext *context)
|
|
8
|
+
: AudioNode(context), playbackState_(PlaybackState::UNSCHEDULED) {
|
|
8
9
|
numberOfInputs_ = 0;
|
|
10
|
+
isInitialized_ = true;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
void AudioScheduledSourceNode::start(double time) {
|
|
14
|
+
context_->getNodeManager()->addSourceNode(shared_from_this());
|
|
15
|
+
|
|
16
|
+
playbackState_ = PlaybackState::SCHEDULED;
|
|
12
17
|
waitAndExecute(time, [this](double time) { startPlayback(); });
|
|
13
18
|
}
|
|
14
19
|
|
|
@@ -16,12 +21,21 @@ void AudioScheduledSourceNode::stop(double time) {
|
|
|
16
21
|
waitAndExecute(time, [this](double time) { stopPlayback(); });
|
|
17
22
|
}
|
|
18
23
|
|
|
24
|
+
bool AudioScheduledSourceNode::isPlaying() {
|
|
25
|
+
return playbackState_ == PlaybackState::PLAYING;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
bool AudioScheduledSourceNode::isFinished() {
|
|
29
|
+
return playbackState_ == PlaybackState::FINISHED;
|
|
30
|
+
}
|
|
31
|
+
|
|
19
32
|
void AudioScheduledSourceNode::startPlayback() {
|
|
20
|
-
|
|
33
|
+
playbackState_ = PlaybackState::PLAYING;
|
|
21
34
|
}
|
|
22
35
|
|
|
23
36
|
void AudioScheduledSourceNode::stopPlayback() {
|
|
24
|
-
|
|
37
|
+
playbackState_ = PlaybackState::FINISHED;
|
|
38
|
+
disable();
|
|
25
39
|
}
|
|
26
40
|
|
|
27
41
|
void AudioScheduledSourceNode::waitAndExecute(
|
|
@@ -13,13 +13,17 @@ namespace audioapi {
|
|
|
13
13
|
|
|
14
14
|
class AudioScheduledSourceNode : public AudioNode {
|
|
15
15
|
public:
|
|
16
|
-
|
|
16
|
+
enum class PlaybackState { UNSCHEDULED, SCHEDULED, PLAYING, FINISHED };
|
|
17
|
+
explicit AudioScheduledSourceNode(BaseAudioContext *context);
|
|
17
18
|
|
|
18
19
|
void start(double time);
|
|
19
20
|
void stop(double time);
|
|
20
21
|
|
|
22
|
+
bool isFinished();
|
|
23
|
+
bool isPlaying();
|
|
24
|
+
|
|
21
25
|
protected:
|
|
22
|
-
std::atomic<
|
|
26
|
+
std::atomic<PlaybackState> playbackState_;
|
|
23
27
|
|
|
24
28
|
private:
|
|
25
29
|
void startPlayback();
|