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.
Files changed (62) hide show
  1. package/common/cpp/audioapi/AudioAPIModuleInstaller.h +2 -0
  2. package/common/cpp/audioapi/HostObjects/effects/DelayNodeHostObject.cpp +6 -2
  3. package/common/cpp/audioapi/core/AudioContext.cpp +15 -13
  4. package/common/cpp/audioapi/core/AudioContext.h +2 -1
  5. package/common/cpp/audioapi/core/AudioNode.cpp +39 -24
  6. package/common/cpp/audioapi/core/AudioNode.h +3 -3
  7. package/common/cpp/audioapi/core/AudioParam.cpp +9 -6
  8. package/common/cpp/audioapi/core/AudioParam.h +2 -2
  9. package/common/cpp/audioapi/core/BaseAudioContext.cpp +25 -21
  10. package/common/cpp/audioapi/core/BaseAudioContext.h +3 -1
  11. package/common/cpp/audioapi/core/analysis/AnalyserNode.cpp +8 -11
  12. package/common/cpp/audioapi/core/analysis/AnalyserNode.h +1 -1
  13. package/common/cpp/audioapi/core/destinations/AudioDestinationNode.cpp +9 -3
  14. package/common/cpp/audioapi/core/destinations/AudioDestinationNode.h +1 -1
  15. package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +18 -9
  16. package/common/cpp/audioapi/core/effects/BiquadFilterNode.h +1 -1
  17. package/common/cpp/audioapi/core/effects/ConvolverNode.cpp +4 -4
  18. package/common/cpp/audioapi/core/effects/ConvolverNode.h +1 -1
  19. package/common/cpp/audioapi/core/effects/DelayNode.cpp +20 -11
  20. package/common/cpp/audioapi/core/effects/DelayNode.h +1 -1
  21. package/common/cpp/audioapi/core/effects/GainNode.cpp +12 -4
  22. package/common/cpp/audioapi/core/effects/GainNode.h +1 -1
  23. package/common/cpp/audioapi/core/effects/IIRFilterNode.cpp +6 -3
  24. package/common/cpp/audioapi/core/effects/IIRFilterNode.h +1 -1
  25. package/common/cpp/audioapi/core/effects/StereoPannerNode.cpp +7 -4
  26. package/common/cpp/audioapi/core/effects/StereoPannerNode.h +1 -1
  27. package/common/cpp/audioapi/core/effects/WorkletNode.cpp +3 -3
  28. package/common/cpp/audioapi/core/effects/WorkletNode.h +2 -2
  29. package/common/cpp/audioapi/core/effects/WorkletProcessingNode.cpp +7 -4
  30. package/common/cpp/audioapi/core/effects/WorkletProcessingNode.h +6 -2
  31. package/common/cpp/audioapi/core/sources/AudioBuffer.cpp +2 -3
  32. package/common/cpp/audioapi/core/sources/AudioBuffer.h +1 -1
  33. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +59 -25
  34. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +4 -2
  35. package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +18 -11
  36. package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h +3 -1
  37. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +37 -21
  38. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +3 -3
  39. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +11 -11
  40. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +4 -2
  41. package/common/cpp/audioapi/core/sources/ConstantSourceNode.cpp +16 -8
  42. package/common/cpp/audioapi/core/sources/ConstantSourceNode.h +1 -1
  43. package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +30 -18
  44. package/common/cpp/audioapi/core/sources/OscillatorNode.h +1 -1
  45. package/common/cpp/audioapi/core/sources/RecorderAdapterNode.cpp +4 -4
  46. package/common/cpp/audioapi/core/sources/RecorderAdapterNode.h +1 -1
  47. package/common/cpp/audioapi/core/sources/StreamerNode.cpp +24 -10
  48. package/common/cpp/audioapi/core/sources/StreamerNode.h +4 -3
  49. package/common/cpp/audioapi/core/sources/WorkletSourceNode.cpp +11 -4
  50. package/common/cpp/audioapi/core/sources/WorkletSourceNode.h +6 -2
  51. package/common/cpp/test/RunTests.sh +1 -1
  52. package/common/cpp/test/src/AudioParamTest.cpp +10 -10
  53. package/common/cpp/test/src/AudioScheduledSourceTest.cpp +31 -15
  54. package/common/cpp/test/src/ConstantSourceTest.cpp +16 -14
  55. package/common/cpp/test/src/DelayTest.cpp +14 -13
  56. package/common/cpp/test/src/GainTest.cpp +10 -9
  57. package/common/cpp/test/src/IIRFilterTest.cpp +4 -4
  58. package/common/cpp/test/src/OscillatorTest.cpp +2 -2
  59. package/common/cpp/test/src/StereoPannerTest.cpp +14 -12
  60. package/common/cpp/test/src/biquad/BiquadFilterTest.cpp +25 -25
  61. package/common/cpp/test/src/biquad/BiquadFilterTest.h +3 -5
  62. package/package.json +1 -1
@@ -7,14 +7,16 @@
7
7
 
