Skip to content

Commit b73b2b8

Browse files
Refactor/buffer source nodes (#986)
* refactor: implmented aligned audio array implementation * refactor: renamed includes from AudioArray.h to AudioArray.hpp * refactor: implemented AlignedAudioBuffer * refactor: renamed AudioBuffer.h to AudioBuffer.hpp and updated all includes accordingly * fix: nitpicks * refactor: integrated DSPAudioBuffer and DSPAudioArray into codebase * fix: nits * fix: nits * refactor: clean up buffer source nodes classes * ci: yarn format --------- Co-authored-by: maciejmakowski2003 <maciejmakowski2003@users.noreply.github.com>
1 parent 053a26c commit b73b2b8

9 files changed

Lines changed: 115 additions & 136 deletions

File tree

packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferBaseSourceNodeHostObject.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ namespace audioapi {
1313
AudioBufferBaseSourceNodeHostObject::AudioBufferBaseSourceNodeHostObject(
1414
const std::shared_ptr<AudioBufferBaseSourceNode> &node,
1515
const BaseAudioBufferSourceOptions &options)
16-
: AudioScheduledSourceNodeHostObject(node, options), pitchCorrection_(options.pitchCorrection) {
16+
: AudioScheduledSourceNodeHostObject(node, options),
17+
onPositionChangedInterval_(options.onPositionChangedInterval),
18+
pitchCorrection_(options.pitchCorrection) {
1719
auto sourceNode = std::static_pointer_cast<AudioBufferBaseSourceNode>(node_);
1820
detuneParam_ = std::make_shared<AudioParamHostObject>(sourceNode->getDetuneParam());
1921
playbackRateParam_ = std::make_shared<AudioParamHostObject>(sourceNode->getPlaybackRateParam());
20-
onPositionChangedInterval_ = sourceNode->getOnPositionChangedInterval();
2122

2223
addGetters(
2324
JSI_EXPORT_PROPERTY_GETTER(AudioBufferBaseSourceNodeHostObject, detune),
@@ -61,7 +62,6 @@ JSI_PROPERTY_SETTER_IMPL(AudioBufferBaseSourceNodeHostObject, onPositionChangedI
6162
auto sourceNode = std::static_pointer_cast<AudioBufferBaseSourceNode>(node_);
6263
auto interval = static_cast<int>(value.getNumber());
6364

64-
sourceNode->setOnPositionChangedInterval(static_cast<int>(value.getNumber()));
6565
auto event = [sourceNode, interval](BaseAudioContext &) {
6666
sourceNode->setOnPositionChangedInterval(interval);
6767
};
@@ -99,8 +99,11 @@ void AudioBufferBaseSourceNodeHostObject::initStretch(int channelCount, float sa
9999
outputLatency_ = std::max(
100100
dsp::sampleFrameToTime(stretch->outputLatency(), node_->getContextSampleRate()), 0.0);
101101

102-
auto event = [sourceNode, stretch](BaseAudioContext &) {
103-
sourceNode->initStretch(stretch);
102+
auto playbackRateBuffer =
103+
std::make_shared<DSPAudioBuffer>(3 * RENDER_QUANTUM_SIZE, channelCount, sampleRate);
104+
105+
auto event = [sourceNode, stretch, playbackRateBuffer](BaseAudioContext &) {
106+
sourceNode->initStretch(stretch, playbackRateBuffer);
104107
};
105108
sourceNode->scheduleAudioEvent(std::move(event));
106109
}

packages/react-native-audio-api/common/cpp/audioapi/HostObjects/sources/AudioBufferSourceNodeHostObject.cpp

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,10 @@ void AudioBufferSourceNodeHostObject::setBuffer(const std::shared_ptr<AudioBuffe
169169
auto audioBufferSourceNode = std::static_pointer_cast<AudioBufferSourceNode>(node_);
170170

171171
std::shared_ptr<AudioBuffer> copiedBuffer;
172-
std::shared_ptr<DSPAudioBuffer> playbackRateBuffer;
173172
std::shared_ptr<DSPAudioBuffer> audioBuffer;
174173

175174
if (buffer == nullptr) {
176175
copiedBuffer = nullptr;
177-
playbackRateBuffer = nullptr;
178176
audioBuffer = std::make_shared<DSPAudioBuffer>(
179177
RENDER_QUANTUM_SIZE, 1, audioBufferSourceNode->getContextSampleRate());
180178
} else {
@@ -191,20 +189,15 @@ void AudioBufferSourceNodeHostObject::setBuffer(const std::shared_ptr<AudioBuffe
191189
copiedBuffer = std::make_shared<AudioBuffer>(*buffer);
192190
}
193191

194-
playbackRateBuffer = std::make_shared<DSPAudioBuffer>(
195-
3 * RENDER_QUANTUM_SIZE,
196-
copiedBuffer->getNumberOfChannels(),
197-
audioBufferSourceNode->getContextSampleRate());
198192
audioBuffer = std::make_shared<DSPAudioBuffer>(
199193
RENDER_QUANTUM_SIZE,
200194
copiedBuffer->getNumberOfChannels(),
201195
audioBufferSourceNode->getContextSampleRate());
202196
}
203197

204-
auto event =
205-
[audioBufferSourceNode, copiedBuffer, playbackRateBuffer, audioBuffer](BaseAudioContext &) {
206-
audioBufferSourceNode->setBuffer(copiedBuffer, playbackRateBuffer, audioBuffer);
207-
};
198+
auto event = [audioBufferSourceNode, copiedBuffer, audioBuffer](BaseAudioContext &) {
199+
audioBufferSourceNode->setBuffer(copiedBuffer, audioBuffer);
200+
};
208201
audioBufferSourceNode->scheduleAudioEvent(std::move(event));
209202
}
210203

packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,8 @@ AudioBufferBaseSourceNode::AudioBufferBaseSourceNode(
1616
const std::shared_ptr<BaseAudioContext> &context,
1717
const BaseAudioBufferSourceOptions &options)
1818
: AudioScheduledSourceNode(context, options),
19+
vReadIndex_(0.0),
1920
pitchCorrection_(options.pitchCorrection),
20-
playbackRateBuffer_( // TODO refactor init
21-
std::make_shared<DSPAudioBuffer>(
22-
RENDER_QUANTUM_SIZE * 3,
23-
channelCount_,
24-
context->getSampleRate())),
2521
detuneParam_(
2622
std::make_shared<AudioParam>(
2723
options.detune,
@@ -33,13 +29,15 @@ AudioBufferBaseSourceNode::AudioBufferBaseSourceNode(
3329
options.playbackRate,
3430
MOST_NEGATIVE_SINGLE_FLOAT,
3531
MOST_POSITIVE_SINGLE_FLOAT,
36-
context)),
37-
vReadIndex_(0.0),
38-
onPositionChangedInterval_(static_cast<int>(context->getSampleRate() * 0.1)) {}
32+
context)) {
33+
setOnPositionChangedInterval(options.onPositionChangedInterval);
34+
}
3935

4036
void AudioBufferBaseSourceNode::initStretch(
41-
const std::shared_ptr<signalsmith::stretch::SignalsmithStretch<float>> &stretch) {
37+
const std::shared_ptr<signalsmith::stretch::SignalsmithStretch<float>> &stretch,
38+
const std::shared_ptr<DSPAudioBuffer> &playbackRateBuffer) {
4239
stretch_ = stretch;
40+
playbackRateBuffer_ = playbackRateBuffer;
4341
}
4442

4543
std::shared_ptr<AudioParam> AudioBufferBaseSourceNode::getDetuneParam() const {
@@ -55,29 +53,45 @@ void AudioBufferBaseSourceNode::setOnPositionChangedCallbackId(uint64_t callback
5553
}
5654

5755
void AudioBufferBaseSourceNode::setOnPositionChangedInterval(int interval) {
58-
onPositionChangedInterval_ =
56+
onPositionChangedIntervalInFrames_ =
5957
static_cast<int>(getContextSampleRate() * static_cast<float>(interval) / 1000);
6058
}
6159

62-
int AudioBufferBaseSourceNode::getOnPositionChangedInterval() const {
63-
return onPositionChangedInterval_;
64-
}
65-
6660
void AudioBufferBaseSourceNode::unregisterOnPositionChangedCallback(uint64_t callbackId) {
6761
audioEventHandlerRegistry_->unregisterHandler(AudioEvent::POSITION_CHANGED, callbackId);
6862
}
6963

64+
std::shared_ptr<DSPAudioBuffer> AudioBufferBaseSourceNode::processNode(
65+
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
66+
int framesToProcess) {
67+
if (isEmpty()) {
68+
processingBuffer->zero();
69+
return processingBuffer;
70+
}
71+
72+
if (!pitchCorrection_) {
73+
processWithoutPitchCorrection(processingBuffer, framesToProcess);
74+
} else {
75+
processWithPitchCorrection(processingBuffer, framesToProcess);
76+
}
77+
78+
handleStopScheduled();
79+
80+
return processingBuffer;
81+
}
82+
7083
void AudioBufferBaseSourceNode::sendOnPositionChangedEvent() {
71-
if (onPositionChangedCallbackId_ != 0 && onPositionChangedTime_ > onPositionChangedInterval_) {
84+
if (onPositionChangedCallbackId_ != 0 &&
85+
onPositionChangedTimeInFrames_ > onPositionChangedIntervalInFrames_) {
7286
std::unordered_map<std::string, EventValue> body = {{"value", getCurrentPosition()}};
7387

7488
audioEventHandlerRegistry_->invokeHandlerWithEventBody(
7589
AudioEvent::POSITION_CHANGED, onPositionChangedCallbackId_, body);
7690

77-
onPositionChangedTime_ = 0;
91+
onPositionChangedTimeInFrames_ = 0;
7892
}
7993

80-
onPositionChangedTime_ += RENDER_QUANTUM_SIZE;
94+
onPositionChangedTimeInFrames_ += RENDER_QUANTUM_SIZE;
8195
}
8296

8397
void AudioBufferBaseSourceNode::processWithPitchCorrection(
@@ -87,7 +101,7 @@ void AudioBufferBaseSourceNode::processWithPitchCorrection(
87101
size_t offsetLength = 0;
88102

89103
std::shared_ptr<BaseAudioContext> context = context_.lock();
90-
if (context == nullptr) {
104+
if (context == nullptr || playbackRateBuffer_ == nullptr) {
91105
processingBuffer->zero();
92106
return;
93107
}
@@ -140,8 +154,10 @@ void AudioBufferBaseSourceNode::processWithoutPitchCorrection(
140154
processingBuffer->zero();
141155
return;
142156
}
157+
143158
auto computedPlaybackRate =
144159
getComputedPlaybackRateValue(framesToProcess, context->getCurrentTime());
160+
145161
updatePlaybackInfo(
146162
processingBuffer,
147163
framesToProcess,

packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
1717
const std::shared_ptr<BaseAudioContext> &context,
1818
const BaseAudioBufferSourceOptions &options);
1919

20-
/// @note JS Thread only
21-
void initStretch(const std::shared_ptr<signalsmith::stretch::SignalsmithStretch<float>> &stretch);
20+
/// @note Audio Thread only
21+
void initStretch(
22+
const std::shared_ptr<signalsmith::stretch::SignalsmithStretch<float>> &stretch,
23+
const std::shared_ptr<DSPAudioBuffer> &playbackRateBuffer);
2224

2325
[[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
2426
[[nodiscard]] std::shared_ptr<AudioParam> getPlaybackRateParam() const;
@@ -29,31 +31,46 @@ class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
2931
/// @note Audio Thread only
3032
void setOnPositionChangedInterval(int interval);
3133

32-
/// TODO remove and refactor
33-
[[nodiscard]] int getOnPositionChangedInterval() const;
34-
3534
void unregisterOnPositionChangedCallback(uint64_t callbackId);
3635

3736
protected:
38-
// pitch correction
39-
const bool pitchCorrection_;
37+
// internal helper
38+
double vReadIndex_;
39+
40+
std::shared_ptr<DSPAudioBuffer> processNode(
41+
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
42+
int framesToProcess) final;
43+
44+
virtual double getCurrentPosition() const = 0;
45+
46+
virtual bool isEmpty() const = 0;
47+
48+
virtual void processWithoutInterpolation(
49+
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
50+
size_t startOffset,
51+
size_t offsetLength,
52+
float playbackRate) = 0;
53+
54+
virtual void processWithInterpolation(
55+
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
56+
size_t startOffset,
57+
size_t offsetLength,
58+
float playbackRate) = 0;
4059

41-
// pitch correction
60+
private:
61+
// pitch correction parameters
62+
// late init to avoid unnecessary allocation when pitch correction is not used.
63+
const bool pitchCorrection_;
4264
std::shared_ptr<signalsmith::stretch::SignalsmithStretch<float>> stretch_;
4365
std::shared_ptr<DSPAudioBuffer> playbackRateBuffer_;
4466

4567
// k-rate params
4668
const std::shared_ptr<AudioParam> detuneParam_;
4769
const std::shared_ptr<AudioParam> playbackRateParam_;
4870

49-
// internal helper
50-
double vReadIndex_;
51-
5271
uint64_t onPositionChangedCallbackId_ = 0; // 0 means no callback
53-
int onPositionChangedInterval_;
54-
int onPositionChangedTime_ = 0;
55-
56-
virtual double getCurrentPosition() const = 0;
72+
int onPositionChangedIntervalInFrames_;
73+
int onPositionChangedTimeInFrames_ = 0;
5774

5875
void sendOnPositionChangedEvent();
5976

@@ -65,18 +82,6 @@ class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
6582
int framesToProcess);
6683

6784
float getComputedPlaybackRateValue(int framesToProcess, double time);
68-
69-
virtual void processWithoutInterpolation(
70-
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
71-
size_t startOffset,
72-
size_t offsetLength,
73-
float playbackRate) = 0;
74-
75-
virtual void processWithInterpolation(
76-
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
77-
size_t startOffset,
78-
size_t offsetLength,
79-
float playbackRate) = 0;
8085
};
8186

8287
} // namespace audioapi

packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -132,26 +132,6 @@ void AudioBufferQueueSourceNode::unregisterOnBufferEndedCallback(uint64_t callba
132132
audioEventHandlerRegistry_->unregisterHandler(AudioEvent::BUFFER_ENDED, callbackId);
133133
}
134134

135-
std::shared_ptr<DSPAudioBuffer> AudioBufferQueueSourceNode::processNode(
136-
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
137-
int framesToProcess) {
138-
// no audio data to fill, zero the output and return.
139-
if (buffers_.empty()) {
140-
processingBuffer->zero();
141-
return processingBuffer;
142-
}
143-
144-
if (!pitchCorrection_) {
145-
processWithoutPitchCorrection(processingBuffer, framesToProcess);
146-
} else {
147-
processWithPitchCorrection(processingBuffer, framesToProcess);
148-
}
149-
150-
handleStopScheduled();
151-
152-
return processingBuffer;
153-
}
154-
155135
double AudioBufferQueueSourceNode::getCurrentPosition() const {
156136
return dsp::sampleFrameToTime(static_cast<int>(vReadIndex_), getContextSampleRate()) +
157137
playedBuffersDuration_;
@@ -171,6 +151,10 @@ void AudioBufferQueueSourceNode::sendOnBufferEndedEvent(size_t bufferId, bool is
171151
* Helper functions
172152
*/
173153

154+
bool AudioBufferQueueSourceNode::isEmpty() const {
155+
return buffers_.empty();
156+
}
157+
174158
void AudioBufferQueueSourceNode::processWithoutInterpolation(
175159
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
176160
size_t startOffset,
@@ -302,8 +286,8 @@ void AudioBufferQueueSourceNode::processWithInterpolation(
302286
break;
303287
}
304288

305-
context->getGraphManager()->addAudioBufferForDestruction(std::move(buffer));
306289
vReadIndex_ = vReadIndex_ - buffer->getSize();
290+
context->getGraphManager()->addAudioBufferForDestruction(std::move(buffer));
307291
data = buffers_.front();
308292
bufferId = data.first;
309293
buffer = data.second;

packages/react-native-audio-api/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,24 @@ class AudioBufferQueueSourceNode : public AudioBufferBaseSourceNode {
4848
void unregisterOnBufferEndedCallback(uint64_t callbackId);
4949

5050
protected:
51-
std::shared_ptr<DSPAudioBuffer> processNode(
52-
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
53-
int framesToProcess) override;
54-
5551
double getCurrentPosition() const override;
5652

5753
void sendOnBufferEndedEvent(size_t bufferId, bool isLastBufferInQueue);
5854

55+
bool isEmpty() const final;
56+
57+
void processWithoutInterpolation(
58+
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
59+
size_t startOffset,
60+
size_t offsetLength,
61+
float playbackRate) final;
62+
63+
void processWithInterpolation(
64+
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
65+
size_t startOffset,
66+
size_t offsetLength,
67+
float playbackRate) final;
68+
5969
private:
6070
// User provided buffers
6171
std::list<std::pair<size_t, std::shared_ptr<AudioBuffer>>> buffers_{};
@@ -67,18 +77,6 @@ class AudioBufferQueueSourceNode : public AudioBufferBaseSourceNode {
6777
double playedBuffersDuration_ = 0;
6878

6979
uint64_t onBufferEndedCallbackId_ = 0; // 0 means no callback
70-
71-
void processWithoutInterpolation(
72-
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
73-
size_t startOffset,
74-
size_t offsetLength,
75-
float playbackRate) override;
76-
77-
void processWithInterpolation(
78-
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
79-
size_t startOffset,
80-
size_t offsetLength,
81-
float playbackRate) override;
8280
};
8381

8482
} // namespace audioapi

0 commit comments

Comments
 (0)