react-native-audio-api 0.2.0 → 0.3.0-rc1
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/android/src/main/cpp/AudioPlayer/AudioPlayer.cpp +16 -7
- package/android/src/main/cpp/AudioPlayer/AudioPlayer.h +3 -2
- package/common/cpp/AudioAPIInstaller/AudioAPIInstallerHostObject.cpp +5 -3
- package/common/cpp/AudioAPIInstaller/AudioAPIInstallerHostObject.h +5 -1
- package/common/cpp/HostObjects/AudioBufferHostObject.cpp +6 -0
- package/common/cpp/HostObjects/AudioContextHostObject.cpp +2 -2
- package/common/cpp/HostObjects/AudioContextHostObject.h +4 -3
- package/common/cpp/HostObjects/BaseAudioContextHostObject.cpp +28 -2
- package/common/cpp/HostObjects/BaseAudioContextHostObject.h +3 -1
- package/common/cpp/core/AudioArray.cpp +28 -14
- package/common/cpp/core/AudioArray.h +20 -14
- package/common/cpp/core/AudioBuffer.cpp +14 -11
- package/common/cpp/core/AudioBuffer.h +1 -0
- package/common/cpp/core/AudioBufferSourceNode.cpp +29 -19
- package/common/cpp/core/AudioBufferSourceNode.h +1 -1
- package/common/cpp/core/AudioBus.cpp +276 -115
- package/common/cpp/core/AudioBus.h +29 -9
- package/common/cpp/core/AudioContext.cpp +5 -9
- package/common/cpp/core/AudioDestinationNode.cpp +10 -8
- package/common/cpp/core/AudioDestinationNode.h +4 -4
- package/common/cpp/core/AudioNode.cpp +25 -17
- package/common/cpp/core/AudioNode.h +5 -5
- package/common/cpp/core/AudioNodeManager.cpp +10 -7
- package/common/cpp/core/AudioNodeManager.h +11 -4
- package/common/cpp/core/AudioScheduledSourceNode.cpp +2 -2
- package/common/cpp/core/BaseAudioContext.cpp +46 -12
- package/common/cpp/core/BaseAudioContext.h +12 -5
- package/common/cpp/core/BiquadFilterNode.cpp +5 -3
- package/common/cpp/core/GainNode.cpp +1 -1
- package/common/cpp/core/OscillatorNode.cpp +4 -4
- package/common/cpp/core/OscillatorNode.h +2 -2
- package/common/cpp/core/StereoPannerNode.cpp +10 -7
- package/common/cpp/core/StereoPannerNode.h +1 -1
- package/common/cpp/utils/FFTFrame.h +5 -1
- package/common/cpp/utils/JsiPromise.cpp +59 -0
- package/common/cpp/utils/JsiPromise.h +42 -0
- package/common/cpp/utils/Locker.h +8 -6
- package/common/cpp/utils/VectorMath.cpp +71 -55
- package/common/cpp/utils/android/FFTFrame.cpp +12 -11
- package/common/cpp/utils/ios/FFTFrame.cpp +6 -1
- package/common/cpp/wrappers/BaseAudioContextWrapper.cpp +7 -0
- package/common/cpp/wrappers/BaseAudioContextWrapper.h +1 -0
- package/ios/AudioAPIModule.mm +3 -1
- package/ios/AudioDecoder/AudioDecoder.h +17 -0
- package/ios/AudioDecoder/AudioDecoder.m +167 -0
- package/ios/AudioDecoder/IOSAudioDecoder.h +26 -0
- package/ios/AudioDecoder/IOSAudioDecoder.mm +40 -0
- package/ios/AudioPlayer/AudioPlayer.h +1 -1
- package/ios/AudioPlayer/AudioPlayer.m +0 -1
- package/ios/AudioPlayer/IOSAudioPlayer.h +5 -5
- package/ios/AudioPlayer/IOSAudioPlayer.mm +4 -3
- package/lib/module/core/BaseAudioContext.js +5 -0
- package/lib/module/core/BaseAudioContext.js.map +1 -1
- package/lib/module/index.js +235 -17
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.native.js +18 -0
- package/lib/module/index.native.js.map +1 -0
- package/lib/module/utils/resolveAudioSource.js +10 -0
- package/lib/module/utils/resolveAudioSource.js.map +1 -0
- package/lib/typescript/core/BaseAudioContext.d.ts +2 -1
- package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/core/types.d.ts +6 -0
- package/lib/typescript/core/types.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +100 -13
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/index.native.d.ts +14 -0
- package/lib/typescript/index.native.d.ts.map +1 -0
- package/lib/typescript/interfaces.d.ts +1 -0
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/lib/typescript/utils/resolveAudioSource.d.ts +3 -0
- package/lib/typescript/utils/resolveAudioSource.d.ts.map +1 -0
- package/package.json +4 -2
- package/src/core/BaseAudioContext.ts +12 -1
- package/src/core/types.ts +7 -0
- package/src/index.native.ts +25 -0
- package/src/index.ts +413 -19
- package/src/interfaces.ts +1 -0
- package/src/utils/resolveAudioSource.ts +14 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
#include "AudioDestinationNode.h"
|
|
1
2
|
#include "AudioBus.h"
|
|
2
3
|
#include "AudioNode.h"
|
|
3
|
-
#include "VectorMath.h"
|
|
4
4
|
#include "AudioNodeManager.h"
|
|
5
5
|
#include "BaseAudioContext.h"
|
|
6
|
-
#include "
|
|
6
|
+
#include "VectorMath.h"
|
|
7
7
|
|
|
8
8
|
namespace audioapi {
|
|
9
9
|
|
|
@@ -23,15 +23,17 @@ double AudioDestinationNode::getCurrentTime() const {
|
|
|
23
23
|
return static_cast<double>(currentSampleFrame_) / context_->getSampleRate();
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
void AudioDestinationNode::renderAudio(
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (!numFrames) {
|
|
26
|
+
void AudioDestinationNode::renderAudio(
|
|
27
|
+
AudioBus *destinationBus,
|
|
28
|
+
int32_t numFrames) {
|
|
29
|
+
if (!numFrames || !destinationBus || !isInitialized_) {
|
|
31
30
|
return;
|
|
32
31
|
}
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
context_->getNodeManager()->preProcessGraph();
|
|
34
|
+
destinationBus->zero();
|
|
35
|
+
|
|
36
|
+
AudioBus *processedBus = processAudio(destinationBus, numFrames);
|
|
35
37
|
|
|
36
38
|
if (processedBus && processedBus != destinationBus) {
|
|
37
39
|
destinationBus->copy(processedBus);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
-
#include <vector>
|
|
4
|
-
#include <memory>
|
|
5
3
|
#include <algorithm>
|
|
4
|
+
#include <memory>
|
|
5
|
+
#include <vector>
|
|
6
6
|
|
|
7
7
|
#include "AudioNode.h"
|
|
8
8
|
|
|
@@ -15,7 +15,7 @@ class AudioDestinationNode : public AudioNode {
|
|
|
15
15
|
public:
|
|
16
16
|
explicit AudioDestinationNode(BaseAudioContext *context);
|
|
17
17
|
|
|
18
|
-
void renderAudio(AudioBus*
|
|
18
|
+
void renderAudio(AudioBus *audioData, int32_t numFrames);
|
|
19
19
|
|
|
20
20
|
std::size_t getCurrentSampleFrame() const;
|
|
21
21
|
double getCurrentTime() const;
|
|
@@ -23,7 +23,7 @@ class AudioDestinationNode : public AudioNode {
|
|
|
23
23
|
protected:
|
|
24
24
|
// DestinationNode is triggered by AudioContext using renderAudio
|
|
25
25
|
// processNode function is not necessary and is never called.
|
|
26
|
-
void processNode(AudioBus*, int) final
|
|
26
|
+
void processNode(AudioBus *, int) final{};
|
|
27
27
|
|
|
28
28
|
private:
|
|
29
29
|
std::size_t currentSampleFrame_;
|
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
#include "AudioBus.h"
|
|
4
4
|
#include "AudioNode.h"
|
|
5
|
-
#include "BaseAudioContext.h"
|
|
6
5
|
#include "AudioNodeManager.h"
|
|
6
|
+
#include "BaseAudioContext.h"
|
|
7
7
|
|
|
8
8
|
namespace audioapi {
|
|
9
9
|
|
|
10
10
|
AudioNode::AudioNode(BaseAudioContext *context) : context_(context) {
|
|
11
|
-
audioBus_ = std::make_shared<AudioBus>(
|
|
11
|
+
audioBus_ = std::make_shared<AudioBus>(
|
|
12
|
+
context->getSampleRate(),
|
|
13
|
+
context->getBufferSizeInFrames(),
|
|
14
|
+
channelCount_);
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
AudioNode::~AudioNode() {
|
|
@@ -37,7 +40,8 @@ std::string AudioNode::getChannelInterpretation() const {
|
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
void AudioNode::connect(const std::shared_ptr<AudioNode> &node) {
|
|
40
|
-
context_->getNodeManager()->addPendingConnection(
|
|
43
|
+
context_->getNodeManager()->addPendingConnection(
|
|
44
|
+
shared_from_this(), node, AudioNodeManager::ConnectionType::CONNECT);
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
void AudioNode::connectNode(const std::shared_ptr<AudioNode> &node) {
|
|
@@ -46,7 +50,8 @@ void AudioNode::connectNode(const std::shared_ptr<AudioNode> &node) {
|
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
void AudioNode::disconnect(const std::shared_ptr<AudioNode> &node) {
|
|
49
|
-
context_->getNodeManager()->addPendingConnection(
|
|
53
|
+
context_->getNodeManager()->addPendingConnection(
|
|
54
|
+
shared_from_this(), node, AudioNodeManager::ConnectionType::DISCONNECT);
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
void AudioNode::disconnectNode(const std::shared_ptr<AudioNode> &node) {
|
|
@@ -103,7 +108,7 @@ std::string AudioNode::toString(ChannelInterpretation interpretation) {
|
|
|
103
108
|
}
|
|
104
109
|
}
|
|
105
110
|
|
|
106
|
-
AudioBus*
|
|
111
|
+
AudioBus *AudioNode::processAudio(AudioBus *outputBus, int framesToProcess) {
|
|
107
112
|
if (!isInitialized_) {
|
|
108
113
|
return outputBus;
|
|
109
114
|
}
|
|
@@ -114,10 +119,14 @@ AudioBus* AudioNode::processAudio(AudioBus* outputBus, int framesToProcess) {
|
|
|
114
119
|
bool isAlreadyProcessed = currentSampleFrame == lastRenderedFrame_;
|
|
115
120
|
|
|
116
121
|
// Node can't use output bus if:
|
|
117
|
-
// - outputBus is not provided, which means that next node is doing a
|
|
118
|
-
// -
|
|
119
|
-
// - it has more than one
|
|
120
|
-
|
|
122
|
+
// - outputBus is not provided, which means that next node is doing a
|
|
123
|
+
// multi-node summing.
|
|
124
|
+
// - it has more than one input, which means that it has to sum all inputs
|
|
125
|
+
// using internal bus.
|
|
126
|
+
// - it has more than one output, so each output node can get the processed
|
|
127
|
+
// data without re-calculating the node.
|
|
128
|
+
bool canUseOutputBus =
|
|
129
|
+
outputBus != 0 && inputNodes_.size() < 2 && outputNodes_.size() < 2;
|
|
121
130
|
|
|
122
131
|
if (isAlreadyProcessed) {
|
|
123
132
|
// If it was already processed in the rendering quantum, return it.
|
|
@@ -127,7 +136,7 @@ AudioBus* AudioNode::processAudio(AudioBus* outputBus, int framesToProcess) {
|
|
|
127
136
|
// Update the last rendered frame before processing node and its inputs.
|
|
128
137
|
lastRenderedFrame_ = currentSampleFrame;
|
|
129
138
|
|
|
130
|
-
AudioBus*
|
|
139
|
+
AudioBus *processingBus = canUseOutputBus ? outputBus : audioBus_.get();
|
|
131
140
|
|
|
132
141
|
if (!canUseOutputBus) {
|
|
133
142
|
// Clear the bus before summing all connected nodes.
|
|
@@ -135,8 +144,8 @@ AudioBus* AudioNode::processAudio(AudioBus* outputBus, int framesToProcess) {
|
|
|
135
144
|
}
|
|
136
145
|
|
|
137
146
|
if (inputNodes_.empty()) {
|
|
138
|
-
// If there are no connected inputs, process the node just to advance the
|
|
139
|
-
// The node will output silence anyway.
|
|
147
|
+
// If there are no connected inputs, process the node just to advance the
|
|
148
|
+
// audio params. The node will output silence anyway.
|
|
140
149
|
processNode(processingBus, framesToProcess);
|
|
141
150
|
return processingBus;
|
|
142
151
|
}
|
|
@@ -146,17 +155,17 @@ AudioBus* AudioNode::processAudio(AudioBus* outputBus, int framesToProcess) {
|
|
|
146
155
|
continue;
|
|
147
156
|
}
|
|
148
157
|
|
|
149
|
-
// Process first connected node, it can be directly connected to the
|
|
150
|
-
// resulting in one less summing operation.
|
|
158
|
+
// Process first connected node, it can be directly connected to the
|
|
159
|
+
// processingBus, resulting in one less summing operation.
|
|
151
160
|
if (it == inputNodes_.begin()) {
|
|
152
|
-
AudioBus*
|
|
161
|
+
AudioBus *inputBus = (*it)->processAudio(processingBus, framesToProcess);
|
|
153
162
|
|
|
154
163
|
if (inputBus != processingBus) {
|
|
155
164
|
processingBus->sum(inputBus);
|
|
156
165
|
}
|
|
157
166
|
} else {
|
|
158
167
|
// Enforce the summing to be done using the internal bus.
|
|
159
|
-
AudioBus*
|
|
168
|
+
AudioBus *inputBus = (*it)->processAudio(0, framesToProcess);
|
|
160
169
|
if (inputBus) {
|
|
161
170
|
processingBus->sum(inputBus);
|
|
162
171
|
}
|
|
@@ -205,7 +214,6 @@ void AudioNode::onInputDisconnected(AudioNode *node) {
|
|
|
205
214
|
inputNodes_.erase(position);
|
|
206
215
|
}
|
|
207
216
|
|
|
208
|
-
|
|
209
217
|
if (inputNodes_.size() > 0) {
|
|
210
218
|
return;
|
|
211
219
|
}
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
#include <string>
|
|
5
5
|
#include <vector>
|
|
6
6
|
|
|
7
|
-
#include "Constants.h"
|
|
8
7
|
#include "ChannelCountMode.h"
|
|
9
8
|
#include "ChannelInterpretation.h"
|
|
9
|
+
#include "Constants.h"
|
|
10
10
|
|
|
11
11
|
namespace audioapi {
|
|
12
12
|
|
|
@@ -45,13 +45,13 @@ class AudioNode : public std::enable_shared_from_this<AudioNode> {
|
|
|
45
45
|
bool isInitialized_ = false;
|
|
46
46
|
bool isEnabled_ = true;
|
|
47
47
|
|
|
48
|
-
std::size_t lastRenderedFrame_
|
|
48
|
+
std::size_t lastRenderedFrame_{SIZE_MAX};
|
|
49
49
|
|
|
50
50
|
ChannelCountMode channelCountMode_ = ChannelCountMode::MAX;
|
|
51
51
|
ChannelInterpretation channelInterpretation_ =
|
|
52
52
|
ChannelInterpretation::SPEAKERS;
|
|
53
53
|
|
|
54
|
-
std::vector<AudioNode*> inputNodes_ = {};
|
|
54
|
+
std::vector<AudioNode *> inputNodes_ = {};
|
|
55
55
|
std::vector<std::shared_ptr<AudioNode>> outputNodes_ = {};
|
|
56
56
|
|
|
57
57
|
private:
|
|
@@ -59,8 +59,8 @@ class AudioNode : public std::enable_shared_from_this<AudioNode> {
|
|
|
59
59
|
static std::string toString(ChannelInterpretation interpretation);
|
|
60
60
|
|
|
61
61
|
void cleanup();
|
|
62
|
-
AudioBus*
|
|
63
|
-
virtual void processNode(AudioBus*
|
|
62
|
+
AudioBus *processAudio(AudioBus *outputBus, int framesToProcess);
|
|
63
|
+
virtual void processNode(AudioBus *processingBus, int framesToProcess) = 0;
|
|
64
64
|
|
|
65
65
|
void connectNode(const std::shared_ptr<AudioNode> &node);
|
|
66
66
|
void disconnectNode(const std::shared_ptr<AudioNode> &node);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
|
-
#include "Locker.h"
|
|
3
|
-
#include "AudioNode.h"
|
|
4
2
|
#include "AudioNodeManager.h"
|
|
3
|
+
#include "AudioNode.h"
|
|
4
|
+
#include "Locker.h"
|
|
5
5
|
|
|
6
6
|
namespace audioapi {
|
|
7
7
|
|
|
@@ -12,7 +12,10 @@ AudioNodeManager::~AudioNodeManager() {
|
|
|
12
12
|
sourceNodes_.clear();
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
void AudioNodeManager::addPendingConnection(
|
|
15
|
+
void AudioNodeManager::addPendingConnection(
|
|
16
|
+
const std::shared_ptr<AudioNode> &from,
|
|
17
|
+
const std::shared_ptr<AudioNode> &to,
|
|
18
|
+
ConnectionType type) {
|
|
16
19
|
Locker lock(getGraphLock());
|
|
17
20
|
|
|
18
21
|
audioNodesToConnect_.push_back(std::make_tuple(from, to, type));
|
|
@@ -25,7 +28,7 @@ void AudioNodeManager::addSourceNode(const std::shared_ptr<AudioNode> &node) {
|
|
|
25
28
|
}
|
|
26
29
|
|
|
27
30
|
void AudioNodeManager::preProcessGraph() {
|
|
28
|
-
|
|
31
|
+
if (!Locker::tryLock(getGraphLock())) {
|
|
29
32
|
return;
|
|
30
33
|
}
|
|
31
34
|
|
|
@@ -33,12 +36,12 @@ void AudioNodeManager::preProcessGraph() {
|
|
|
33
36
|
removeFinishedSourceNodes();
|
|
34
37
|
}
|
|
35
38
|
|
|
36
|
-
std::mutex&
|
|
39
|
+
std::mutex &AudioNodeManager::getGraphLock() {
|
|
37
40
|
return graphLock_;
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
void AudioNodeManager::settlePendingConnections() {
|
|
41
|
-
for (auto&
|
|
44
|
+
for (auto &connection : audioNodesToConnect_) {
|
|
42
45
|
std::shared_ptr<AudioNode> from = std::get<0>(connection);
|
|
43
46
|
std::shared_ptr<AudioNode> to = std::get<1>(connection);
|
|
44
47
|
ConnectionType type = std::get<2>(connection);
|
|
@@ -58,7 +61,7 @@ void AudioNodeManager::removeFinishedSourceNodes() {
|
|
|
58
61
|
auto currentNode = it->get();
|
|
59
62
|
// Release the source node if use count is equal to 1 (this vector)
|
|
60
63
|
if (!currentNode->isEnabled() && it->use_count() == 1) {
|
|
61
|
-
for (auto&
|
|
64
|
+
for (auto &outputNode : currentNode->outputNodes_) {
|
|
62
65
|
currentNode->disconnectNode(outputNode);
|
|
63
66
|
}
|
|
64
67
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
+
#include <memory>
|
|
3
4
|
#include <mutex>
|
|
4
5
|
#include <tuple>
|
|
5
|
-
#include <memory>
|
|
6
6
|
#include <vector>
|
|
7
7
|
|
|
8
8
|
namespace audioapi {
|
|
@@ -16,17 +16,24 @@ class AudioNodeManager {
|
|
|
16
16
|
~AudioNodeManager();
|
|
17
17
|
|
|
18
18
|
void preProcessGraph();
|
|
19
|
-
void addPendingConnection(
|
|
19
|
+
void addPendingConnection(
|
|
20
|
+
const std::shared_ptr<AudioNode> &from,
|
|
21
|
+
const std::shared_ptr<AudioNode> &to,
|
|
22
|
+
ConnectionType type);
|
|
20
23
|
|
|
21
24
|
void addSourceNode(const std::shared_ptr<AudioNode> &node);
|
|
22
25
|
|
|
23
|
-
std::mutex&
|
|
26
|
+
std::mutex &getGraphLock();
|
|
24
27
|
|
|
25
28
|
private:
|
|
26
29
|
std::mutex graphLock_;
|
|
27
30
|
|
|
28
31
|
std::vector<std::shared_ptr<AudioNode>> sourceNodes_;
|
|
29
|
-
std::vector<std::tuple<
|
|
32
|
+
std::vector<std::tuple<
|
|
33
|
+
std::shared_ptr<AudioNode>,
|
|
34
|
+
std::shared_ptr<AudioNode>,
|
|
35
|
+
ConnectionType>>
|
|
36
|
+
audioNodesToConnect_;
|
|
30
37
|
|
|
31
38
|
void settlePendingConnections();
|
|
32
39
|
void removeFinishedSourceNodes();
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
#ifdef ANDROID
|
|
2
2
|
#include "AudioPlayer.h"
|
|
3
3
|
#else
|
|
4
|
+
#include "IOSAudioDecoder.h"
|
|
4
5
|
#include "IOSAudioPlayer.h"
|
|
5
6
|
#endif
|
|
6
7
|
|
|
7
8
|
#include "BaseAudioContext.h"
|
|
8
9
|
|
|
9
|
-
#include "GainNode.h"
|
|
10
|
-
#include "AudioBus.h"
|
|
11
10
|
#include "AudioArray.h"
|
|
12
11
|
#include "AudioBuffer.h"
|
|
12
|
+
#include "AudioBufferSourceNode.h"
|
|
13
|
+
#include "AudioBus.h"
|
|
14
|
+
#include "AudioDestinationNode.h"
|
|
15
|
+
#include "AudioNodeManager.h"
|
|
16
|
+
#include "BiquadFilterNode.h"
|
|
13
17
|
#include "ContextState.h"
|
|
18
|
+
#include "GainNode.h"
|
|
14
19
|
#include "OscillatorNode.h"
|
|
15
20
|
#include "StereoPannerNode.h"
|
|
16
|
-
#include "BiquadFilterNode.h"
|
|
17
|
-
#include "AudioNodeManager.h"
|
|
18
|
-
#include "AudioDestinationNode.h"
|
|
19
|
-
#include "AudioBufferSourceNode.h"
|
|
20
21
|
|
|
21
22
|
namespace audioapi {
|
|
22
23
|
|
|
@@ -25,16 +26,26 @@ BaseAudioContext::BaseAudioContext() {
|
|
|
25
26
|
audioPlayer_ = std::make_shared<AudioPlayer>(this->renderAudio());
|
|
26
27
|
#else
|
|
27
28
|
audioPlayer_ = std::make_shared<IOSAudioPlayer>(this->renderAudio());
|
|
29
|
+
audioDecoder_ =
|
|
30
|
+
std::make_shared<IOSAudioDecoder>(audioPlayer_->getSampleRate());
|
|
28
31
|
#endif
|
|
29
32
|
|
|
30
33
|
sampleRate_ = audioPlayer_->getSampleRate();
|
|
31
34
|
bufferSizeInFrames_ = audioPlayer_->getBufferSizeInFrames();
|
|
32
35
|
|
|
33
|
-
audioPlayer_->start();
|
|
34
36
|
nodeManager_ = std::make_shared<AudioNodeManager>();
|
|
35
37
|
destination_ = std::make_shared<AudioDestinationNode>(this);
|
|
36
38
|
}
|
|
37
39
|
|
|
40
|
+
BaseAudioContext::~BaseAudioContext() {
|
|
41
|
+
if (isRunning()) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
state_ = ContextState::CLOSED;
|
|
46
|
+
audioPlayer_->stop();
|
|
47
|
+
}
|
|
48
|
+
|
|
38
49
|
std::string BaseAudioContext::getState() {
|
|
39
50
|
return BaseAudioContext::toString(state_);
|
|
40
51
|
}
|
|
@@ -95,20 +106,41 @@ std::shared_ptr<PeriodicWave> BaseAudioContext::createPeriodicWave(
|
|
|
95
106
|
sampleRate_, real, imag, length, disableNormalization);
|
|
96
107
|
}
|
|
97
108
|
|
|
109
|
+
#ifdef ANDROID
|
|
110
|
+
std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioDataSource(
|
|
111
|
+
const std::string &source) {
|
|
112
|
+
return {nullptr};
|
|
113
|
+
}
|
|
114
|
+
#else
|
|
115
|
+
std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioDataSource(
|
|
116
|
+
const std::string &source) {
|
|
117
|
+
auto audioBus = audioDecoder_->decodeWithFilePath(source);
|
|
118
|
+
return std::make_shared<AudioBuffer>(audioBus);
|
|
119
|
+
}
|
|
120
|
+
#endif
|
|
121
|
+
|
|
98
122
|
std::function<void(AudioBus *, int)> BaseAudioContext::renderAudio() {
|
|
99
|
-
if (
|
|
123
|
+
if (isClosed()) {
|
|
100
124
|
return [](AudioBus *, int) {};
|
|
101
125
|
}
|
|
102
126
|
|
|
103
|
-
return [this](AudioBus*
|
|
127
|
+
return [this](AudioBus *data, int frames) {
|
|
104
128
|
destination_->renderAudio(data, frames);
|
|
105
129
|
};
|
|
106
130
|
}
|
|
107
131
|
|
|
108
|
-
AudioNodeManager*
|
|
132
|
+
AudioNodeManager *BaseAudioContext::getNodeManager() {
|
|
109
133
|
return nodeManager_.get();
|
|
110
134
|
}
|
|
111
135
|
|
|
136
|
+
bool BaseAudioContext::isRunning() const {
|
|
137
|
+
return state_ == ContextState::RUNNING;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
bool BaseAudioContext::isClosed() const {
|
|
141
|
+
return state_ == ContextState::CLOSED;
|
|
142
|
+
}
|
|
143
|
+
|
|
112
144
|
std::string BaseAudioContext::toString(ContextState state) {
|
|
113
145
|
switch (state) {
|
|
114
146
|
case ContextState::SUSPENDED:
|
|
@@ -122,7 +154,8 @@ std::string BaseAudioContext::toString(ContextState state) {
|
|
|
122
154
|
}
|
|
123
155
|
}
|
|
124
156
|
|
|
125
|
-
std::shared_ptr<PeriodicWave> BaseAudioContext::getBasicWaveForm(
|
|
157
|
+
std::shared_ptr<PeriodicWave> BaseAudioContext::getBasicWaveForm(
|
|
158
|
+
OscillatorType type) {
|
|
126
159
|
switch (type) {
|
|
127
160
|
case OscillatorType::SINE:
|
|
128
161
|
if (cachedSineWave_ == nullptr) {
|
|
@@ -149,7 +182,8 @@ std::shared_ptr<PeriodicWave> BaseAudioContext::getBasicWaveForm(OscillatorType
|
|
|
149
182
|
}
|
|
150
183
|
return cachedTriangleWave_;
|
|
151
184
|
case OscillatorType::CUSTOM:
|
|
152
|
-
throw std::invalid_argument(
|
|
185
|
+
throw std::invalid_argument(
|
|
186
|
+
"You can't get a custom wave form. You need to create it.");
|
|
153
187
|
break;
|
|
154
188
|
}
|
|
155
189
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
+
#include <functional>
|
|
3
4
|
#include <memory>
|
|
4
5
|
#include <string>
|
|
5
|
-
#include <vector>
|
|
6
6
|
#include <utility>
|
|
7
|
-
#include <
|
|
7
|
+
#include <vector>
|
|
8
8
|
|
|
9
9
|
#include "ContextState.h"
|
|
10
10
|
#include "OscillatorType.h"
|
|
@@ -26,11 +26,13 @@ class AudioBufferSourceNode;
|
|
|
26
26
|
class AudioPlayer;
|
|
27
27
|
#else
|
|
28
28
|
class IOSAudioPlayer;
|
|
29
|
+
class IOSAudioDecoder;
|
|
29
30
|
#endif
|
|
30
31
|
|
|
31
32
|
class BaseAudioContext {
|
|
32
33
|
public:
|
|
33
34
|
BaseAudioContext();
|
|
35
|
+
~BaseAudioContext();
|
|
34
36
|
std::string getState();
|
|
35
37
|
[[nodiscard]] int getSampleRate() const;
|
|
36
38
|
[[nodiscard]] double getCurrentTime() const;
|
|
@@ -43,17 +45,21 @@ class BaseAudioContext {
|
|
|
43
45
|
std::shared_ptr<StereoPannerNode> createStereoPanner();
|
|
44
46
|
std::shared_ptr<BiquadFilterNode> createBiquadFilter();
|
|
45
47
|
std::shared_ptr<AudioBufferSourceNode> createBufferSource();
|
|
46
|
-
static std::shared_ptr<AudioBuffer>
|
|
48
|
+
static std::shared_ptr<AudioBuffer>
|
|
49
|
+
createBuffer(int numberOfChannels, int length, int sampleRate);
|
|
47
50
|
std::shared_ptr<PeriodicWave> createPeriodicWave(
|
|
48
51
|
float *real,
|
|
49
52
|
float *imag,
|
|
50
53
|
bool disableNormalization,
|
|
51
54
|
int length);
|
|
52
|
-
std::shared_ptr<
|
|
55
|
+
std::shared_ptr<AudioBuffer> decodeAudioDataSource(const std::string &source);
|
|
53
56
|
|
|
57
|
+
std::shared_ptr<PeriodicWave> getBasicWaveForm(OscillatorType type);
|
|
54
58
|
std::function<void(AudioBus *, int)> renderAudio();
|
|
55
59
|
|
|
56
|
-
AudioNodeManager*
|
|
60
|
+
AudioNodeManager *getNodeManager();
|
|
61
|
+
[[nodiscard]] bool isRunning() const;
|
|
62
|
+
[[nodiscard]] bool isClosed() const;
|
|
57
63
|
|
|
58
64
|
protected:
|
|
59
65
|
static std::string toString(ContextState state);
|
|
@@ -63,6 +69,7 @@ class BaseAudioContext {
|
|
|
63
69
|
std::shared_ptr<AudioPlayer> audioPlayer_;
|
|
64
70
|
#else
|
|
65
71
|
std::shared_ptr<IOSAudioPlayer> audioPlayer_;
|
|
72
|
+
std::shared_ptr<IOSAudioDecoder> audioDecoder_;
|
|
66
73
|
#endif
|
|
67
74
|
|
|
68
75
|
int sampleRate_;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#include "AudioBus.h"
|
|
2
|
-
#include "AudioArray.h"
|
|
3
1
|
#include "BiquadFilterNode.h"
|
|
2
|
+
#include "AudioArray.h"
|
|
3
|
+
#include "AudioBus.h"
|
|
4
4
|
#include "BaseAudioContext.h"
|
|
5
5
|
|
|
6
6
|
// https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html - math
|
|
@@ -352,7 +352,9 @@ void BiquadFilterNode::applyFilter() {
|
|
|
352
352
|
}
|
|
353
353
|
}
|
|
354
354
|
|
|
355
|
-
void BiquadFilterNode::processNode(
|
|
355
|
+
void BiquadFilterNode::processNode(
|
|
356
|
+
AudioBus *processingBus,
|
|
357
|
+
int framesToProcess) {
|
|
356
358
|
resetCoefficients();
|
|
357
359
|
applyFilter();
|
|
358
360
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#include "AudioBus.h"
|
|
2
|
-
#include "AudioArray.h"
|
|
3
1
|
#include "OscillatorNode.h"
|
|
2
|
+
#include "AudioArray.h"
|
|
3
|
+
#include "AudioBus.h"
|
|
4
4
|
#include "BaseAudioContext.h"
|
|
5
5
|
|
|
6
6
|
namespace audioapi {
|
|
@@ -39,7 +39,7 @@ void OscillatorNode::setPeriodicWave(
|
|
|
39
39
|
type_ = OscillatorType::CUSTOM;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
void OscillatorNode::processNode(AudioBus*
|
|
42
|
+
void OscillatorNode::processNode(AudioBus *processingBus, int framesToProcess) {
|
|
43
43
|
if (!isPlaying()) {
|
|
44
44
|
processingBus->zero();
|
|
45
45
|
return;
|
|
@@ -50,7 +50,7 @@ void OscillatorNode::processNode(AudioBus* processingBus, int framesToProcess) {
|
|
|
50
50
|
|
|
51
51
|
for (int i = 0; i < framesToProcess; i += 1) {
|
|
52
52
|
auto detuneRatio =
|
|
53
|
-
|
|
53
|
+
std::pow(2.0f, detuneParam_->getValueAtTime(time) / 1200.0f);
|
|
54
54
|
auto detunedFrequency =
|
|
55
55
|
round(frequencyParam_->getValueAtTime(time) * detuneRatio);
|
|
56
56
|
auto phaseIncrement = detunedFrequency * periodicWave_->getScale();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
#include "AudioBus.h"
|
|
2
|
-
#include "Constants.h"
|
|
3
|
-
#include "AudioArray.h"
|
|
4
1
|
#include "StereoPannerNode.h"
|
|
2
|
+
#include "AudioArray.h"
|
|
3
|
+
#include "AudioBus.h"
|
|
5
4
|
#include "BaseAudioContext.h"
|
|
5
|
+
#include "Constants.h"
|
|
6
6
|
|
|
7
7
|
// https://webaudio.github.io/web-audio-api/#stereopanner-algorithm
|
|
8
8
|
|
|
@@ -19,17 +19,20 @@ std::shared_ptr<AudioParam> StereoPannerNode::getPanParam() const {
|
|
|
19
19
|
return panParam_;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
void StereoPannerNode::processNode(
|
|
22
|
+
void StereoPannerNode::processNode(
|
|
23
|
+
AudioBus *processingBus,
|
|
24
|
+
int framesToProcess) {
|
|
23
25
|
// TODO: Currently assumed channelCount is 2
|
|
24
26
|
// it should:
|
|
25
27
|
// - support mono-channel buses
|
|
26
|
-
// - throw errors when trying to setup stereo panner with more than 2
|
|
28
|
+
// - throw errors when trying to setup stereo panner with more than 2
|
|
29
|
+
// channels
|
|
27
30
|
|
|
28
31
|
double time = context_->getCurrentTime();
|
|
29
32
|
double deltaTime = 1.0 / context_->getSampleRate();
|
|
30
33
|
|
|
31
|
-
AudioArray*
|
|
32
|
-
AudioArray*
|
|
34
|
+
AudioArray *left = processingBus->getChannelByType(AudioBus::ChannelLeft);
|
|
35
|
+
AudioArray *right = processingBus->getChannelByType(AudioBus::ChannelRight);
|
|
33
36
|
|
|
34
37
|
for (int i = 0; i < framesToProcess; i += 1) {
|
|
35
38
|
float pan = panParam_->getValueAtTime(time);
|
|
@@ -17,7 +17,7 @@ class StereoPannerNode : public AudioNode {
|
|
|
17
17
|
[[nodiscard]] std::shared_ptr<AudioParam> getPanParam() const;
|
|
18
18
|
|
|
19
19
|
protected:
|
|
20
|
-
void processNode(AudioBus*
|
|
20
|
+
void processNode(AudioBus *processingBus, int framesToProcess) override;
|
|
21
21
|
|
|
22
22
|
private:
|
|
23
23
|
std::shared_ptr<AudioParam> panParam_;
|
|
@@ -38,7 +38,11 @@ namespace audioapi {
|
|
|
38
38
|
|
|
39
39
|
class FFTFrame {
|
|
40
40
|
public:
|
|
41
|
-
explicit FFTFrame(int size)
|
|
41
|
+
explicit FFTFrame(int size)
|
|
42
|
+
: size_(size),
|
|
43
|
+
log2Size_(static_cast<int>(log2(size))),
|
|
44
|
+
realData_(new float[size]),
|
|
45
|
+
imaginaryData_(new float[size]) {}
|
|
42
46
|
~FFTFrame() {
|
|
43
47
|
delete[] realData_;
|
|
44
48
|
delete[] imaginaryData_;
|