react-native-audio-api 0.12.1 → 0.12.2
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 +8 -3
- package/RNAudioAPI.podspec +0 -2
- package/android/src/main/cpp/audioapi/CMakeLists.txt +8 -2
- package/android/src/main/cpp/audioapi/android/AudioAPIModule.cpp +7 -29
- package/android/src/main/cpp/audioapi/android/JniEventPayloadParser.cpp +83 -0
- package/android/src/main/cpp/audioapi/android/JniEventPayloadParser.h +14 -0
- package/android/src/main/cpp/audioapi/android/core/AndroidAudioRecorder.cpp +4 -3
- package/android/src/main/cpp/audioapi/android/core/AudioPlayer.cpp +1 -0
- package/android/src/main/cpp/audioapi/android/core/utils/AndroidRecorderCallback.cpp +37 -21
- package/android/src/main/cpp/audioapi/android/core/utils/AndroidRecorderCallback.h +1 -1
- package/common/cpp/audioapi/AudioAPIModuleInstaller.h +21 -0
- package/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.cpp +26 -4
- package/common/cpp/audioapi/HostObjects/sources/AudioBufferQueueSourceNodeHostObject.h +1 -0
- package/common/cpp/audioapi/HostObjects/sources/AudioFileSourceNodeHostObject.cpp +2 -2
- package/common/cpp/audioapi/HostObjects/utils/AudioDecoderHostObject.cpp +3 -3
- package/common/cpp/audioapi/HostObjects/utils/AudioFileUtilsHostObject.cpp +60 -0
- package/common/cpp/audioapi/HostObjects/utils/AudioFileUtilsHostObject.h +24 -0
- package/common/cpp/audioapi/HostObjects/utils/NodeOptionsParser.h +2 -2
- package/common/cpp/audioapi/core/OfflineAudioContext.cpp +0 -1
- package/common/cpp/audioapi/core/OfflineAudioContext.h +0 -1
- package/common/cpp/audioapi/core/effects/ConvolverNode.cpp +4 -10
- package/common/cpp/audioapi/core/effects/ConvolverNode.h +0 -4
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +13 -11
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +5 -9
- package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +47 -139
- package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h +11 -8
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +29 -114
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +6 -8
- package/common/cpp/audioapi/core/sources/AudioFileSourceNode.cpp +9 -11
- package/common/cpp/audioapi/core/sources/AudioFileSourceNode.h +1 -1
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +2 -2
- package/common/cpp/audioapi/core/types/AudioFormat.h +3 -1
- package/common/cpp/audioapi/core/utils/AudioDecoder.cpp +120 -91
- package/common/cpp/audioapi/core/utils/AudioDecoder.h +24 -101
- package/common/cpp/audioapi/core/utils/AudioFileConcatenator.cpp +862 -0
- package/common/cpp/audioapi/core/utils/AudioFileConcatenator.h +164 -0
- package/common/cpp/audioapi/core/utils/AudioFileWriter.cpp +2 -4
- package/common/cpp/audioapi/core/utils/AudioRecorderCallback.cpp +7 -12
- package/common/cpp/audioapi/core/utils/AudioRecorderCallback.h +2 -0
- package/common/cpp/audioapi/core/utils/buffer/BufferProcessingDirection.h +6 -0
- package/common/cpp/audioapi/core/utils/buffer/BufferProcessorBase.cpp +110 -0
- package/common/cpp/audioapi/core/utils/buffer/BufferProcessorBase.h +75 -0
- package/common/cpp/audioapi/core/utils/buffer/QueueBufferProcessor.cpp +129 -0
- package/common/cpp/audioapi/core/utils/buffer/QueueBufferProcessor.h +55 -0
- package/common/cpp/audioapi/core/utils/buffer/SingleBufferProcessor.cpp +95 -0
- package/common/cpp/audioapi/core/utils/buffer/SingleBufferProcessor.h +52 -0
- package/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp +65 -157
- package/common/cpp/audioapi/events/AudioEventHandlerRegistry.h +52 -33
- package/common/cpp/audioapi/events/AudioEventPayload.h +87 -0
- package/common/cpp/audioapi/events/IAudioEventHandlerRegistry.h +12 -12
- package/common/cpp/audioapi/libs/decoding/IncrementalAudioDecoder.h +12 -10
- package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp +152 -78
- package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.h +6 -6
- package/common/cpp/audioapi/libs/miniaudio/MiniAudioDecoding.cpp +34 -20
- package/common/cpp/audioapi/libs/miniaudio/MiniAudioDecoding.h +4 -4
- package/common/cpp/audioapi/utils/AudioArray.hpp +6 -1
- package/common/cpp/audioapi/utils/CrossThreadEventScheduler.hpp +1 -1
- package/common/cpp/audioapi/utils/TaskOffloader.hpp +3 -5
- package/ios/audioapi/ios/AudioAPIModule.h +2 -1
- package/ios/audioapi/ios/AudioAPIModule.mm +4 -25
- package/ios/audioapi/ios/core/IOSAudioPlayer.h +16 -2
- package/ios/audioapi/ios/core/IOSAudioPlayer.mm +90 -24
- package/ios/audioapi/ios/core/IOSAudioRecorder.mm +1 -1
- package/ios/audioapi/ios/core/utils/IOSRecorderCallback.mm +64 -20
- package/ios/audioapi/ios/system/AudioSessionManager.mm +18 -7
- package/ios/audioapi/ios/system/SystemNotificationManager.mm +22 -22
- package/ios/audioapi/ios/system/notification/PlaybackNotification.mm +10 -13
- package/lib/commonjs/AudioAPIModule/AudioAPIModule.js +1 -1
- package/lib/commonjs/AudioAPIModule/AudioAPIModule.js.map +1 -1
- package/lib/commonjs/api.js +8 -0
- package/lib/commonjs/api.js.map +1 -1
- package/lib/commonjs/api.web.js +5 -0
- package/lib/commonjs/api.web.js.map +1 -1
- package/lib/commonjs/core/AudioFileUtils.js +35 -0
- package/lib/commonjs/core/AudioFileUtils.js.map +1 -0
- package/lib/commonjs/mock/index.js +15 -1
- package/lib/commonjs/mock/index.js.map +1 -1
- package/lib/module/AudioAPIModule/AudioAPIModule.js +1 -1
- package/lib/module/AudioAPIModule/AudioAPIModule.js.map +1 -1
- package/lib/module/api.js +1 -0
- package/lib/module/api.js.map +1 -1
- package/lib/module/api.web.js +3 -0
- package/lib/module/api.web.js.map +1 -1
- package/lib/module/core/AudioFileUtils.js +31 -0
- package/lib/module/core/AudioFileUtils.js.map +1 -0
- package/lib/module/mock/index.js +14 -1
- package/lib/module/mock/index.js.map +1 -1
- package/lib/typescript/AudioAPIModule/AudioAPIModule.d.ts.map +1 -1
- package/lib/typescript/api.d.ts +1 -0
- package/lib/typescript/api.d.ts.map +1 -1
- package/lib/typescript/api.web.d.ts +1 -0
- package/lib/typescript/api.web.d.ts.map +1 -1
- package/lib/typescript/core/AudioFileUtils.d.ts +2 -0
- package/lib/typescript/core/AudioFileUtils.d.ts.map +1 -0
- package/lib/typescript/interfaces.d.ts +3 -0
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/lib/typescript/mock/index.d.ts +3 -1
- package/lib/typescript/mock/index.d.ts.map +1 -1
- package/package.json +3 -3
- package/scripts/download-prebuilt-binaries.sh +34 -1
- package/src/AudioAPIModule/AudioAPIModule.ts +1 -0
- package/src/AudioAPIModule/globals.d.ts +3 -0
- package/src/api.ts +1 -0
- package/src/api.web.ts +7 -0
- package/src/core/AudioFileUtils.ts +49 -0
- package/src/interfaces.ts +7 -0
- package/src/mock/index.ts +29 -0
|
@@ -41,10 +41,6 @@ class ConvolverNode : public AudioNode {
|
|
|
41
41
|
int framesToProcess) override;
|
|
42
42
|
|
|
43
43
|
private:
|
|
44
|
-
std::shared_ptr<DSPAudioBuffer> processInputs(
|
|
45
|
-
const std::shared_ptr<DSPAudioBuffer> &outputBuffer,
|
|
46
|
-
int framesToProcess,
|
|
47
|
-
bool checkIsAlreadyProcessed) override;
|
|
48
44
|
void onInputDisabled() override;
|
|
49
45
|
const float gainCalibrationSampleRate_;
|
|
50
46
|
size_t remainingSegments_;
|
|
@@ -8,8 +8,6 @@
|
|
|
8
8
|
|
|
9
9
|
#include <algorithm>
|
|
10
10
|
#include <memory>
|
|
11
|
-
#include <string>
|
|
12
|
-
#include <unordered_map>
|
|
13
11
|
|
|
14
12
|
namespace audioapi {
|
|
15
13
|
AudioBufferBaseSourceNode::AudioBufferBaseSourceNode(
|
|
@@ -85,10 +83,10 @@ std::shared_ptr<DSPAudioBuffer> AudioBufferBaseSourceNode::processNode(
|
|
|
85
83
|
void AudioBufferBaseSourceNode::sendOnPositionChangedEvent() {
|
|
86
84
|
if (onPositionChangedCallbackId_ != 0 &&
|
|
87
85
|
onPositionChangedTimeInFrames_ > onPositionChangedIntervalInFrames_) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
86
|
+
audioEventHandlerRegistry_->dispatchEvent(
|
|
87
|
+
AudioEvent::POSITION_CHANGED,
|
|
88
|
+
onPositionChangedCallbackId_,
|
|
89
|
+
DoubleValuePayload{.value = getCurrentPosition()});
|
|
92
90
|
|
|
93
91
|
onPositionChangedTimeInFrames_ = 0;
|
|
94
92
|
}
|
|
@@ -119,7 +117,8 @@ void AudioBufferBaseSourceNode::processWithPitchCorrection(
|
|
|
119
117
|
|
|
120
118
|
playbackRateBuffer_->zero();
|
|
121
119
|
|
|
122
|
-
auto framesNeededToStretch =
|
|
120
|
+
auto framesNeededToStretch =
|
|
121
|
+
std::abs(static_cast<int>(playbackRate * static_cast<float>(framesToProcess)));
|
|
123
122
|
|
|
124
123
|
updatePlaybackInfo(
|
|
125
124
|
playbackRateBuffer_,
|
|
@@ -134,7 +133,7 @@ void AudioBufferBaseSourceNode::processWithPitchCorrection(
|
|
|
134
133
|
return;
|
|
135
134
|
}
|
|
136
135
|
|
|
137
|
-
|
|
136
|
+
runBufferProcessor(playbackRateBuffer_, startOffset, offsetLength, playbackRate, false);
|
|
138
137
|
|
|
139
138
|
stretch_->process(
|
|
140
139
|
playbackRateBuffer_.get()[0],
|
|
@@ -178,16 +177,19 @@ void AudioBufferBaseSourceNode::processWithoutPitchCorrection(
|
|
|
178
177
|
}
|
|
179
178
|
|
|
180
179
|
if (std::fabs(computedPlaybackRate) == 1.0) {
|
|
181
|
-
|
|
180
|
+
runBufferProcessor(processingBuffer, startOffset, offsetLength, computedPlaybackRate, false);
|
|
182
181
|
} else {
|
|
183
|
-
|
|
182
|
+
runBufferProcessor(processingBuffer, startOffset, offsetLength, computedPlaybackRate, true);
|
|
184
183
|
}
|
|
185
184
|
|
|
186
185
|
sendOnPositionChangedEvent();
|
|
187
186
|
}
|
|
188
187
|
|
|
189
188
|
float AudioBufferBaseSourceNode::getComputedPlaybackRateValue(int framesToProcess, double time) {
|
|
190
|
-
auto playbackRate =
|
|
189
|
+
auto playbackRate = std::clamp(
|
|
190
|
+
playbackRateParam_->processKRateParam(framesToProcess, time),
|
|
191
|
+
MIN_PLAYBACK_RATE,
|
|
192
|
+
MAX_PLAYBACK_RATE);
|
|
191
193
|
auto detune = std::pow(
|
|
192
194
|
2.0f, //NOLINT(cppcoreguidelines-avoid-magic-numbers, readability-magic-numbers)
|
|
193
195
|
detuneParam_->processKRateParam(framesToProcess, time) / static_cast<float>(OCTAVE_RANGE));
|
|
@@ -45,17 +45,12 @@ class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
|
|
|
45
45
|
|
|
46
46
|
virtual bool isEmpty() const = 0;
|
|
47
47
|
|
|
48
|
-
virtual void
|
|
48
|
+
virtual void runBufferProcessor(
|
|
49
49
|
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
|
|
50
50
|
size_t startOffset,
|
|
51
51
|
size_t offsetLength,
|
|
52
|
-
float playbackRate
|
|
53
|
-
|
|
54
|
-
virtual void processWithInterpolation(
|
|
55
|
-
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
|
|
56
|
-
size_t startOffset,
|
|
57
|
-
size_t offsetLength,
|
|
58
|
-
float playbackRate) = 0;
|
|
52
|
+
float playbackRate,
|
|
53
|
+
bool interpolate) = 0;
|
|
59
54
|
|
|
60
55
|
private:
|
|
61
56
|
// pitch correction parameters
|
|
@@ -64,7 +59,7 @@ class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
|
|
|
64
59
|
std::shared_ptr<signalsmith::stretch::SignalsmithStretch<float>> stretch_;
|
|
65
60
|
std::shared_ptr<DSPAudioBuffer> playbackRateBuffer_;
|
|
66
61
|
static constexpr float MAX_PLAYBACK_RATE = 3.0f;
|
|
67
|
-
static constexpr float MIN_PLAYBACK_RATE =
|
|
62
|
+
static constexpr float MIN_PLAYBACK_RATE = -3.0f;
|
|
68
63
|
|
|
69
64
|
// k-rate params
|
|
70
65
|
const std::shared_ptr<AudioParam> detuneParam_;
|
|
@@ -79,6 +74,7 @@ class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
|
|
|
79
74
|
void processWithPitchCorrection(
|
|
80
75
|
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
|
|
81
76
|
int framesToProcess);
|
|
77
|
+
|
|
82
78
|
void processWithoutPitchCorrection(
|
|
83
79
|
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
|
|
84
80
|
int framesToProcess);
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
#include <audioapi/core/utils/AudioGraphManager.h>
|
|
5
5
|
#include <audioapi/core/utils/Constants.h>
|
|
6
6
|
#include <audioapi/core/utils/Locker.h>
|
|
7
|
+
#include <audioapi/core/utils/buffer/QueueBufferProcessor.h>
|
|
7
8
|
#include <audioapi/dsp/AudioUtils.hpp>
|
|
8
9
|
#include <audioapi/events/AudioEventHandlerRegistry.h>
|
|
9
10
|
#include <audioapi/types/NodeOptions.h>
|
|
@@ -11,8 +12,6 @@
|
|
|
11
12
|
|
|
12
13
|
#include <algorithm>
|
|
13
14
|
#include <memory>
|
|
14
|
-
#include <string>
|
|
15
|
-
#include <unordered_map>
|
|
16
15
|
#include <utility>
|
|
17
16
|
|
|
18
17
|
namespace audioapi {
|
|
@@ -28,6 +27,22 @@ AudioBufferQueueSourceNode::AudioBufferQueueSourceNode(
|
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
isInitialized_.store(true, std::memory_order_release);
|
|
30
|
+
|
|
31
|
+
auto graphManager = context->getGraphManager();
|
|
32
|
+
|
|
33
|
+
auto onBufferConsumed = [this, graphManager](
|
|
34
|
+
size_t bufferId,
|
|
35
|
+
std::shared_ptr<AudioBuffer> buffer,
|
|
36
|
+
bool isLastInQueue,
|
|
37
|
+
bool fireBufferEndedEvent) {
|
|
38
|
+
playedBuffersDuration_ += buffer->getDuration();
|
|
39
|
+
if (fireBufferEndedEvent) {
|
|
40
|
+
sendOnBufferEndedEvent(bufferId, isLastInQueue);
|
|
41
|
+
}
|
|
42
|
+
graphManager->addAudioBufferForDestruction(std::move(buffer));
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
processor_ = std::make_unique<QueueBufferProcessor>(&buffers_, onBufferConsumed);
|
|
31
46
|
}
|
|
32
47
|
|
|
33
48
|
void AudioBufferQueueSourceNode::stop(double when) {
|
|
@@ -132,6 +147,14 @@ void AudioBufferQueueSourceNode::unregisterOnBufferEndedCallback(uint64_t callba
|
|
|
132
147
|
audioEventHandlerRegistry_->unregisterHandler(AudioEvent::BUFFER_ENDED, callbackId);
|
|
133
148
|
}
|
|
134
149
|
|
|
150
|
+
void AudioBufferQueueSourceNode::setChannelCount(int channelCount) {
|
|
151
|
+
if (channelCount_ != channelCount) {
|
|
152
|
+
channelCount_ = channelCount;
|
|
153
|
+
audioBuffer_ = std::make_shared<DSPAudioBuffer>(
|
|
154
|
+
RENDER_QUANTUM_SIZE, channelCount_, getContextSampleRate());
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
135
158
|
double AudioBufferQueueSourceNode::getCurrentPosition() const {
|
|
136
159
|
return dsp::sampleFrameToTime(static_cast<int>(vReadIndex_), getContextSampleRate()) +
|
|
137
160
|
playedBuffersDuration_;
|
|
@@ -139,11 +162,10 @@ double AudioBufferQueueSourceNode::getCurrentPosition() const {
|
|
|
139
162
|
|
|
140
163
|
void AudioBufferQueueSourceNode::sendOnBufferEndedEvent(size_t bufferId, bool isLastBufferInQueue) {
|
|
141
164
|
if (onBufferEndedCallbackId_ != 0) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
AudioEvent::BUFFER_ENDED, onBufferEndedCallbackId_, body);
|
|
165
|
+
audioEventHandlerRegistry_->dispatchEvent(
|
|
166
|
+
AudioEvent::BUFFER_ENDED,
|
|
167
|
+
onBufferEndedCallbackId_,
|
|
168
|
+
BufferEndedPayload{.bufferId = bufferId, .isLastBufferInQueue = isLastBufferInQueue});
|
|
147
169
|
}
|
|
148
170
|
}
|
|
149
171
|
|
|
@@ -155,147 +177,33 @@ bool AudioBufferQueueSourceNode::isEmpty() const {
|
|
|
155
177
|
return buffers_.empty();
|
|
156
178
|
}
|
|
157
179
|
|
|
158
|
-
|
|
159
|
-
void AudioBufferQueueSourceNode::processWithoutInterpolation(
|
|
180
|
+
void AudioBufferQueueSourceNode::runBufferProcessor(
|
|
160
181
|
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
|
|
161
182
|
size_t startOffset,
|
|
162
183
|
size_t offsetLength,
|
|
163
|
-
float playbackRate
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
auto data = buffers_.front();
|
|
169
|
-
auto bufferId = data.first;
|
|
170
|
-
auto buffer = data.second;
|
|
171
|
-
|
|
172
|
-
size_t framesLeft = offsetLength;
|
|
173
|
-
|
|
174
|
-
while (framesLeft > 0) {
|
|
175
|
-
size_t framesToEnd = buffer->getSize() - readIndex;
|
|
176
|
-
size_t framesToCopy = std::min(framesToEnd, framesLeft);
|
|
177
|
-
framesToCopy = framesToCopy > 0 ? framesToCopy : 0;
|
|
178
|
-
|
|
179
|
-
assert(readIndex >= 0);
|
|
180
|
-
assert(writeIndex >= 0);
|
|
181
|
-
assert(readIndex + framesToCopy <= buffer->getSize());
|
|
182
|
-
assert(writeIndex + framesToCopy <= processingBuffer->getSize());
|
|
183
|
-
|
|
184
|
-
processingBuffer->copy(*buffer, readIndex, writeIndex, framesToCopy);
|
|
185
|
-
|
|
186
|
-
writeIndex += framesToCopy;
|
|
187
|
-
readIndex += framesToCopy;
|
|
188
|
-
framesLeft -= framesToCopy;
|
|
189
|
-
|
|
190
|
-
if (readIndex >= buffer->getSize()) {
|
|
191
|
-
playedBuffersDuration_ += buffer->getDuration();
|
|
192
|
-
buffers_.pop_front();
|
|
193
|
-
|
|
194
|
-
if (!(buffers_.empty() && addExtraTailFrames_)) {
|
|
195
|
-
sendOnBufferEndedEvent(bufferId, buffers_.empty());
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (buffers_.empty()) {
|
|
199
|
-
if (addExtraTailFrames_) {
|
|
200
|
-
buffers_.emplace_back(bufferId, tailBuffer_);
|
|
201
|
-
addExtraTailFrames_ = false;
|
|
202
|
-
} else {
|
|
203
|
-
context->getGraphManager()->addAudioBufferForDestruction(std::move(buffer));
|
|
204
|
-
processingBuffer->zero(writeIndex, framesLeft);
|
|
205
|
-
readIndex = 0;
|
|
206
|
-
|
|
207
|
-
break;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
context->getGraphManager()->addAudioBufferForDestruction(std::move(buffer));
|
|
212
|
-
data = buffers_.front();
|
|
213
|
-
bufferId = data.first;
|
|
214
|
-
buffer = data.second;
|
|
215
|
-
readIndex = 0;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
184
|
+
float playbackRate,
|
|
185
|
+
bool interpolate) {
|
|
186
|
+
if (!processingBuffer) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
218
189
|
|
|
219
|
-
|
|
220
|
-
|
|
190
|
+
if (buffers_.empty()) {
|
|
191
|
+
processingBuffer->zero(startOffset, offsetLength);
|
|
192
|
+
return;
|
|
221
193
|
}
|
|
222
|
-
}
|
|
223
194
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
size_t startOffset,
|
|
228
|
-
size_t offsetLength,
|
|
229
|
-
float playbackRate) {
|
|
230
|
-
if (auto context = context_.lock()) {
|
|
231
|
-
size_t writeIndex = startOffset;
|
|
232
|
-
size_t framesLeft = offsetLength;
|
|
233
|
-
|
|
234
|
-
auto data = buffers_.front();
|
|
235
|
-
auto bufferId = data.first;
|
|
236
|
-
auto buffer = data.second;
|
|
237
|
-
|
|
238
|
-
while (framesLeft > 0) {
|
|
239
|
-
auto readIndex = static_cast<size_t>(vReadIndex_);
|
|
240
|
-
size_t nextReadIndex = readIndex + 1;
|
|
241
|
-
auto factor = static_cast<float>(vReadIndex_ - static_cast<double>(readIndex));
|
|
242
|
-
|
|
243
|
-
bool crossBufferInterpolation = false;
|
|
244
|
-
std::shared_ptr<AudioBuffer> nextBuffer = nullptr;
|
|
245
|
-
|
|
246
|
-
if (nextReadIndex >= buffer->getSize()) {
|
|
247
|
-
if (buffers_.size() > 1) {
|
|
248
|
-
auto tempQueue = buffers_;
|
|
249
|
-
tempQueue.pop_front();
|
|
250
|
-
nextBuffer = tempQueue.front().second;
|
|
251
|
-
nextReadIndex = 0;
|
|
252
|
-
crossBufferInterpolation = true;
|
|
253
|
-
} else {
|
|
254
|
-
nextReadIndex = readIndex;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
195
|
+
if (addExtraTailFrames_ && tailBuffer_ != nullptr) {
|
|
196
|
+
processor_->setPendingTail(tailBuffer_);
|
|
197
|
+
}
|
|
257
198
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const auto currentSource = buffer->getChannel(i)->span();
|
|
261
|
-
|
|
262
|
-
if (crossBufferInterpolation) {
|
|
263
|
-
const auto nextSource = nextBuffer->getChannel(i)->span();
|
|
264
|
-
float currentSample = currentSource[readIndex];
|
|
265
|
-
float nextSample = nextSource[nextReadIndex];
|
|
266
|
-
destination[writeIndex] = currentSample + factor * (nextSample - currentSample);
|
|
267
|
-
} else {
|
|
268
|
-
destination[writeIndex] =
|
|
269
|
-
dsp::linearInterpolate(currentSource, readIndex, nextReadIndex, factor);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
199
|
+
processor_->setPosition(vReadIndex_);
|
|
200
|
+
processor_->process(processingBuffer, startOffset, offsetLength, playbackRate, interpolate);
|
|
272
201
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
vReadIndex_ += std::abs(playbackRate);
|
|
276
|
-
framesLeft -= 1;
|
|
277
|
-
|
|
278
|
-
if (vReadIndex_ >= static_cast<double>(buffer->getSize())) {
|
|
279
|
-
playedBuffersDuration_ += buffer->getDuration();
|
|
280
|
-
buffers_.pop_front();
|
|
281
|
-
|
|
282
|
-
sendOnBufferEndedEvent(bufferId, buffers_.empty());
|
|
283
|
-
|
|
284
|
-
if (buffers_.empty()) {
|
|
285
|
-
context->getGraphManager()->addAudioBufferForDestruction(std::move(buffer));
|
|
286
|
-
processingBuffer->zero(writeIndex, framesLeft);
|
|
287
|
-
vReadIndex_ = 0.0;
|
|
288
|
-
break;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
vReadIndex_ = vReadIndex_ - static_cast<double>(buffer->getSize());
|
|
292
|
-
context->getGraphManager()->addAudioBufferForDestruction(std::move(buffer));
|
|
293
|
-
data = buffers_.front();
|
|
294
|
-
bufferId = data.first;
|
|
295
|
-
buffer = data.second;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
202
|
+
if (processor_->didConsumeTail()) {
|
|
203
|
+
addExtraTailFrames_ = false;
|
|
298
204
|
}
|
|
205
|
+
|
|
206
|
+
vReadIndex_ = processor_->getPosition();
|
|
299
207
|
}
|
|
300
208
|
|
|
301
209
|
} // namespace audioapi
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
#include <cstddef>
|
|
9
9
|
#include <list>
|
|
10
10
|
#include <memory>
|
|
11
|
+
#include "audioapi/core/utils/buffer/QueueBufferProcessor.h"
|
|
11
12
|
|
|
12
13
|
namespace audioapi {
|
|
13
14
|
|
|
@@ -48,6 +49,11 @@ class AudioBufferQueueSourceNode : public AudioBufferBaseSourceNode {
|
|
|
48
49
|
|
|
49
50
|
void unregisterOnBufferEndedCallback(uint64_t callbackId);
|
|
50
51
|
|
|
52
|
+
/// @brief Set the channel count of the node. Channel count is set only once when the first buffer is enqueued.
|
|
53
|
+
/// @param channelCount The channel count to set.
|
|
54
|
+
/// @note Audio Thread only
|
|
55
|
+
void setChannelCount(int channelCount);
|
|
56
|
+
|
|
51
57
|
protected:
|
|
52
58
|
double getCurrentPosition() const override;
|
|
53
59
|
|
|
@@ -55,17 +61,12 @@ class AudioBufferQueueSourceNode : public AudioBufferBaseSourceNode {
|
|
|
55
61
|
|
|
56
62
|
bool isEmpty() const final;
|
|
57
63
|
|
|
58
|
-
void
|
|
64
|
+
void runBufferProcessor(
|
|
59
65
|
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
|
|
60
66
|
size_t startOffset,
|
|
61
67
|
size_t offsetLength,
|
|
62
|
-
float playbackRate
|
|
63
|
-
|
|
64
|
-
void processWithInterpolation(
|
|
65
|
-
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
|
|
66
|
-
size_t startOffset,
|
|
67
|
-
size_t offsetLength,
|
|
68
|
-
float playbackRate) final;
|
|
68
|
+
float playbackRate,
|
|
69
|
+
bool interpolate) final;
|
|
69
70
|
|
|
70
71
|
private:
|
|
71
72
|
// User provided buffers
|
|
@@ -78,6 +79,8 @@ class AudioBufferQueueSourceNode : public AudioBufferBaseSourceNode {
|
|
|
78
79
|
double playedBuffersDuration_ = 0;
|
|
79
80
|
|
|
80
81
|
uint64_t onBufferEndedCallbackId_ = 0; // 0 means no callback
|
|
82
|
+
|
|
83
|
+
std::unique_ptr<QueueBufferProcessor> processor_;
|
|
81
84
|
};
|
|
82
85
|
|
|
83
86
|
} // namespace audioapi
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
#include <audioapi/types/NodeOptions.h>
|
|
10
10
|
#include <audioapi/utils/AudioArray.hpp>
|
|
11
11
|
|
|
12
|
+
#include <audioapi/core/utils/buffer/SingleBufferProcessor.h>
|
|
12
13
|
#include <algorithm>
|
|
14
|
+
#include <cstddef>
|
|
13
15
|
#include <memory>
|
|
14
16
|
#include <utility>
|
|
15
17
|
|
|
@@ -23,11 +25,13 @@ AudioBufferSourceNode::AudioBufferSourceNode(
|
|
|
23
25
|
loopSkip_(options.loopSkip),
|
|
24
26
|
loopStart_(options.loopStart),
|
|
25
27
|
loopEnd_(options.loopEnd) {
|
|
28
|
+
processor_ = std::make_unique<SingleBufferProcessor>();
|
|
26
29
|
isInitialized_.store(true, std::memory_order_release);
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
void AudioBufferSourceNode::setLoop(bool loop) {
|
|
30
33
|
loop_ = loop;
|
|
34
|
+
processor_->setLoop(loop_);
|
|
31
35
|
}
|
|
32
36
|
|
|
33
37
|
void AudioBufferSourceNode::setLoopSkip(bool loopSkip) {
|
|
@@ -67,6 +71,7 @@ void AudioBufferSourceNode::setBuffer(
|
|
|
67
71
|
channelCount_ = 1;
|
|
68
72
|
|
|
69
73
|
buffer_ = nullptr;
|
|
74
|
+
processor_->setBuffer(nullptr);
|
|
70
75
|
return;
|
|
71
76
|
}
|
|
72
77
|
|
|
@@ -74,6 +79,7 @@ void AudioBufferSourceNode::setBuffer(
|
|
|
74
79
|
audioBuffer_ = audioBuffer;
|
|
75
80
|
channelCount_ = static_cast<int>(buffer_->getNumberOfChannels());
|
|
76
81
|
loopEnd_ = buffer_->getDuration();
|
|
82
|
+
processor_->setBuffer(buffer_);
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
void AudioBufferSourceNode::start(double when, double offset, double duration) {
|
|
@@ -114,8 +120,8 @@ double AudioBufferSourceNode::getCurrentPosition() const {
|
|
|
114
120
|
|
|
115
121
|
void AudioBufferSourceNode::sendOnLoopEndedEvent() {
|
|
116
122
|
if (onLoopEndedCallbackId_ != 0) {
|
|
117
|
-
audioEventHandlerRegistry_->
|
|
118
|
-
AudioEvent::LOOP_ENDED, onLoopEndedCallbackId_, {});
|
|
123
|
+
audioEventHandlerRegistry_->dispatchEvent(
|
|
124
|
+
AudioEvent::LOOP_ENDED, onLoopEndedCallbackId_, EmptyPayload{});
|
|
119
125
|
}
|
|
120
126
|
}
|
|
121
127
|
|
|
@@ -127,129 +133,38 @@ bool AudioBufferSourceNode::isEmpty() const {
|
|
|
127
133
|
return buffer_ == nullptr;
|
|
128
134
|
}
|
|
129
135
|
|
|
130
|
-
|
|
131
|
-
void AudioBufferSourceNode::processWithoutInterpolation(
|
|
136
|
+
void AudioBufferSourceNode::runBufferProcessor(
|
|
132
137
|
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
|
|
133
138
|
size_t startOffset,
|
|
134
139
|
size_t offsetLength,
|
|
135
|
-
float playbackRate
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
size_t writeIndex = startOffset;
|
|
140
|
-
|
|
141
|
-
auto frameStart = static_cast<size_t>(getVirtualStartFrame(getContextSampleRate()));
|
|
142
|
-
auto frameEnd = static_cast<size_t>(getVirtualEndFrame(getContextSampleRate()));
|
|
143
|
-
size_t frameDelta = frameEnd - frameStart;
|
|
144
|
-
|
|
145
|
-
size_t framesLeft = offsetLength;
|
|
146
|
-
|
|
147
|
-
// if we are moving towards loop, we do nothing because we will achieve it
|
|
148
|
-
// otherwise, we wrap to the start of the loop if necessary
|
|
149
|
-
if (loop_ &&
|
|
150
|
-
((readIndex >= frameEnd && direction == 1) || (readIndex < frameStart && direction == -1))) {
|
|
151
|
-
readIndex = frameStart +
|
|
152
|
-
(static_cast<int64_t>(readIndex) - static_cast<int64_t>(frameStart)) % frameDelta;
|
|
140
|
+
float playbackRate,
|
|
141
|
+
bool interpolate) {
|
|
142
|
+
if (!processingBuffer) {
|
|
143
|
+
return;
|
|
153
144
|
}
|
|
154
145
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
framesToCopy = framesToCopy > 0 ? framesToCopy : 0;
|
|
159
|
-
|
|
160
|
-
assert(readIndex >= 0);
|
|
161
|
-
assert(writeIndex >= 0);
|
|
162
|
-
assert(readIndex + framesToCopy <= buffer_->getSize());
|
|
163
|
-
assert(writeIndex + framesToCopy <= processingBuffer->getSize());
|
|
164
|
-
|
|
165
|
-
// Direction is forward, we can normally copy the data
|
|
166
|
-
if (direction == 1) {
|
|
167
|
-
processingBuffer->copy(*buffer_, readIndex, writeIndex, framesToCopy);
|
|
168
|
-
} else {
|
|
169
|
-
for (size_t ch = 0; ch < processingBuffer->getNumberOfChannels(); ch += 1) {
|
|
170
|
-
processingBuffer->getChannel(ch)->copyReverse(
|
|
171
|
-
*buffer_->getChannel(ch), readIndex, writeIndex, framesToCopy);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
writeIndex += framesToCopy;
|
|
176
|
-
readIndex += framesToCopy * direction;
|
|
177
|
-
framesLeft -= framesToCopy;
|
|
178
|
-
|
|
179
|
-
// if we are moving towards loop, we do nothing because we will achieve it
|
|
180
|
-
// otherwise, we wrap to the start of the loop if necessary
|
|
181
|
-
if ((readIndex >= frameEnd && direction == 1) || (readIndex < frameStart && direction == -1)) {
|
|
182
|
-
readIndex -= direction * frameDelta;
|
|
146
|
+
const float sampleRate = getContextSampleRate();
|
|
147
|
+
const double startFrame = getVirtualStartFrame(sampleRate);
|
|
148
|
+
const double endFrame = getVirtualEndFrame(sampleRate);
|
|
183
149
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
sendOnLoopEndedEvent();
|
|
191
|
-
}
|
|
150
|
+
// start(when, offset=duration) sets vReadIndex_ to endFrame, so clamp it
|
|
151
|
+
if (playbackRate < 0 && vReadIndex_ >= endFrame && endFrame > startFrame) {
|
|
152
|
+
vReadIndex_ = endFrame - 1.0;
|
|
192
153
|
}
|
|
193
154
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
void AudioBufferSourceNode::processWithInterpolation(
|
|
199
|
-
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
|
|
200
|
-
size_t startOffset,
|
|
201
|
-
size_t offsetLength,
|
|
202
|
-
float playbackRate) {
|
|
203
|
-
size_t direction = playbackRate < 0.0f ? -1 : 1;
|
|
204
|
-
|
|
205
|
-
size_t writeIndex = startOffset;
|
|
155
|
+
processor_->setPosition(vReadIndex_);
|
|
156
|
+
processor_->setEndFrame(static_cast<size_t>(endFrame));
|
|
157
|
+
processor_->setStartFrame(static_cast<size_t>(startFrame));
|
|
158
|
+
processor_->process(processingBuffer, startOffset, offsetLength, playbackRate, interpolate);
|
|
206
159
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
auto frameStart = static_cast<size_t>(vFrameStart);
|
|
212
|
-
auto frameEnd = static_cast<size_t>(vFrameEnd);
|
|
213
|
-
|
|
214
|
-
size_t framesLeft = offsetLength;
|
|
215
|
-
|
|
216
|
-
// Wrap to the start of the loop if necessary
|
|
217
|
-
if (loop_ && (vReadIndex_ >= vFrameEnd || vReadIndex_ < vFrameStart)) {
|
|
218
|
-
vReadIndex_ = vFrameStart + std::fmod(vReadIndex_ - vFrameStart, vFrameDelta);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
while (framesLeft > 0) {
|
|
222
|
-
auto readIndex = static_cast<size_t>(vReadIndex_);
|
|
223
|
-
size_t nextReadIndex = readIndex + 1;
|
|
224
|
-
auto factor = static_cast<float>(vReadIndex_ - static_cast<double>(readIndex));
|
|
225
|
-
|
|
226
|
-
if (nextReadIndex >= frameEnd) {
|
|
227
|
-
nextReadIndex = loop_ ? frameStart : readIndex;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
for (size_t i = 0; i < processingBuffer->getNumberOfChannels(); i++) {
|
|
231
|
-
auto destination = processingBuffer->getChannel(i)->span();
|
|
232
|
-
const auto source = buffer_->getChannel(i)->span();
|
|
233
|
-
|
|
234
|
-
destination[writeIndex] = dsp::linearInterpolate(source, readIndex, nextReadIndex, factor);
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
writeIndex += 1;
|
|
238
|
-
vReadIndex_ += playbackRate * static_cast<double>(direction);
|
|
239
|
-
framesLeft -= 1;
|
|
240
|
-
|
|
241
|
-
if (vReadIndex_ < vFrameStart || vReadIndex_ >= vFrameEnd) {
|
|
242
|
-
vReadIndex_ -= static_cast<double>(direction) * vFrameDelta;
|
|
243
|
-
|
|
244
|
-
if (!loop_) {
|
|
245
|
-
processingBuffer->zero(writeIndex, framesLeft);
|
|
246
|
-
playbackState_ = PlaybackState::STOP_SCHEDULED;
|
|
247
|
-
break;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
sendOnLoopEndedEvent();
|
|
160
|
+
if (processor_->atBoundary()) {
|
|
161
|
+
if (processor_->shouldStop()) {
|
|
162
|
+
playbackState_ = PlaybackState::STOP_SCHEDULED;
|
|
251
163
|
}
|
|
164
|
+
sendOnLoopEndedEvent();
|
|
252
165
|
}
|
|
166
|
+
|
|
167
|
+
vReadIndex_ = processor_->getPosition();
|
|
253
168
|
}
|
|
254
169
|
|
|
255
170
|
double AudioBufferSourceNode::getVirtualStartFrame(float sampleRate) const {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
#include <audioapi/libs/signalsmith-stretch/signalsmith-stretch.h>
|
|
5
5
|
#include <audioapi/utils/AudioBuffer.hpp>
|
|
6
6
|
|
|
7
|
+
#include <audioapi/core/utils/buffer/SingleBufferProcessor.h>
|
|
7
8
|
#include <cstddef>
|
|
8
9
|
#include <memory>
|
|
9
10
|
|
|
@@ -52,17 +53,12 @@ class AudioBufferSourceNode : public AudioBufferBaseSourceNode {
|
|
|
52
53
|
|
|
53
54
|
bool isEmpty() const final;
|
|
54
55
|
|
|
55
|
-
void
|
|
56
|
+
void runBufferProcessor(
|
|
56
57
|
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
|
|
57
58
|
size_t startOffset,
|
|
58
59
|
size_t offsetLength,
|
|
59
|
-
float playbackRate
|
|
60
|
-
|
|
61
|
-
void processWithInterpolation(
|
|
62
|
-
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
|
|
63
|
-
size_t startOffset,
|
|
64
|
-
size_t offsetLength,
|
|
65
|
-
float playbackRate) final;
|
|
60
|
+
float playbackRate,
|
|
61
|
+
bool interpolate) final;
|
|
66
62
|
|
|
67
63
|
private:
|
|
68
64
|
// Looping related properties
|
|
@@ -79,6 +75,8 @@ class AudioBufferSourceNode : public AudioBufferBaseSourceNode {
|
|
|
79
75
|
|
|
80
76
|
double getVirtualStartFrame(float sampleRate) const;
|
|
81
77
|
double getVirtualEndFrame(float sampleRate);
|
|
78
|
+
|
|
79
|
+
std::unique_ptr<SingleBufferProcessor> processor_;
|
|
82
80
|
};
|
|
83
81
|
|
|
84
82
|
} // namespace audioapi
|