Skip to content

Commit 92b9b3c

Browse files
Merge branch 'main' into feat/graph_refactor_2
2 parents 52d274d + b73b2b8 commit 92b9b3c

11 files changed

Lines changed: 138 additions & 140 deletions

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/AudioParam.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ void AudioParam::exponentialRampToValueAtTime(float value, double endTime) {
115115
// Exponential curve function using power law
116116
auto calculateValue =
117117
[](double startTime, double endTime, float startValue, float endValue, double time) {
118+
if (startValue * endValue < 0 || startValue == 0) {
119+
return startValue;
120+
}
121+
118122
if (time < startTime) {
119123
return startValue;
120124
}
@@ -143,6 +147,10 @@ void AudioParam::setTargetAtTime(float target, double startTime, double timeCons
143147
// Exponential decay function towards target value
144148
auto calculateValue = [timeConstant, target](
145149
double startTime, double, float startValue, float, double time) {
150+
if (timeConstant == 0) {
151+
return target;
152+
}
153+
146154
if (time < startTime) {
147155
return startValue;
148156
}

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

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,15 @@
1010
#include <memory>
1111
#include <string>
1212
#include <unordered_map>
13+
#include <utility>
1314

1415
namespace audioapi {
1516
AudioBufferBaseSourceNode::AudioBufferBaseSourceNode(
1617
const std::shared_ptr<BaseAudioContext> &context,
1718
const BaseAudioBufferSourceOptions &options)
1819
: AudioScheduledSourceNode(context, options),
20+
vReadIndex_(0.0),
1921
pitchCorrection_(options.pitchCorrection),
20-
playbackRateBuffer_( // TODO refactor init
21-
std::make_shared<DSPAudioBuffer>(
22-
RENDER_QUANTUM_SIZE * 3,
23-
channelCount_,
24-
context->getSampleRate())),
2522
detuneParam_(
2623
std::make_shared<AudioParam>(
2724
options.detune,
@@ -33,13 +30,25 @@ AudioBufferBaseSourceNode::AudioBufferBaseSourceNode(
3330
options.playbackRate,
3431
MOST_NEGATIVE_SINGLE_FLOAT,
3532
MOST_POSITIVE_SINGLE_FLOAT,
36-
context)),
37-
vReadIndex_(0.0),
38-
onPositionChangedInterval_(static_cast<int>(context->getSampleRate() * 0.1)) {}
33+
context)) {
34+
setOnPositionChangedInterval(options.onPositionChangedInterval);
35+
}
3936

4037
void AudioBufferBaseSourceNode::initStretch(
41-
const std::shared_ptr<signalsmith::stretch::SignalsmithStretch<float>> &stretch) {
42-
stretch_ = stretch;
38+
const std::shared_ptr<signalsmith::stretch::SignalsmithStretch<float>> &stretch,
39+
const std::shared_ptr<DSPAudioBuffer> &playbackRateBuffer) {
40+
if (auto context = context_.lock()) {
41+
if (playbackRateBuffer_ != nullptr) {
42+
context->getDisposer()->dispose(std::move(playbackRateBuffer_));
43+
}
44+
45+
if (stretch_ != nullptr) {
46+
context->getDisposer()->dispose(std::move(stretch_));
47+
}
48+
49+
stretch_ = stretch;
50+
playbackRateBuffer_ = playbackRateBuffer;
51+
}
4352
}
4453

4554
std::shared_ptr<AudioParam> AudioBufferBaseSourceNode::getDetuneParam() const {
@@ -55,29 +64,45 @@ void AudioBufferBaseSourceNode::setOnPositionChangedCallbackId(uint64_t callback
5564
}
5665

5766
void AudioBufferBaseSourceNode::setOnPositionChangedInterval(int interval) {
58-
onPositionChangedInterval_ =
67+
onPositionChangedIntervalInFrames_ =
5968
static_cast<int>(getContextSampleRate() * static_cast<float>(interval) / 1000);
6069
}
6170

62-
int AudioBufferBaseSourceNode::getOnPositionChangedInterval() const {
63-
return onPositionChangedInterval_;
64-
}
65-
6671
void AudioBufferBaseSourceNode::unregisterOnPositionChangedCallback(uint64_t callbackId) {
6772
audioEventHandlerRegistry_->unregisterHandler(AudioEvent::POSITION_CHANGED, callbackId);
6873
}
6974

75+
std::shared_ptr<DSPAudioBuffer> AudioBufferBaseSourceNode::processNode(
76+
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
77+
int framesToProcess) {
78+
if (isEmpty()) {
79+
processingBuffer->zero();
80+
return processingBuffer;
81+
}
82+
83+
if (!pitchCorrection_) {
84+
processWithoutPitchCorrection(processingBuffer, framesToProcess);
85+
} else {
86+
processWithPitchCorrection(processingBuffer, framesToProcess);
87+
}
88+
89+
handleStopScheduled();
90+
91+
return processingBuffer;
92+
}
93+
7094
void AudioBufferBaseSourceNode::sendOnPositionChangedEvent() {
71-
if (onPositionChangedCallbackId_ != 0 && onPositionChangedTime_ > onPositionChangedInterval_) {
95+
if (onPositionChangedCallbackId_ != 0 &&
96+
onPositionChangedTimeInFrames_ > onPositionChangedIntervalInFrames_) {
7297
std::unordered_map<std::string, EventValue> body = {{"value", getCurrentPosition()}};
7398

7499
audioEventHandlerRegistry_->invokeHandlerWithEventBody(
75100
AudioEvent::POSITION_CHANGED, onPositionChangedCallbackId_, body);
76101

77-
onPositionChangedTime_ = 0;
102+
onPositionChangedTimeInFrames_ = 0;
78103
}
79104

80-
onPositionChangedTime_ += RENDER_QUANTUM_SIZE;
105+
onPositionChangedTimeInFrames_ += RENDER_QUANTUM_SIZE;
81106
}
82107

83108
void AudioBufferBaseSourceNode::processWithPitchCorrection(
@@ -87,7 +112,7 @@ void AudioBufferBaseSourceNode::processWithPitchCorrection(
87112
size_t offsetLength = 0;
88113

89114
std::shared_ptr<BaseAudioContext> context = context_.lock();
90-
if (context == nullptr) {
115+
if (context == nullptr || playbackRateBuffer_ == nullptr) {
91116
processingBuffer->zero();
92117
return;
93118
}
@@ -140,8 +165,10 @@ void AudioBufferBaseSourceNode::processWithoutPitchCorrection(
140165
processingBuffer->zero();
141166
return;
142167
}
168+
143169
auto computedPlaybackRate =
144170
getComputedPlaybackRateValue(framesToProcess, context->getCurrentTime());
171+
145172
updatePlaybackInfo(
146173
processingBuffer,
147174
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: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -129,26 +129,6 @@ void AudioBufferQueueSourceNode::unregisterOnBufferEndedCallback(uint64_t callba
129129
audioEventHandlerRegistry_->unregisterHandler(AudioEvent::BUFFER_ENDED, callbackId);
130130
}
131131

132-
std::shared_ptr<DSPAudioBuffer> AudioBufferQueueSourceNode::processNode(
133-
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
134-
int framesToProcess) {
135-
// no audio data to fill, zero the output and return.
136-
if (buffers_.empty()) {
137-
processingBuffer->zero();
138-
return processingBuffer;
139-
}
140-
141-
if (!pitchCorrection_) {
142-
processWithoutPitchCorrection(processingBuffer, framesToProcess);
143-
} else {
144-
processWithPitchCorrection(processingBuffer, framesToProcess);
145-
}
146-
147-
handleStopScheduled();
148-
149-
return processingBuffer;
150-
}
151-
152132
double AudioBufferQueueSourceNode::getCurrentPosition() const {
153133
return dsp::sampleFrameToTime(static_cast<int>(vReadIndex_), getContextSampleRate()) +
154134
playedBuffersDuration_;
@@ -168,6 +148,10 @@ void AudioBufferQueueSourceNode::sendOnBufferEndedEvent(size_t bufferId, bool is
168148
* Helper functions
169149
*/
170150

151+
bool AudioBufferQueueSourceNode::isEmpty() const {
152+
return buffers_.empty();
153+
}
154+
171155
void AudioBufferQueueSourceNode::processWithoutInterpolation(
172156
const std::shared_ptr<DSPAudioBuffer> &processingBuffer,
173157
size_t startOffset,

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)