react-native-audio-api 0.11.0-nightly-568a154-20251222 → 0.11.0-nightly-9548557-20251223
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/common/cpp/audioapi/AudioAPIModuleInstaller.h +2 -0
- package/common/cpp/audioapi/HostObjects/effects/DelayNodeHostObject.cpp +6 -2
- package/common/cpp/audioapi/core/AudioContext.cpp +15 -13
- package/common/cpp/audioapi/core/AudioContext.h +2 -1
- package/common/cpp/audioapi/core/AudioNode.cpp +39 -24
- package/common/cpp/audioapi/core/AudioNode.h +3 -3
- package/common/cpp/audioapi/core/AudioParam.cpp +9 -6
- package/common/cpp/audioapi/core/AudioParam.h +2 -2
- package/common/cpp/audioapi/core/BaseAudioContext.cpp +25 -21
- package/common/cpp/audioapi/core/BaseAudioContext.h +3 -1
- package/common/cpp/audioapi/core/analysis/AnalyserNode.cpp +8 -11
- package/common/cpp/audioapi/core/analysis/AnalyserNode.h +1 -1
- package/common/cpp/audioapi/core/destinations/AudioDestinationNode.cpp +9 -3
- package/common/cpp/audioapi/core/destinations/AudioDestinationNode.h +1 -1
- package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +18 -9
- package/common/cpp/audioapi/core/effects/BiquadFilterNode.h +1 -1
- package/common/cpp/audioapi/core/effects/ConvolverNode.cpp +4 -4
- package/common/cpp/audioapi/core/effects/ConvolverNode.h +1 -1
- package/common/cpp/audioapi/core/effects/DelayNode.cpp +20 -11
- package/common/cpp/audioapi/core/effects/DelayNode.h +1 -1
- package/common/cpp/audioapi/core/effects/GainNode.cpp +12 -4
- package/common/cpp/audioapi/core/effects/GainNode.h +1 -1
- package/common/cpp/audioapi/core/effects/IIRFilterNode.cpp +6 -3
- package/common/cpp/audioapi/core/effects/IIRFilterNode.h +1 -1
- package/common/cpp/audioapi/core/effects/StereoPannerNode.cpp +7 -4
- package/common/cpp/audioapi/core/effects/StereoPannerNode.h +1 -1
- package/common/cpp/audioapi/core/effects/WorkletNode.cpp +3 -3
- package/common/cpp/audioapi/core/effects/WorkletNode.h +2 -2
- package/common/cpp/audioapi/core/effects/WorkletProcessingNode.cpp +7 -4
- package/common/cpp/audioapi/core/effects/WorkletProcessingNode.h +6 -2
- package/common/cpp/audioapi/core/sources/AudioBuffer.cpp +2 -3
- package/common/cpp/audioapi/core/sources/AudioBuffer.h +1 -1
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +59 -25
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +4 -2
- package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +18 -11
- package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h +3 -1
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +37 -21
- package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +3 -3
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +11 -11
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +4 -2
- package/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp +16 -8
- package/common/cpp/audioapi/core/sources/ConstantSourceNode.h +1 -1
- package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +30 -18
- package/common/cpp/audioapi/core/sources/OscillatorNode.h +1 -1
- package/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp +4 -4
- package/common/cpp/audioapi/core/sources/RecorderAdapterNode.h +1 -1
- package/common/cpp/audioapi/core/sources/StreamerNode.cpp +24 -10
- package/common/cpp/audioapi/core/sources/StreamerNode.h +4 -3
- package/common/cpp/audioapi/core/sources/WorkletSourceNode.cpp +11 -4
- package/common/cpp/audioapi/core/sources/WorkletSourceNode.h +6 -2
- package/common/cpp/test/RunTests.sh +1 -1
- package/common/cpp/test/src/AudioParamTest.cpp +10 -10
- package/common/cpp/test/src/AudioScheduledSourceTest.cpp +31 -15
- package/common/cpp/test/src/ConstantSourceTest.cpp +16 -14
- package/common/cpp/test/src/DelayTest.cpp +14 -13
- package/common/cpp/test/src/GainTest.cpp +10 -9
- package/common/cpp/test/src/IIRFilterTest.cpp +4 -4
- package/common/cpp/test/src/OscillatorTest.cpp +2 -2
- package/common/cpp/test/src/StereoPannerTest.cpp +14 -12
- package/common/cpp/test/src/biquad/BiquadFilterTest.cpp +25 -25
- package/common/cpp/test/src/biquad/BiquadFilterTest.h +3 -5
- package/package.json +1 -1
|
@@ -7,14 +7,16 @@
|
|
|
7
7
|
|
|
8
8
|
namespace audioapi {
|
|
9
9
|
|
|
10
|
-
DelayNode::DelayNode(BaseAudioContext
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
DelayNode::DelayNode(std::shared_ptr<BaseAudioContext> context, float maxDelayTime)
|
|
11
|
+
: AudioNode(context),
|
|
12
|
+
delayTimeParam_(std::make_shared<AudioParam>(0, 0, maxDelayTime, context)),
|
|
13
|
+
delayBuffer_(
|
|
14
|
+
std::make_shared<AudioBus>(
|
|
15
|
+
static_cast<size_t>(
|
|
16
|
+
maxDelayTime * context->getSampleRate() +
|
|
17
|
+
1), // +1 to enable delayTime equal to maxDelayTime
|
|
18
|
+
channelCount_,
|
|
19
|
+
context->getSampleRate())) {
|
|
18
20
|
requiresTailProcessing_ = true;
|
|
19
21
|
isInitialized_ = true;
|
|
20
22
|
}
|
|
@@ -27,7 +29,11 @@ void DelayNode::onInputDisabled() {
|
|
|
27
29
|
numberOfEnabledInputNodes_ -= 1;
|
|
28
30
|
if (isEnabled() && numberOfEnabledInputNodes_ == 0) {
|
|
29
31
|
signalledToStop_ = true;
|
|
30
|
-
|
|
32
|
+
if (std::shared_ptr<BaseAudioContext> context = context_.lock()) {
|
|
33
|
+
remainingFrames_ = delayTimeParam_->getValue() * context->getSampleRate();
|
|
34
|
+
} else {
|
|
35
|
+
remainingFrames_ = 0;
|
|
36
|
+
}
|
|
31
37
|
}
|
|
32
38
|
}
|
|
33
39
|
|
|
@@ -89,8 +95,11 @@ std::shared_ptr<AudioBus> DelayNode::processNode(
|
|
|
89
95
|
}
|
|
90
96
|
|
|
91
97
|
// normal processing
|
|
92
|
-
|
|
93
|
-
|
|
98
|
+
std::shared_ptr<BaseAudioContext> context = context_.lock();
|
|
99
|
+
if (context == nullptr)
|
|
100
|
+
return processingBus;
|
|
101
|
+
auto delayTime = delayTimeParam_->processKRateParam(framesToProcess, context->getCurrentTime());
|
|
102
|
+
size_t writeIndex = static_cast<size_t>(readIndex_ + delayTime * context->getSampleRate()) %
|
|
94
103
|
delayBuffer_->getSize();
|
|
95
104
|
delayBufferOperation(processingBus, framesToProcess, writeIndex, DelayNode::BufferAction::WRITE);
|
|
96
105
|
delayBufferOperation(processingBus, framesToProcess, readIndex_, DelayNode::BufferAction::READ);
|
|
@@ -12,7 +12,7 @@ class AudioBus;
|
|
|
12
12
|
|
|
13
13
|
class DelayNode : public AudioNode {
|
|
14
14
|
public:
|
|
15
|
-
explicit DelayNode(BaseAudioContext
|
|
15
|
+
explicit DelayNode(std::shared_ptr<BaseAudioContext> context, float maxDelayTime);
|
|
16
16
|
|
|
17
17
|
[[nodiscard]] std::shared_ptr<AudioParam> getDelayTimeParam() const;
|
|
18
18
|
|
|
@@ -7,9 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
namespace audioapi {
|
|
9
9
|
|
|
10
|
-
GainNode::GainNode(BaseAudioContext
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
GainNode::GainNode(std::shared_ptr<BaseAudioContext> context)
|
|
11
|
+
: AudioNode(context),
|
|
12
|
+
gainParam_(
|
|
13
|
+
std::make_shared<AudioParam>(
|
|
14
|
+
1.0,
|
|
15
|
+
MOST_NEGATIVE_SINGLE_FLOAT,
|
|
16
|
+
MOST_POSITIVE_SINGLE_FLOAT,
|
|
17
|
+
context)) {
|
|
13
18
|
isInitialized_ = true;
|
|
14
19
|
}
|
|
15
20
|
|
|
@@ -20,7 +25,10 @@ std::shared_ptr<AudioParam> GainNode::getGainParam() const {
|
|
|
20
25
|
std::shared_ptr<AudioBus> GainNode::processNode(
|
|
21
26
|
const std::shared_ptr<AudioBus> &processingBus,
|
|
22
27
|
int framesToProcess) {
|
|
23
|
-
|
|
28
|
+
std::shared_ptr<BaseAudioContext> context = context_.lock();
|
|
29
|
+
if (context == nullptr)
|
|
30
|
+
return processingBus;
|
|
31
|
+
double time = context->getCurrentTime();
|
|
24
32
|
auto gainParamValues = gainParam_->processARateParam(framesToProcess, time);
|
|
25
33
|
for (int i = 0; i < processingBus->getNumberOfChannels(); i += 1) {
|
|
26
34
|
dsp::multiply(
|
|
@@ -35,11 +35,10 @@
|
|
|
35
35
|
namespace audioapi {
|
|
36
36
|
|
|
37
37
|
IIRFilterNode::IIRFilterNode(
|
|
38
|
-
BaseAudioContext
|
|
38
|
+
std::shared_ptr<BaseAudioContext> context,
|
|
39
39
|
const std::vector<float> &feedforward,
|
|
40
40
|
const std::vector<float> &feedback)
|
|
41
41
|
: AudioNode(context), feedforward_(feedforward), feedback_(feedback) {
|
|
42
|
-
isInitialized_ = true;
|
|
43
42
|
channelCountMode_ = ChannelCountMode::MAX;
|
|
44
43
|
|
|
45
44
|
int maxChannels = MAX_CHANNEL_COUNT;
|
|
@@ -65,6 +64,7 @@ IIRFilterNode::IIRFilterNode(
|
|
|
65
64
|
|
|
66
65
|
feedback_[0] = 1.0f;
|
|
67
66
|
}
|
|
67
|
+
isInitialized_ = true;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
// Compute Z-transform of the filter
|
|
@@ -89,7 +89,10 @@ void IIRFilterNode::getFrequencyResponse(
|
|
|
89
89
|
float *magResponseOutput,
|
|
90
90
|
float *phaseResponseOutput,
|
|
91
91
|
size_t length) {
|
|
92
|
-
|
|
92
|
+
std::shared_ptr<BaseAudioContext> context = context_.lock();
|
|
93
|
+
if (context == nullptr)
|
|
94
|
+
return;
|
|
95
|
+
float nyquist = context->getNyquistFrequency();
|
|
93
96
|
|
|
94
97
|
for (size_t k = 0; k < length; ++k) {
|
|
95
98
|
float normalizedFreq = frequencyArray[k] / nyquist;
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
|
|
10
10
|
namespace audioapi {
|
|
11
11
|
|
|
12
|
-
StereoPannerNode::StereoPannerNode(BaseAudioContext
|
|
12
|
+
StereoPannerNode::StereoPannerNode(std::shared_ptr<BaseAudioContext> context)
|
|
13
|
+
: AudioNode(context), panParam_(std::make_shared<AudioParam>(0.0, -1.0f, 1.0f, context)) {
|
|
13
14
|
channelCountMode_ = ChannelCountMode::CLAMPED_MAX;
|
|
14
|
-
panParam_ = std::make_shared<AudioParam>(0.0, -1.0f, 1.0f, context);
|
|
15
15
|
isInitialized_ = true;
|
|
16
16
|
}
|
|
17
17
|
|
|
@@ -22,8 +22,11 @@ std::shared_ptr<AudioParam> StereoPannerNode::getPanParam() const {
|
|
|
22
22
|
std::shared_ptr<AudioBus> StereoPannerNode::processNode(
|
|
23
23
|
const std::shared_ptr<AudioBus> &processingBus,
|
|
24
24
|
int framesToProcess) {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
std::shared_ptr<BaseAudioContext> context = context_.lock();
|
|
26
|
+
if (context == nullptr)
|
|
27
|
+
return processingBus;
|
|
28
|
+
double time = context->getCurrentTime();
|
|
29
|
+
double deltaTime = 1.0 / context->getSampleRate();
|
|
27
30
|
|
|
28
31
|
auto *inputLeft = processingBus->getChannelByType(AudioBus::ChannelLeft);
|
|
29
32
|
auto panParamValues =
|
|
@@ -13,7 +13,7 @@ class AudioBus;
|
|
|
13
13
|
|
|
14
14
|
class StereoPannerNode : public AudioNode {
|
|
15
15
|
public:
|
|
16
|
-
explicit StereoPannerNode(BaseAudioContext
|
|
16
|
+
explicit StereoPannerNode(std::shared_ptr<BaseAudioContext> context);
|
|
17
17
|
|
|
18
18
|
[[nodiscard]] std::shared_ptr<AudioParam> getPanParam() const;
|
|
19
19
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
namespace audioapi {
|
|
8
8
|
|
|
9
9
|
WorkletNode::WorkletNode(
|
|
10
|
-
BaseAudioContext
|
|
10
|
+
std::shared_ptr<BaseAudioContext> context,
|
|
11
11
|
size_t bufferLength,
|
|
12
12
|
size_t inputChannelCount,
|
|
13
13
|
WorkletsRunner &&runtime)
|
|
@@ -15,8 +15,8 @@ WorkletNode::WorkletNode(
|
|
|
15
15
|
workletRunner_(std::move(runtime)),
|
|
16
16
|
bufferLength_(bufferLength),
|
|
17
17
|
inputChannelCount_(inputChannelCount),
|
|
18
|
-
curBuffIndex_(0)
|
|
19
|
-
|
|
18
|
+
curBuffIndex_(0),
|
|
19
|
+
bus_(std::make_shared<AudioBus>(bufferLength, inputChannelCount, context->getSampleRate())) {
|
|
20
20
|
isInitialized_ = true;
|
|
21
21
|
}
|
|
22
22
|
|
|
@@ -17,7 +17,7 @@ namespace audioapi {
|
|
|
17
17
|
class WorkletNode : public AudioNode {
|
|
18
18
|
public:
|
|
19
19
|
explicit WorkletNode(
|
|
20
|
-
BaseAudioContext
|
|
20
|
+
std::shared_ptr<BaseAudioContext> context,
|
|
21
21
|
size_t bufferLength,
|
|
22
22
|
size_t inputChannelCount,
|
|
23
23
|
WorkletsRunner &&workletRunner)
|
|
@@ -37,7 +37,7 @@ using namespace facebook;
|
|
|
37
37
|
class WorkletNode : public AudioNode {
|
|
38
38
|
public:
|
|
39
39
|
explicit WorkletNode(
|
|
40
|
-
BaseAudioContext
|
|
40
|
+
std::shared_ptr<BaseAudioContext> context,
|
|
41
41
|
size_t bufferLength,
|
|
42
42
|
size_t inputChannelCount,
|
|
43
43
|
WorkletsRunner &&workletRunner);
|
|
@@ -6,11 +6,9 @@
|
|
|
6
6
|
namespace audioapi {
|
|
7
7
|
|
|
8
8
|
WorkletProcessingNode::WorkletProcessingNode(
|
|
9
|
-
BaseAudioContext
|
|
9
|
+
std::shared_ptr<BaseAudioContext> context,
|
|
10
10
|
WorkletsRunner &&workletRunner)
|
|
11
11
|
: AudioNode(context), workletRunner_(std::move(workletRunner)) {
|
|
12
|
-
isInitialized_ = true;
|
|
13
|
-
|
|
14
12
|
// Pre-allocate buffers for max 128 frames and 2 channels (stereo)
|
|
15
13
|
size_t maxChannelCount = 2;
|
|
16
14
|
inputBuffsHandles_.resize(maxChannelCount);
|
|
@@ -23,6 +21,7 @@ WorkletProcessingNode::WorkletProcessingNode(
|
|
|
23
21
|
auto outputAudioArray = std::make_shared<AudioArray>(RENDER_QUANTUM_SIZE);
|
|
24
22
|
outputBuffsHandles_[i] = std::make_shared<AudioArrayBuffer>(outputAudioArray);
|
|
25
23
|
}
|
|
24
|
+
isInitialized_ = true;
|
|
26
25
|
}
|
|
27
26
|
|
|
28
27
|
std::shared_ptr<AudioBus> WorkletProcessingNode::processNode(
|
|
@@ -60,11 +59,15 @@ std::shared_ptr<AudioBus> WorkletProcessingNode::processNode(
|
|
|
60
59
|
// We call unsafely here because we are already on the runtime thread
|
|
61
60
|
// and the runtime is locked by executeOnRuntimeSync (if
|
|
62
61
|
// shouldLockRuntime is true)
|
|
62
|
+
float time = 0.0f;
|
|
63
|
+
if (std::shared_ptr<BaseAudioContext> context = context_.lock()) {
|
|
64
|
+
time = context->getCurrentTime();
|
|
65
|
+
}
|
|
63
66
|
return workletRunner_.callUnsafe(
|
|
64
67
|
inputJsArray,
|
|
65
68
|
outputJsArray,
|
|
66
69
|
jsi::Value(rt, static_cast<int>(framesToProcess)),
|
|
67
|
-
jsi::Value(rt,
|
|
70
|
+
jsi::Value(rt, time));
|
|
68
71
|
});
|
|
69
72
|
|
|
70
73
|
// Copy processed output data back to the processing bus or zero on failure
|
|
@@ -16,7 +16,9 @@ namespace audioapi {
|
|
|
16
16
|
#if RN_AUDIO_API_TEST
|
|
17
17
|
class WorkletProcessingNode : public AudioNode {
|
|
18
18
|
public:
|
|
19
|
-
explicit WorkletProcessingNode(
|
|
19
|
+
explicit WorkletProcessingNode(
|
|
20
|
+
std::shared_ptr<BaseAudioContext> context,
|
|
21
|
+
WorkletsRunner &&workletRunner)
|
|
20
22
|
: AudioNode(context) {}
|
|
21
23
|
|
|
22
24
|
protected:
|
|
@@ -32,7 +34,9 @@ using namespace facebook;
|
|
|
32
34
|
|
|
33
35
|
class WorkletProcessingNode : public AudioNode {
|
|
34
36
|
public:
|
|
35
|
-
explicit WorkletProcessingNode(
|
|
37
|
+
explicit WorkletProcessingNode(
|
|
38
|
+
std::shared_ptr<BaseAudioContext> context,
|
|
39
|
+
WorkletsRunner &&workletRunner);
|
|
36
40
|
|
|
37
41
|
protected:
|
|
38
42
|
std::shared_ptr<AudioBus> processNode(
|
|
@@ -8,9 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
namespace audioapi {
|
|
10
10
|
|
|
11
|
-
AudioBuffer::AudioBuffer(int numberOfChannels, size_t length, float sampleRate)
|
|
12
|
-
|
|
13
|
-
}
|
|
11
|
+
AudioBuffer::AudioBuffer(int numberOfChannels, size_t length, float sampleRate)
|
|
12
|
+
: bus_(std::make_shared<AudioBus>(length, numberOfChannels, sampleRate)) {}
|
|
14
13
|
|
|
15
14
|
AudioBuffer::AudioBuffer(std::shared_ptr<AudioBus> bus) {
|
|
16
15
|
bus_ = std::move(bus);
|
|
@@ -11,7 +11,7 @@ namespace audioapi {
|
|
|
11
11
|
|
|
12
12
|
class AudioBus;
|
|
13
13
|
|
|
14
|
-
class AudioBuffer
|
|
14
|
+
class AudioBuffer {
|
|
15
15
|
public:
|
|
16
16
|
explicit AudioBuffer(int numberOfChannels, size_t length, float sampleRate);
|
|
17
17
|
explicit AudioBuffer(std::shared_ptr<AudioBus> bus);
|
|
@@ -11,21 +11,30 @@
|
|
|
11
11
|
|
|
12
12
|
namespace audioapi {
|
|
13
13
|
AudioBufferBaseSourceNode::AudioBufferBaseSourceNode(
|
|
14
|
-
BaseAudioContext
|
|
14
|
+
std::shared_ptr<BaseAudioContext> context,
|
|
15
15
|
bool pitchCorrection)
|
|
16
|
-
: AudioScheduledSourceNode(context),
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
16
|
+
: AudioScheduledSourceNode(context),
|
|
17
|
+
pitchCorrection_(pitchCorrection),
|
|
18
|
+
vReadIndex_(0.0),
|
|
19
|
+
onPositionChangedInterval_(static_cast<int>(context->getSampleRate() * 0.1f)),
|
|
20
|
+
detuneParam_(
|
|
21
|
+
std::make_shared<AudioParam>(
|
|
22
|
+
0.0,
|
|
23
|
+
MOST_NEGATIVE_SINGLE_FLOAT,
|
|
24
|
+
MOST_POSITIVE_SINGLE_FLOAT,
|
|
25
|
+
context)),
|
|
26
|
+
playbackRateParam_(
|
|
27
|
+
std::make_shared<AudioParam>(
|
|
28
|
+
1.0,
|
|
29
|
+
MOST_NEGATIVE_SINGLE_FLOAT,
|
|
30
|
+
MOST_POSITIVE_SINGLE_FLOAT,
|
|
31
|
+
context)),
|
|
32
|
+
playbackRateBus_(
|
|
33
|
+
std::make_shared<AudioBus>(
|
|
34
|
+
RENDER_QUANTUM_SIZE * 3,
|
|
35
|
+
channelCount_,
|
|
36
|
+
context->getSampleRate())),
|
|
37
|
+
stretch_(std::make_shared<signalsmith::stretch::SignalsmithStretch<float>>()) {}
|
|
29
38
|
|
|
30
39
|
std::shared_ptr<AudioParam> AudioBufferBaseSourceNode::getDetuneParam() const {
|
|
31
40
|
return detuneParam_;
|
|
@@ -44,8 +53,10 @@ void AudioBufferBaseSourceNode::setOnPositionChangedCallbackId(uint64_t callback
|
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
void AudioBufferBaseSourceNode::setOnPositionChangedInterval(int interval) {
|
|
47
|
-
|
|
48
|
-
|
|
56
|
+
if (std::shared_ptr<BaseAudioContext> context = context_.lock()) {
|
|
57
|
+
onPositionChangedInterval_ =
|
|
58
|
+
static_cast<int>(context->getSampleRate() * static_cast<float>(interval) / 1000);
|
|
59
|
+
}
|
|
49
60
|
}
|
|
50
61
|
|
|
51
62
|
int AudioBufferBaseSourceNode::getOnPositionChangedInterval() const {
|
|
@@ -58,14 +69,22 @@ std::mutex &AudioBufferBaseSourceNode::getBufferLock() {
|
|
|
58
69
|
|
|
59
70
|
double AudioBufferBaseSourceNode::getInputLatency() const {
|
|
60
71
|
if (pitchCorrection_) {
|
|
61
|
-
|
|
72
|
+
if (std::shared_ptr<BaseAudioContext> context = context_.lock()) {
|
|
73
|
+
return static_cast<double>(stretch_->inputLatency()) / context->getSampleRate();
|
|
74
|
+
} else {
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
62
77
|
}
|
|
63
78
|
return 0;
|
|
64
79
|
}
|
|
65
80
|
|
|
66
81
|
double AudioBufferBaseSourceNode::getOutputLatency() const {
|
|
67
82
|
if (pitchCorrection_) {
|
|
68
|
-
|
|
83
|
+
if (std::shared_ptr<BaseAudioContext> context = context_.lock()) {
|
|
84
|
+
return static_cast<double>(stretch_->outputLatency()) / context->getSampleRate();
|
|
85
|
+
} else {
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
69
88
|
}
|
|
70
89
|
return 0;
|
|
71
90
|
}
|
|
@@ -91,7 +110,12 @@ void AudioBufferBaseSourceNode::processWithPitchCorrection(
|
|
|
91
110
|
size_t startOffset = 0;
|
|
92
111
|
size_t offsetLength = 0;
|
|
93
112
|
|
|
94
|
-
|
|
113
|
+
std::shared_ptr<BaseAudioContext> context = context_.lock();
|
|
114
|
+
if (context == nullptr) {
|
|
115
|
+
processingBus->zero();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
auto time = context->getCurrentTime();
|
|
95
119
|
auto playbackRate =
|
|
96
120
|
std::clamp(playbackRateParam_->processKRateParam(framesToProcess, time), 0.0f, 3.0f);
|
|
97
121
|
auto detune =
|
|
@@ -101,7 +125,13 @@ void AudioBufferBaseSourceNode::processWithPitchCorrection(
|
|
|
101
125
|
|
|
102
126
|
auto framesNeededToStretch = static_cast<int>(playbackRate * static_cast<float>(framesToProcess));
|
|
103
127
|
|
|
104
|
-
updatePlaybackInfo(
|
|
128
|
+
updatePlaybackInfo(
|
|
129
|
+
playbackRateBus_,
|
|
130
|
+
framesNeededToStretch,
|
|
131
|
+
startOffset,
|
|
132
|
+
offsetLength,
|
|
133
|
+
context->getSampleRate(),
|
|
134
|
+
context->getCurrentSampleFrame());
|
|
105
135
|
|
|
106
136
|
if (playbackRate == 0.0f || (!isPlaying() && !isStopScheduled())) {
|
|
107
137
|
processingBus->zero();
|
|
@@ -126,8 +156,14 @@ void AudioBufferBaseSourceNode::processWithoutPitchCorrection(
|
|
|
126
156
|
size_t startOffset = 0;
|
|
127
157
|
size_t offsetLength = 0;
|
|
128
158
|
|
|
129
|
-
|
|
130
|
-
|
|
159
|
+
std::shared_ptr<BaseAudioContext> context = context_.lock();
|
|
160
|
+
if (context == nullptr) {
|
|
161
|
+
processingBus->zero();
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
auto computedPlaybackRate =
|
|
165
|
+
getComputedPlaybackRateValue(framesToProcess, context->getCurrentTime());
|
|
166
|
+
updatePlaybackInfo(processingBus, framesToProcess, startOffset, offsetLength, context->getSampleRate(), context->getCurrentSampleFrame());
|
|
131
167
|
|
|
132
168
|
if (computedPlaybackRate == 0.0f || (!isPlaying() && !isStopScheduled())) {
|
|
133
169
|
processingBus->zero();
|
|
@@ -143,9 +179,7 @@ void AudioBufferBaseSourceNode::processWithoutPitchCorrection(
|
|
|
143
179
|
sendOnPositionChangedEvent();
|
|
144
180
|
}
|
|
145
181
|
|
|
146
|
-
float AudioBufferBaseSourceNode::getComputedPlaybackRateValue(int framesToProcess) {
|
|
147
|
-
auto time = context_->getCurrentTime();
|
|
148
|
-
|
|
182
|
+
float AudioBufferBaseSourceNode::getComputedPlaybackRateValue(int framesToProcess, double time) {
|
|
149
183
|
auto playbackRate = playbackRateParam_->processKRateParam(framesToProcess, time);
|
|
150
184
|
auto detune = std::pow(2.0f, detuneParam_->processKRateParam(framesToProcess, time) / 1200.0f);
|
|
151
185
|
|
|
@@ -14,7 +14,9 @@ class AudioParam;
|
|
|
14
14
|
|
|
15
15
|
class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
|
|
16
16
|
public:
|
|
17
|
-
explicit AudioBufferBaseSourceNode(
|
|
17
|
+
explicit AudioBufferBaseSourceNode(
|
|
18
|
+
std::shared_ptr<BaseAudioContext> context,
|
|
19
|
+
bool pitchCorrection);
|
|
18
20
|
|
|
19
21
|
[[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
|
|
20
22
|
[[nodiscard]] std::shared_ptr<AudioParam> getPlaybackRateParam() const;
|
|
@@ -58,7 +60,7 @@ class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
|
|
|
58
60
|
const std::shared_ptr<AudioBus> &processingBus,
|
|
59
61
|
int framesToProcess);
|
|
60
62
|
|
|
61
|
-
float getComputedPlaybackRateValue(int framesToProcess);
|
|
63
|
+
float getComputedPlaybackRateValue(int framesToProcess, double time);
|
|
62
64
|
|
|
63
65
|
virtual void processWithoutInterpolation(
|
|
64
66
|
const std::shared_ptr<AudioBus> &processingBus,
|
|
@@ -18,11 +18,10 @@
|
|
|
18
18
|
namespace audioapi {
|
|
19
19
|
|
|
20
20
|
AudioBufferQueueSourceNode::AudioBufferQueueSourceNode(
|
|
21
|
-
BaseAudioContext
|
|
21
|
+
std::shared_ptr<BaseAudioContext> context,
|
|
22
22
|
bool pitchCorrection)
|
|
23
|
-
: AudioBufferBaseSourceNode(context, pitchCorrection) {
|
|
24
|
-
|
|
25
|
-
stretch_->presetDefault(channelCount_, context_->getSampleRate());
|
|
23
|
+
: AudioBufferBaseSourceNode(context, pitchCorrection), buffers_() {
|
|
24
|
+
stretch_->presetDefault(channelCount_, context->getSampleRate());
|
|
26
25
|
|
|
27
26
|
if (pitchCorrection) {
|
|
28
27
|
// If pitch correction is enabled, add extra frames at the end
|
|
@@ -31,7 +30,7 @@ AudioBufferQueueSourceNode::AudioBufferQueueSourceNode(
|
|
|
31
30
|
|
|
32
31
|
int extraTailFrames = static_cast<int>(stretch_->inputLatency() + stretch_->outputLatency());
|
|
33
32
|
tailBuffer_ =
|
|
34
|
-
std::make_shared<AudioBuffer>(channelCount_, extraTailFrames,
|
|
33
|
+
std::make_shared<AudioBuffer>(channelCount_, extraTailFrames, context->getSampleRate());
|
|
35
34
|
|
|
36
35
|
tailBuffer_->bus_->zero();
|
|
37
36
|
}
|
|
@@ -148,8 +147,12 @@ std::shared_ptr<AudioBus> AudioBufferQueueSourceNode::processNode(
|
|
|
148
147
|
}
|
|
149
148
|
|
|
150
149
|
double AudioBufferQueueSourceNode::getCurrentPosition() const {
|
|
151
|
-
|
|
152
|
-
|
|
150
|
+
if (std::shared_ptr<BaseAudioContext> context = context_.lock()) {
|
|
151
|
+
return dsp::sampleFrameToTime(static_cast<int>(vReadIndex_), context->getSampleRate()) +
|
|
152
|
+
playedBuffersDuration_;
|
|
153
|
+
} else {
|
|
154
|
+
return 0.0;
|
|
155
|
+
}
|
|
153
156
|
}
|
|
154
157
|
|
|
155
158
|
/**
|
|
@@ -192,8 +195,10 @@ void AudioBufferQueueSourceNode::processWithoutInterpolation(
|
|
|
192
195
|
|
|
193
196
|
std::unordered_map<std::string, EventValue> body = {
|
|
194
197
|
{"bufferId", std::to_string(bufferId)}, {"isLast", buffers_.empty()}};
|
|
195
|
-
context_
|
|
196
|
-
|
|
198
|
+
if (std::shared_ptr<BaseAudioContext> context = context_.lock()) {
|
|
199
|
+
context->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
|
|
200
|
+
"ended", onEndedCallbackId_, body);
|
|
201
|
+
}
|
|
197
202
|
|
|
198
203
|
if (buffers_.empty()) {
|
|
199
204
|
if (addExtraTailFrames_) {
|
|
@@ -277,8 +282,10 @@ void AudioBufferQueueSourceNode::processWithInterpolation(
|
|
|
277
282
|
buffers_.pop();
|
|
278
283
|
|
|
279
284
|
std::unordered_map<std::string, EventValue> body = {{"bufferId", std::to_string(bufferId)}};
|
|
280
|
-
context_
|
|
281
|
-
|
|
285
|
+
if (std::shared_ptr<BaseAudioContext> context = context_.lock()) {
|
|
286
|
+
context->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
|
|
287
|
+
"ended", onEndedCallbackId_, body);
|
|
288
|
+
}
|
|
282
289
|
|
|
283
290
|
if (buffers_.empty()) {
|
|
284
291
|
processingBus->zero(writeIndex, framesLeft);
|
|
@@ -17,7 +17,9 @@ class AudioParam;
|
|
|
17
17
|
|
|
18
18
|
class AudioBufferQueueSourceNode : public AudioBufferBaseSourceNode {
|
|
19
19
|
public:
|
|
20
|
-
explicit AudioBufferQueueSourceNode(
|
|
20
|
+
explicit AudioBufferQueueSourceNode(
|
|
21
|
+
std::shared_ptr<BaseAudioContext> context,
|
|
22
|
+
bool pitchCorrection);
|
|
21
23
|
~AudioBufferQueueSourceNode() override;
|
|
22
24
|
|
|
23
25
|
void stop(double when) override;
|