react-native-audio-api 0.3.0-rc1 → 0.3.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/android/CMakeLists.txt +4 -4
- package/android/build.gradle +1 -3
- package/android/libs/include/miniaudio.h +92621 -0
- package/android/src/main/cpp/AudioAPIInstaller/AudioAPIInstaller.cpp +10 -12
- package/android/src/main/cpp/AudioAPIInstaller/AudioAPIInstaller.h +16 -9
- package/android/src/main/cpp/AudioDecoder/AudioDecoder.cpp +64 -0
- package/android/src/main/cpp/AudioDecoder/AudioDecoder.h +21 -0
- package/android/src/main/cpp/AudioPlayer/AudioPlayer.h +2 -2
- package/android/src/main/java/com/swmansion/audioapi/module/AudioAPIInstaller.kt +14 -4
- package/android/src/main/java/com/swmansion/audioapi/nativemodules/AudioAPIModule.kt +2 -3
- package/common/cpp/AudioAPIInstaller/AudioAPIInstallerHostObject.h +26 -27
- package/common/cpp/HostObjects/AudioBufferHostObject.h +79 -13
- package/common/cpp/HostObjects/AudioBufferSourceNodeHostObject.h +93 -14
- package/common/cpp/HostObjects/AudioContextHostObject.h +10 -19
- package/common/cpp/HostObjects/AudioDestinationNodeHostObject.h +3 -16
- package/common/cpp/HostObjects/AudioNodeHostObject.h +48 -11
- package/common/cpp/HostObjects/AudioParamHostObject.h +56 -14
- package/common/cpp/HostObjects/AudioScheduledSourceNodeHostObject.h +23 -16
- package/common/cpp/HostObjects/BaseAudioContextHostObject.h +131 -13
- package/common/cpp/HostObjects/BiquadFilterNodeHostObject.h +76 -18
- package/common/cpp/HostObjects/Constants.h +2 -0
- package/common/cpp/HostObjects/GainNodeHostObject.h +10 -15
- package/common/cpp/HostObjects/OscillatorNodeHostObject.h +40 -17
- package/common/cpp/HostObjects/PeriodicWaveHostObject.h +4 -17
- package/common/cpp/HostObjects/StereoPannerNodeHostObject.h +10 -17
- package/common/cpp/core/AudioBufferSourceNode.cpp +180 -73
- package/common/cpp/core/AudioBufferSourceNode.h +41 -1
- package/common/cpp/core/AudioDestinationNode.cpp +1 -0
- package/common/cpp/core/AudioDestinationNode.h +1 -1
- package/common/cpp/core/AudioScheduledSourceNode.cpp +86 -21
- package/common/cpp/core/AudioScheduledSourceNode.h +12 -4
- package/common/cpp/core/BaseAudioContext.cpp +8 -5
- package/common/cpp/core/BaseAudioContext.h +5 -3
- package/common/cpp/core/OscillatorNode.cpp +7 -2
- package/common/cpp/jsi/JsiHostObject.cpp +85 -0
- package/common/cpp/jsi/JsiHostObject.h +94 -0
- package/common/cpp/jsi/JsiPromise.cpp +65 -0
- package/common/cpp/jsi/JsiPromise.h +48 -0
- package/common/cpp/utils/AudioUtils.cpp +26 -0
- package/common/cpp/utils/AudioUtils.h +16 -0
- package/ios/AudioAPIModule.mm +3 -6
- package/ios/AudioDecoder/AudioDecoder.h +1 -1
- package/ios/AudioDecoder/AudioDecoder.m +14 -102
- package/ios/AudioDecoder/IOSAudioDecoder.h +2 -0
- package/ios/AudioDecoder/IOSAudioDecoder.mm +7 -1
- package/ios/AudioPlayer/AudioPlayer.m +3 -1
- package/lib/module/core/AudioBufferSourceNode.js +15 -0
- package/lib/module/core/AudioBufferSourceNode.js.map +1 -1
- package/lib/module/core/BaseAudioContext.js +2 -3
- package/lib/module/core/BaseAudioContext.js.map +1 -1
- package/lib/module/index.js +18 -3
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/core/AudioBufferSourceNode.d.ts +7 -0
- package/lib/typescript/core/AudioBufferSourceNode.d.ts.map +1 -1
- package/lib/typescript/core/BaseAudioContext.d.ts +2 -2
- package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/core/types.d.ts +0 -6
- package/lib/typescript/core/types.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +8 -4
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/interfaces.d.ts +5 -1
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/core/AudioBufferSourceNode.ts +23 -0
- package/src/core/BaseAudioContext.ts +3 -8
- package/src/core/types.ts +0 -7
- package/src/index.ts +26 -12
- package/src/interfaces.ts +6 -1
- package/android/libs/fftw3/x86/libfftw3.a +0 -0
- package/android/libs/fftw3/x86_64/libfftw3.a +0 -0
- package/common/cpp/AudioAPIInstaller/AudioAPIInstallerHostObject.cpp +0 -54
- package/common/cpp/AudioAPIInstaller/AudioAPIInstallerWrapper.h +0 -38
- package/common/cpp/AudioAPIInstaller/android/AudioAPIInstallerWrapper.cpp +0 -16
- package/common/cpp/AudioAPIInstaller/ios/AudioAPIInstallerWrapper.cpp +0 -12
- package/common/cpp/HostObjects/AudioBufferHostObject.cpp +0 -149
- package/common/cpp/HostObjects/AudioBufferSourceNodeHostObject.cpp +0 -79
- package/common/cpp/HostObjects/AudioContextHostObject.cpp +0 -54
- package/common/cpp/HostObjects/AudioDestinationNodeHostObject.cpp +0 -33
- package/common/cpp/HostObjects/AudioNodeHostObject.cpp +0 -102
- package/common/cpp/HostObjects/AudioParamHostObject.cpp +0 -115
- package/common/cpp/HostObjects/AudioScheduledSourceNodeHostObject.cpp +0 -73
- package/common/cpp/HostObjects/BaseAudioContextHostObject.cpp +0 -240
- package/common/cpp/HostObjects/BiquadFilterNodeHostObject.cpp +0 -125
- package/common/cpp/HostObjects/GainNodeHostObject.cpp +0 -41
- package/common/cpp/HostObjects/OscillatorNodeHostObject.cpp +0 -88
- package/common/cpp/HostObjects/PeriodicWaveHostObject.cpp +0 -33
- package/common/cpp/HostObjects/StereoPannerNodeHostObject.cpp +0 -41
- package/common/cpp/utils/JsiPromise.cpp +0 -59
- package/common/cpp/utils/JsiPromise.h +0 -42
- package/common/cpp/wrappers/AudioBufferSourceNodeWrapper.cpp +0 -45
- package/common/cpp/wrappers/AudioBufferSourceNodeWrapper.h +0 -26
- package/common/cpp/wrappers/AudioBufferWrapper.cpp +0 -46
- package/common/cpp/wrappers/AudioBufferWrapper.h +0 -30
- package/common/cpp/wrappers/AudioContextWrapper.cpp +0 -17
- package/common/cpp/wrappers/AudioContextWrapper.h +0 -19
- package/common/cpp/wrappers/AudioDestinationNodeWrapper.h +0 -16
- package/common/cpp/wrappers/AudioNodeWrapper.cpp +0 -37
- package/common/cpp/wrappers/AudioNodeWrapper.h +0 -25
- package/common/cpp/wrappers/AudioParamWrapper.cpp +0 -42
- package/common/cpp/wrappers/AudioParamWrapper.h +0 -25
- package/common/cpp/wrappers/AudioScheduledSourceNodeWrapper.cpp +0 -23
- package/common/cpp/wrappers/AudioScheduledSourceNodeWrapper.h +0 -23
- package/common/cpp/wrappers/BaseAudioContextWrapper.cpp +0 -83
- package/common/cpp/wrappers/BaseAudioContextWrapper.h +0 -50
- package/common/cpp/wrappers/BiquadFilterNodeWrapper.cpp +0 -60
- package/common/cpp/wrappers/BiquadFilterNodeWrapper.h +0 -37
- package/common/cpp/wrappers/GainNodeWrapper.cpp +0 -14
- package/common/cpp/wrappers/GainNodeWrapper.h +0 -20
- package/common/cpp/wrappers/OscillatorNodeWrapper.cpp +0 -44
- package/common/cpp/wrappers/OscillatorNodeWrapper.h +0 -31
- package/common/cpp/wrappers/PeriodicWaveWrapper.h +0 -17
- package/common/cpp/wrappers/StereoPannerNodeWrapper.cpp +0 -16
- package/common/cpp/wrappers/StereoPannerNodeWrapper.h +0 -21
- package/lib/module/utils/resolveAudioSource.js +0 -10
- package/lib/module/utils/resolveAudioSource.js.map +0 -1
- package/lib/typescript/utils/resolveAudioSource.d.ts +0 -3
- package/lib/typescript/utils/resolveAudioSource.d.ts.map +0 -1
- package/src/utils/resolveAudioSource.ts +0 -14
- /package/android/libs/{fftw3/arm64-v8a → arm64-v8a}/libfftw3.a +0 -0
- /package/android/libs/{fftw3/armeabi-v7a → armeabi-v7a}/libfftw3.a +0 -0
- /package/android/libs/include/{fftw3/fftw3.h → fftw3.h} +0 -0
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
#include "AudioNodeHostObject.h"
|
|
8
8
|
#include "AudioParamHostObject.h"
|
|
9
|
-
#include "
|
|
9
|
+
#include "StereoPannerNode.h"
|
|
10
10
|
|
|
11
11
|
namespace audioapi {
|
|
12
12
|
using namespace facebook;
|
|
@@ -14,23 +14,16 @@ using namespace facebook;
|
|
|
14
14
|
class StereoPannerNodeHostObject : public AudioNodeHostObject {
|
|
15
15
|
public:
|
|
16
16
|
explicit StereoPannerNodeHostObject(
|
|
17
|
-
const std::shared_ptr<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
void set(
|
|
22
|
-
jsi::Runtime &runtime,
|
|
23
|
-
const jsi::PropNameID &name,
|
|
24
|
-
const jsi::Value &value) override;
|
|
25
|
-
|
|
26
|
-
std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime &rt) override;
|
|
27
|
-
|
|
28
|
-
static std::shared_ptr<StereoPannerNodeHostObject> createFromWrapper(
|
|
29
|
-
const std::shared_ptr<StereoPannerNodeWrapper> &wrapper) {
|
|
30
|
-
return std::make_shared<StereoPannerNodeHostObject>(wrapper);
|
|
17
|
+
const std::shared_ptr<StereoPannerNode> &node)
|
|
18
|
+
: AudioNodeHostObject(node) {
|
|
19
|
+
addGetters(JSI_EXPORT_PROPERTY_GETTER(StereoPannerNodeHostObject, pan));
|
|
31
20
|
}
|
|
32
21
|
|
|
33
|
-
|
|
34
|
-
|
|
22
|
+
JSI_PROPERTY_GETTER(pan) {
|
|
23
|
+
auto stereoPannerNode = std::static_pointer_cast<StereoPannerNode>(node_);
|
|
24
|
+
auto panParam_ =
|
|
25
|
+
std::make_shared<AudioParamHostObject>(stereoPannerNode->getPanParam());
|
|
26
|
+
return jsi::Object::createFromHostObject(runtime, panParam_);
|
|
27
|
+
}
|
|
35
28
|
};
|
|
36
29
|
} // namespace audioapi
|
|
@@ -3,14 +3,27 @@
|
|
|
3
3
|
#include "AudioArray.h"
|
|
4
4
|
#include "AudioBufferSourceNode.h"
|
|
5
5
|
#include "AudioBus.h"
|
|
6
|
+
#include "AudioParam.h"
|
|
7
|
+
#include "AudioUtils.h"
|
|
6
8
|
#include "BaseAudioContext.h"
|
|
9
|
+
#include "Constants.h"
|
|
7
10
|
|
|
8
11
|
namespace audioapi {
|
|
9
12
|
|
|
10
13
|
AudioBufferSourceNode::AudioBufferSourceNode(BaseAudioContext *context)
|
|
11
|
-
: AudioScheduledSourceNode(context),
|
|
14
|
+
: AudioScheduledSourceNode(context),
|
|
15
|
+
loop_(false),
|
|
16
|
+
loopStart_(0),
|
|
17
|
+
loopEnd_(0),
|
|
18
|
+
vReadIndex_(0.0) {
|
|
12
19
|
numberOfInputs_ = 0;
|
|
13
20
|
buffer_ = std::shared_ptr<AudioBuffer>(nullptr);
|
|
21
|
+
|
|
22
|
+
detuneParam_ =
|
|
23
|
+
std::make_shared<AudioParam>(context, 0.0, -MAX_DETUNE, MAX_DETUNE);
|
|
24
|
+
playbackRateParam_ = std::make_shared<AudioParam>(
|
|
25
|
+
context, 1.0, MOST_NEGATIVE_SINGLE_FLOAT, MOST_POSITIVE_SINGLE_FLOAT);
|
|
26
|
+
|
|
14
27
|
isInitialized_ = true;
|
|
15
28
|
}
|
|
16
29
|
|
|
@@ -18,6 +31,23 @@ bool AudioBufferSourceNode::getLoop() const {
|
|
|
18
31
|
return loop_;
|
|
19
32
|
}
|
|
20
33
|
|
|
34
|
+
double AudioBufferSourceNode::getLoopStart() const {
|
|
35
|
+
return loopStart_;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
double AudioBufferSourceNode::getLoopEnd() const {
|
|
39
|
+
return loopEnd_;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
std::shared_ptr<AudioParam> AudioBufferSourceNode::getDetuneParam() const {
|
|
43
|
+
return detuneParam_;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
std::shared_ptr<AudioParam> AudioBufferSourceNode::getPlaybackRateParam()
|
|
47
|
+
const {
|
|
48
|
+
return playbackRateParam_;
|
|
49
|
+
}
|
|
50
|
+
|
|
21
51
|
std::shared_ptr<AudioBuffer> AudioBufferSourceNode::getBuffer() const {
|
|
22
52
|
return buffer_;
|
|
23
53
|
}
|
|
@@ -26,120 +56,197 @@ void AudioBufferSourceNode::setLoop(bool loop) {
|
|
|
26
56
|
loop_ = loop;
|
|
27
57
|
}
|
|
28
58
|
|
|
59
|
+
void AudioBufferSourceNode::setLoopStart(double loopStart) {
|
|
60
|
+
loopStart_ = loopStart;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
void AudioBufferSourceNode::setLoopEnd(double loopEnd) {
|
|
64
|
+
loopEnd_ = loopEnd;
|
|
65
|
+
}
|
|
66
|
+
|
|
29
67
|
void AudioBufferSourceNode::setBuffer(
|
|
30
68
|
const std::shared_ptr<AudioBuffer> &buffer) {
|
|
31
69
|
if (!buffer) {
|
|
32
70
|
buffer_ = std::shared_ptr<AudioBuffer>(nullptr);
|
|
71
|
+
alignedBus_ = std::shared_ptr<AudioBus>(nullptr);
|
|
33
72
|
return;
|
|
34
73
|
}
|
|
35
74
|
|
|
36
75
|
buffer_ = buffer;
|
|
76
|
+
alignedBus_ = std::make_shared<AudioBus>(
|
|
77
|
+
context_->getSampleRate(), buffer_->getLength());
|
|
78
|
+
|
|
79
|
+
alignedBus_->zero();
|
|
80
|
+
alignedBus_->sum(buffer_->bus_.get());
|
|
37
81
|
}
|
|
38
82
|
|
|
39
|
-
// Note: AudioBus copy method will use memcpy if the source buffer and system
|
|
40
|
-
// processing bus have same channel count, otherwise it will use the summing
|
|
41
|
-
// function taking care of up/down mixing.
|
|
42
83
|
void AudioBufferSourceNode::processNode(
|
|
43
84
|
AudioBus *processingBus,
|
|
44
85
|
int framesToProcess) {
|
|
86
|
+
size_t startOffset = 0;
|
|
87
|
+
size_t offsetLength = 0;
|
|
88
|
+
|
|
89
|
+
updatePlaybackInfo(processingBus, framesToProcess, startOffset, offsetLength);
|
|
90
|
+
float playbackRate = getPlaybackRateValue(startOffset);
|
|
91
|
+
|
|
45
92
|
// No audio data to fill, zero the output and return.
|
|
46
|
-
if (!isPlaying() || !
|
|
93
|
+
if (!isPlaying() || !alignedBus_ || alignedBus_->getSize() == 0 ||
|
|
94
|
+
!playbackRate) {
|
|
47
95
|
processingBus->zero();
|
|
48
96
|
return;
|
|
49
97
|
}
|
|
50
98
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
99
|
+
if (std::fabs(playbackRate) == 1.0) {
|
|
100
|
+
processWithoutInterpolation(
|
|
101
|
+
processingBus, startOffset, offsetLength, playbackRate);
|
|
102
|
+
} else {
|
|
103
|
+
processWithInterpolation(
|
|
104
|
+
processingBus, startOffset, offsetLength, playbackRate);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
55
107
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
108
|
+
/**
|
|
109
|
+
* Helper functions
|
|
110
|
+
*/
|
|
60
111
|
|
|
61
|
-
|
|
62
|
-
|
|
112
|
+
void AudioBufferSourceNode::processWithoutInterpolation(
|
|
113
|
+
AudioBus *processingBus,
|
|
114
|
+
size_t startOffset,
|
|
115
|
+
size_t offsetLength,
|
|
116
|
+
float playbackRate) {
|
|
117
|
+
size_t direction = playbackRate < 0 ? -1 : 1;
|
|
63
118
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (framesToProcess < buffer_->getLength()) {
|
|
67
|
-
int outputBusIndex = 0;
|
|
68
|
-
int framesToCopy = 0;
|
|
119
|
+
auto readIndex = static_cast<size_t>(vReadIndex_);
|
|
120
|
+
size_t writeIndex = startOffset;
|
|
69
121
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
buffer_->getLength() - bufferIndex_);
|
|
122
|
+
auto frameStart = static_cast<size_t>(getVirtualStartFrame());
|
|
123
|
+
auto frameEnd = static_cast<size_t>(getVirtualEndFrame());
|
|
124
|
+
size_t frameDelta = frameEnd - frameStart;
|
|
74
125
|
|
|
75
|
-
|
|
76
|
-
buffer_->bus_.get(), bufferIndex_, outputBusIndex, framesToCopy);
|
|
126
|
+
size_t framesLeft = offsetLength;
|
|
77
127
|
|
|
78
|
-
|
|
79
|
-
|
|
128
|
+
if (loop_ && (readIndex >= frameEnd || readIndex < frameStart)) {
|
|
129
|
+
readIndex = frameStart + (readIndex - frameStart) % frameDelta;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
while (framesLeft > 0) {
|
|
133
|
+
size_t framesToEnd = frameEnd - readIndex;
|
|
134
|
+
size_t framesToCopy = std::min(framesToEnd, framesLeft);
|
|
135
|
+
framesToCopy = framesToCopy > 0 ? framesToCopy : 0;
|
|
80
136
|
|
|
81
|
-
|
|
82
|
-
|
|
137
|
+
// Direction is forward, we can normally copy the data
|
|
138
|
+
if (direction == 1) {
|
|
139
|
+
processingBus->copy(
|
|
140
|
+
alignedBus_.get(), readIndex, writeIndex, framesToCopy);
|
|
141
|
+
} else {
|
|
142
|
+
for (int i = 0; i < framesToCopy; i += 1) {
|
|
143
|
+
for (int j = 0; j < processingBus->getNumberOfChannels(); j += 1) {
|
|
144
|
+
(*processingBus->getChannel(j))[writeIndex + i] =
|
|
145
|
+
(*alignedBus_->getChannel(j))[readIndex - i];
|
|
146
|
+
}
|
|
83
147
|
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
writeIndex += framesToCopy;
|
|
151
|
+
readIndex += framesToCopy * direction;
|
|
152
|
+
framesLeft -= framesToCopy;
|
|
84
153
|
|
|
85
|
-
|
|
154
|
+
if (readIndex >= frameEnd || readIndex < frameStart) {
|
|
155
|
+
readIndex -= direction * frameDelta;
|
|
86
156
|
|
|
87
157
|
if (!loop_) {
|
|
158
|
+
processingBus->zero(writeIndex, framesLeft);
|
|
88
159
|
playbackState_ = PlaybackState::FINISHED;
|
|
89
160
|
disable();
|
|
90
|
-
|
|
91
|
-
if (framesToProcess - outputBusIndex > 0) {
|
|
92
|
-
processingBus->zero(outputBusIndex, framesToProcess - outputBusIndex);
|
|
93
|
-
}
|
|
161
|
+
break;
|
|
94
162
|
}
|
|
95
163
|
}
|
|
96
|
-
|
|
97
|
-
return;
|
|
98
164
|
}
|
|
99
165
|
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
processingBus
|
|
106
|
-
|
|
166
|
+
// update reading index for next render quantum
|
|
167
|
+
vReadIndex_ = readIndex;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
void AudioBufferSourceNode::processWithInterpolation(
|
|
171
|
+
AudioBus *processingBus,
|
|
172
|
+
size_t startOffset,
|
|
173
|
+
size_t offsetLength,
|
|
174
|
+
float playbackRate) {
|
|
175
|
+
size_t direction = playbackRate < 0 ? -1 : 1;
|
|
107
176
|
|
|
108
|
-
|
|
109
|
-
disable();
|
|
177
|
+
size_t writeIndex = startOffset;
|
|
110
178
|
|
|
111
|
-
|
|
112
|
-
|
|
179
|
+
double vFrameStart = getVirtualStartFrame();
|
|
180
|
+
double vFrameEnd = getVirtualEndFrame();
|
|
181
|
+
double vFrameDelta = vFrameEnd - vFrameStart;
|
|
113
182
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// the loop, which will also carry over some buffer frames to the next render
|
|
117
|
-
// quantum.
|
|
118
|
-
int processingBusPosition = 0;
|
|
119
|
-
int bufferSize = buffer_->getLength();
|
|
120
|
-
int remainingFrames = framesToProcess - framesToProcess / bufferSize;
|
|
121
|
-
|
|
122
|
-
// Do we have some frames left in the buffer from the previous render quantum,
|
|
123
|
-
// if yes copy them over and reset the buffer position.
|
|
124
|
-
if (bufferIndex_ > 0) {
|
|
125
|
-
processingBus->copy(buffer_->bus_.get(), 0, bufferIndex_);
|
|
126
|
-
processingBusPosition += bufferIndex_;
|
|
127
|
-
bufferIndex_ = 0;
|
|
128
|
-
}
|
|
183
|
+
auto frameStart = static_cast<size_t>(vFrameStart);
|
|
184
|
+
auto frameEnd = static_cast<size_t>(vFrameEnd);
|
|
129
185
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
186
|
+
size_t framesLeft = offsetLength;
|
|
187
|
+
|
|
188
|
+
// Wrap to the start of the loop if necessary
|
|
189
|
+
if (loop_ && (vReadIndex_ >= vFrameEnd || vReadIndex_ < vFrameStart)) {
|
|
190
|
+
vReadIndex_ =
|
|
191
|
+
vFrameStart + std::fmod(vReadIndex_ - vFrameStart, vFrameDelta);
|
|
134
192
|
}
|
|
135
193
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
194
|
+
while (framesLeft > 0) {
|
|
195
|
+
auto readIndex = static_cast<size_t>(vReadIndex_);
|
|
196
|
+
size_t nextReadIndex = readIndex + 1;
|
|
197
|
+
float factor = vReadIndex_ - readIndex;
|
|
198
|
+
|
|
199
|
+
if (nextReadIndex >= frameEnd) {
|
|
200
|
+
nextReadIndex = loop_ ? frameStart : readIndex;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
for (int i = 0; i < processingBus->getNumberOfChannels(); i += 1) {
|
|
204
|
+
float *destination = processingBus->getChannel(i)->getData();
|
|
205
|
+
const float *source = alignedBus_->getChannel(i)->getData();
|
|
206
|
+
|
|
207
|
+
destination[writeIndex] = AudioUtils::linearInterpolate(
|
|
208
|
+
source, readIndex, nextReadIndex, factor);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
writeIndex += 1;
|
|
212
|
+
vReadIndex_ += playbackRate * direction;
|
|
213
|
+
framesLeft -= 1;
|
|
214
|
+
|
|
215
|
+
if (vReadIndex_ < vFrameStart || vReadIndex_ >= vFrameEnd) {
|
|
216
|
+
vReadIndex_ -= direction * vFrameDelta;
|
|
217
|
+
|
|
218
|
+
if (!loop_) {
|
|
219
|
+
processingBus->zero(writeIndex, framesLeft);
|
|
220
|
+
playbackState_ = PlaybackState::FINISHED;
|
|
221
|
+
disable();
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
142
225
|
}
|
|
143
226
|
}
|
|
144
227
|
|
|
228
|
+
float AudioBufferSourceNode::getPlaybackRateValue(size_t &startOffset) {
|
|
229
|
+
double time =
|
|
230
|
+
context_->getCurrentTime() + startOffset / context_->getSampleRate();
|
|
231
|
+
|
|
232
|
+
return playbackRateParam_->getValueAtTime(time) *
|
|
233
|
+
std::pow(2.0f, detuneParam_->getValueAtTime(time) / 1200.0f);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
double AudioBufferSourceNode::getVirtualStartFrame() {
|
|
237
|
+
double loopStartFrame = loopStart_ * context_->getSampleRate();
|
|
238
|
+
|
|
239
|
+
return loop_ && loopStartFrame >= 0 && loopStart_ < loopEnd_ ? loopStartFrame
|
|
240
|
+
: 0.0;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
double AudioBufferSourceNode::getVirtualEndFrame() {
|
|
244
|
+
double inputBufferLength = alignedBus_->getSize();
|
|
245
|
+
double loopEndFrame = loopEnd_ * context_->getSampleRate();
|
|
246
|
+
|
|
247
|
+
return loop_ && loopEndFrame > 0 && loopStart_ < loopEnd_
|
|
248
|
+
? std::min(loopEndFrame, inputBufferLength)
|
|
249
|
+
: inputBufferLength;
|
|
250
|
+
}
|
|
251
|
+
|
|
145
252
|
} // namespace audioapi
|
|
@@ -8,23 +8,63 @@
|
|
|
8
8
|
namespace audioapi {
|
|
9
9
|
|
|
10
10
|
class AudioBus;
|
|
11
|
+
class AudioParam;
|
|
11
12
|
|
|
12
13
|
class AudioBufferSourceNode : public AudioScheduledSourceNode {
|
|
13
14
|
public:
|
|
14
15
|
explicit AudioBufferSourceNode(BaseAudioContext *context);
|
|
15
16
|
|
|
16
17
|
[[nodiscard]] bool getLoop() const;
|
|
18
|
+
[[nodiscard]] double getLoopStart() const;
|
|
19
|
+
[[nodiscard]] double getLoopEnd() const;
|
|
20
|
+
|
|
21
|
+
[[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
|
|
22
|
+
[[nodiscard]] std::shared_ptr<AudioParam> getPlaybackRateParam() const;
|
|
23
|
+
|
|
17
24
|
[[nodiscard]] std::shared_ptr<AudioBuffer> getBuffer() const;
|
|
25
|
+
|
|
18
26
|
void setLoop(bool loop);
|
|
27
|
+
void setLoopStart(double loopStart);
|
|
28
|
+
void setLoopEnd(double loopEnd);
|
|
29
|
+
|
|
19
30
|
void setBuffer(const std::shared_ptr<AudioBuffer> &buffer);
|
|
20
31
|
|
|
21
32
|
protected:
|
|
22
33
|
void processNode(AudioBus *processingBus, int framesToProcess) override;
|
|
23
34
|
|
|
24
35
|
private:
|
|
36
|
+
// Looping related properties
|
|
25
37
|
bool loop_;
|
|
38
|
+
double loopStart_;
|
|
39
|
+
double loopEnd_;
|
|
40
|
+
|
|
41
|
+
// playback rate aka pitch change params
|
|
42
|
+
std::shared_ptr<AudioParam> detuneParam_;
|
|
43
|
+
std::shared_ptr<AudioParam> playbackRateParam_;
|
|
44
|
+
|
|
45
|
+
// internal helper
|
|
46
|
+
double vReadIndex_;
|
|
47
|
+
|
|
48
|
+
// User provided buffer
|
|
26
49
|
std::shared_ptr<AudioBuffer> buffer_;
|
|
27
|
-
|
|
50
|
+
std::shared_ptr<AudioBus> alignedBus_;
|
|
51
|
+
|
|
52
|
+
float getPlaybackRateValue(size_t &startOffset);
|
|
53
|
+
|
|
54
|
+
double getVirtualStartFrame();
|
|
55
|
+
double getVirtualEndFrame();
|
|
56
|
+
|
|
57
|
+
void processWithoutInterpolation(
|
|
58
|
+
AudioBus *processingBus,
|
|
59
|
+
size_t startOffset,
|
|
60
|
+
size_t offsetLength,
|
|
61
|
+
float playbackRate);
|
|
62
|
+
|
|
63
|
+
void processWithInterpolation(
|
|
64
|
+
AudioBus *processingBus,
|
|
65
|
+
size_t startOffset,
|
|
66
|
+
size_t offsetLength,
|
|
67
|
+
float playbackRate);
|
|
28
68
|
};
|
|
29
69
|
|
|
30
70
|
} // namespace audioapi
|
|
@@ -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_;
|
|
@@ -1,24 +1,37 @@
|
|
|
1
1
|
#include "AudioScheduledSourceNode.h"
|
|
2
|
+
#include "AudioArray.h"
|
|
3
|
+
#include "AudioBus.h"
|
|
2
4
|
#include "AudioNodeManager.h"
|
|
5
|
+
#include "AudioUtils.h"
|
|
3
6
|
#include "BaseAudioContext.h"
|
|
4
7
|
|
|
5
8
|
namespace audioapi {
|
|
6
9
|
|
|
7
10
|
AudioScheduledSourceNode::AudioScheduledSourceNode(BaseAudioContext *context)
|
|
8
|
-
: AudioNode(context),
|
|
11
|
+
: AudioNode(context),
|
|
12
|
+
playbackState_(PlaybackState::UNSCHEDULED),
|
|
13
|
+
startTime_(-1.0),
|
|
14
|
+
stopTime_(-1.0) {
|
|
9
15
|
numberOfInputs_ = 0;
|
|
10
|
-
isInitialized_ = true;
|
|
11
16
|
}
|
|
12
17
|
|
|
13
18
|
void AudioScheduledSourceNode::start(double time) {
|
|
14
|
-
context_->getNodeManager()->addSourceNode(shared_from_this());
|
|
15
|
-
|
|
16
19
|
playbackState_ = PlaybackState::SCHEDULED;
|
|
17
|
-
|
|
20
|
+
startTime_ = time;
|
|
21
|
+
|
|
22
|
+
context_->getNodeManager()->addSourceNode(shared_from_this());
|
|
18
23
|
}
|
|
19
24
|
|
|
20
25
|
void AudioScheduledSourceNode::stop(double time) {
|
|
21
|
-
|
|
26
|
+
stopTime_ = time;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
bool AudioScheduledSourceNode::isUnscheduled() {
|
|
30
|
+
return playbackState_ == PlaybackState::UNSCHEDULED;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
bool AudioScheduledSourceNode::isScheduled() {
|
|
34
|
+
return playbackState_ == PlaybackState::SCHEDULED;
|
|
22
35
|
}
|
|
23
36
|
|
|
24
37
|
bool AudioScheduledSourceNode::isPlaying() {
|
|
@@ -29,25 +42,77 @@ bool AudioScheduledSourceNode::isFinished() {
|
|
|
29
42
|
return playbackState_ == PlaybackState::FINISHED;
|
|
30
43
|
}
|
|
31
44
|
|
|
32
|
-
void AudioScheduledSourceNode::
|
|
33
|
-
|
|
34
|
-
|
|
45
|
+
void AudioScheduledSourceNode::updatePlaybackInfo(
|
|
46
|
+
AudioBus *processingBus,
|
|
47
|
+
int framesToProcess,
|
|
48
|
+
size_t &startOffset,
|
|
49
|
+
size_t &nonSilentFramesToProcess) {
|
|
50
|
+
if (!isInitialized_) {
|
|
51
|
+
startOffset = 0;
|
|
52
|
+
nonSilentFramesToProcess = 0;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
35
55
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
56
|
+
int sampleRate = context_->getSampleRate();
|
|
57
|
+
|
|
58
|
+
size_t firstFrame = context_->getCurrentSampleFrame();
|
|
59
|
+
size_t lastFrame = firstFrame + framesToProcess;
|
|
60
|
+
|
|
61
|
+
size_t startFrame = std::max(
|
|
62
|
+
AudioUtils::timeToSampleFrame(startTime_, sampleRate), firstFrame);
|
|
63
|
+
size_t stopFrame = stopTime_ == -1.0
|
|
64
|
+
? std::numeric_limits<size_t>::max()
|
|
65
|
+
: std::max(
|
|
66
|
+
AudioUtils::timeToSampleFrame(stopTime_, sampleRate), firstFrame);
|
|
67
|
+
|
|
68
|
+
if (isUnscheduled() || isFinished()) {
|
|
69
|
+
startOffset = 0;
|
|
70
|
+
nonSilentFramesToProcess = 0;
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
40
73
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
74
|
+
if (isScheduled()) {
|
|
75
|
+
// not yet playing
|
|
76
|
+
if (startFrame > lastFrame) {
|
|
77
|
+
startOffset = 0;
|
|
78
|
+
nonSilentFramesToProcess = 0;
|
|
79
|
+
return;
|
|
47
80
|
}
|
|
48
81
|
|
|
49
|
-
|
|
50
|
-
|
|
82
|
+
// start playing
|
|
83
|
+
// zero first frames before starting frame
|
|
84
|
+
playbackState_ = PlaybackState::PLAYING;
|
|
85
|
+
startOffset = std::max(startFrame, firstFrame) - firstFrame > 0
|
|
86
|
+
? std::max(startFrame, firstFrame) - firstFrame
|
|
87
|
+
: 0;
|
|
88
|
+
nonSilentFramesToProcess =
|
|
89
|
+
std::min(lastFrame, stopFrame) - startFrame - startOffset;
|
|
90
|
+
processingBus->zero(0, startOffset);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// the node is playing
|
|
95
|
+
|
|
96
|
+
// stop will happen in this render quantum
|
|
97
|
+
// zero remaining frames after stop frame
|
|
98
|
+
if (stopFrame < lastFrame && stopFrame >= firstFrame) {
|
|
99
|
+
startOffset = 0;
|
|
100
|
+
nonSilentFramesToProcess = stopFrame - firstFrame;
|
|
101
|
+
processingBus->zero(stopFrame - firstFrame, lastFrame - stopFrame);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// mark as finished in first silent render quantum
|
|
106
|
+
if (stopFrame < firstFrame) {
|
|
107
|
+
startOffset = 0;
|
|
108
|
+
nonSilentFramesToProcess = 0;
|
|
109
|
+
playbackState_ = PlaybackState::FINISHED;
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// normal "mid-buffer" playback
|
|
114
|
+
startOffset = 0;
|
|
115
|
+
nonSilentFramesToProcess = framesToProcess;
|
|
51
116
|
}
|
|
52
117
|
|
|
53
118
|
} // namespace audioapi
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
+
#include <algorithm>
|
|
3
4
|
#include <atomic>
|
|
4
5
|
#include <chrono>
|
|
5
6
|
#include <functional>
|
|
6
7
|
#include <iostream>
|
|
8
|
+
#include <limits>
|
|
7
9
|
#include <memory>
|
|
8
10
|
#include <thread>
|
|
9
11
|
|
|
@@ -19,16 +21,22 @@ class AudioScheduledSourceNode : public AudioNode {
|
|
|
19
21
|
void start(double time);
|
|
20
22
|
void stop(double time);
|
|
21
23
|
|
|
22
|
-
bool
|
|
24
|
+
bool isUnscheduled();
|
|
25
|
+
bool isScheduled();
|
|
23
26
|
bool isPlaying();
|
|
27
|
+
bool isFinished();
|
|
24
28
|
|
|
25
29
|
protected:
|
|
26
30
|
std::atomic<PlaybackState> playbackState_;
|
|
31
|
+
void updatePlaybackInfo(
|
|
32
|
+
AudioBus *processingBus,
|
|
33
|
+
int framesToProcess,
|
|
34
|
+
size_t &startOffset,
|
|
35
|
+
size_t &nonSilentFramesToProcess);
|
|
27
36
|
|
|
28
37
|
private:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
void waitAndExecute(double time, const std::function<void(double)> &fun);
|
|
38
|
+
double startTime_;
|
|
39
|
+
double stopTime_;
|
|
32
40
|
};
|
|
33
41
|
|
|
34
42
|
} // namespace audioapi
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#ifdef ANDROID
|
|
2
|
+
#include "AudioDecoder.h"
|
|
2
3
|
#include "AudioPlayer.h"
|
|
3
4
|
#else
|
|
4
5
|
#include "IOSAudioDecoder.h"
|
|
@@ -24,6 +25,7 @@ namespace audioapi {
|
|
|
24
25
|
BaseAudioContext::BaseAudioContext() {
|
|
25
26
|
#ifdef ANDROID
|
|
26
27
|
audioPlayer_ = std::make_shared<AudioPlayer>(this->renderAudio());
|
|
28
|
+
audioDecoder_ = std::make_shared<AudioDecoder>(audioPlayer_->getSampleRate());
|
|
27
29
|
#else
|
|
28
30
|
audioPlayer_ = std::make_shared<IOSAudioPlayer>(this->renderAudio());
|
|
29
31
|
audioDecoder_ =
|
|
@@ -108,19 +110,20 @@ std::shared_ptr<PeriodicWave> BaseAudioContext::createPeriodicWave(
|
|
|
108
110
|
|
|
109
111
|
#ifdef ANDROID
|
|
110
112
|
std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioDataSource(
|
|
111
|
-
const std::string &
|
|
112
|
-
|
|
113
|
+
const std::string &path) {
|
|
114
|
+
auto audioBus = audioDecoder_->decodeWithFilePath(path);
|
|
115
|
+
return std::make_shared<AudioBuffer>(audioBus);
|
|
113
116
|
}
|
|
114
117
|
#else
|
|
115
118
|
std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioDataSource(
|
|
116
|
-
const std::string &
|
|
117
|
-
auto audioBus = audioDecoder_->decodeWithFilePath(
|
|
119
|
+
const std::string &path) {
|
|
120
|
+
auto audioBus = audioDecoder_->decodeWithFilePath(path);
|
|
118
121
|
return std::make_shared<AudioBuffer>(audioBus);
|
|
119
122
|
}
|
|
120
123
|
#endif
|
|
121
124
|
|
|
122
125
|
std::function<void(AudioBus *, int)> BaseAudioContext::renderAudio() {
|
|
123
|
-
if (
|
|
126
|
+
if (!isRunning()) {
|
|
124
127
|
return [](AudioBus *, int) {};
|
|
125
128
|
}
|
|
126
129
|
|