8
8
  namespace audioapi {
9
9
 
10
- DelayNode::DelayNode(BaseAudioContext *context, float maxDelayTime) : AudioNode(context) {
11
- delayTimeParam_ = std::make_shared<AudioParam>(0, 0, maxDelayTime, context);
12
- delayBuffer_ = std::make_shared<AudioBus>(
13
- static_cast<size_t>(
14
- maxDelayTime * context->getSampleRate() +
15
- 1), // +1 to enable delayTime equal to maxDelayTime
16
- channelCount_,
17
- context->getSampleRate());
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
- remainingFrames_ = delayTimeParam_->getValue() * context_->getSampleRate();
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
- auto delayTime = delayTimeParam_->processKRateParam(framesToProcess, context_->getCurrentTime());
93
- size_t writeIndex = static_cast<size_t>(readIndex_ + delayTime * context_->getSampleRate()) %
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 *context, float maxDelayTime);
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 *context) : AudioNode(context) {
11
- gainParam_ = std::make_shared<AudioParam>(
12
- 1.0, MOST_NEGATIVE_SINGLE_FLOAT, MOST_POSITIVE_SINGLE_FLOAT, context);
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
- double time = context_->getCurrentTime();
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(
@@ -11,7 +11,7 @@ class AudioBus;
11
11
 
12
12
  class GainNode : public AudioNode {
13
13
  public:
14
- explicit GainNode(BaseAudioContext *context);
14
+ explicit GainNode(std::shared_ptr<BaseAudioContext> context);
15
15
 
16
16
  [[nodiscard]] std::shared_ptr<AudioParam> getGainParam() const;
17
17
 
@@ -35,11 +35,10 @@
35
35
  namespace audioapi {
36
36
 
37
37
  IIRFilterNode::IIRFilterNode(
38
- BaseAudioContext *context,
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
- float nyquist = context_->getNyquistFrequency();
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;
@@ -37,7 +37,7 @@ class IIRFilterNode : public AudioNode {
37
37
 
38
38
  public:
39
39
  explicit IIRFilterNode(
40
- BaseAudioContext *context,
40
+ std::shared_ptr<BaseAudioContext> context,
41
41
  const std::vector<float> &feedforward,
42
42
  const std::vector<float> &feedback);
43
43
 
@@ -9,9 +9,9 @@
9
9
 
10
10
  namespace audioapi {
11
11
 
12
- StereoPannerNode::StereoPannerNode(BaseAudioContext *context) : AudioNode(context) {
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
- double time = context_->getCurrentTime();
26
- double deltaTime = 1.0 / context_->getSampleRate();
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 *context);
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 *context,
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
- bus_ = std::make_shared<AudioBus>(bufferLength, inputChannelCount, context->getSampleRate());
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 *context,
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 *context,
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 *context,
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, this->context_->getCurrentTime()));
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(BaseAudioContext *context, WorkletsRunner &&workletRunner)
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(BaseAudioContext *context, WorkletsRunner &&workletRunner);
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
- bus_ = std::make_shared<AudioBus>(length, numberOfChannels, sampleRate);
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 : public std::enable_shared_from_this<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 *context,
14
+ std::shared_ptr<BaseAudioContext> context,
15
15
  bool pitchCorrection)
16
- : AudioScheduledSourceNode(context), pitchCorrection_(pitchCorrection), vReadIndex_(0.0) {
17
- onPositionChangedInterval_ = static_cast<int>(context->getSampleRate() * 0.1);
18
-
19
- detuneParam_ = std::make_shared<AudioParam>(
20
- 0.0, MOST_NEGATIVE_SINGLE_FLOAT, MOST_POSITIVE_SINGLE_FLOAT, context);
21
- playbackRateParam_ = std::make_shared<AudioParam>(
22
- 1.0, MOST_NEGATIVE_SINGLE_FLOAT, MOST_POSITIVE_SINGLE_FLOAT, context);
23
-
24
- playbackRateBus_ =
25
- std::make_shared<AudioBus>(RENDER_QUANTUM_SIZE * 3, channelCount_, context_->getSampleRate());
26
-
27
- stretch_ = std::make_shared<signalsmith::stretch::SignalsmithStretch<float>>();
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
- onPositionChangedInterval_ =
48
- static_cast<int>(context_->getSampleRate() * static_cast<float>(interval) / 1000);
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
- return static_cast<double>(stretch_->inputLatency()) / context_->getSampleRate();
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
- return static_cast<double>(stretch_->outputLatency()) / context_->getSampleRate();
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
- auto time = context_->getCurrentTime();
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(playbackRateBus_, framesNeededToStretch, startOffset, offsetLength);
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
- auto computedPlaybackRate = getComputedPlaybackRateValue(framesToProcess);
130
- updatePlaybackInfo(processingBus, framesToProcess, startOffset, offsetLength);
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(BaseAudioContext *context, bool pitchCorrection);
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 *context,
21
+ std::shared_ptr<BaseAudioContext> context,
22
22
  bool pitchCorrection)
23
- : AudioBufferBaseSourceNode(context, pitchCorrection) {
24
- buffers_ = {};
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, context_->getSampleRate());
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
- return dsp::sampleFrameToTime(static_cast<int>(vReadIndex_), context_->getSampleRate()) +
152
- playedBuffersDuration_;
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_->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
196
- "ended", onEndedCallbackId_, body);
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_->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
281
- "ended", onEndedCallbackId_, body);
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(BaseAudioContext *context, bool pitchCorrection);
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;