react-native-audio-api 0.6.2-rc.6 → 0.6.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.
Files changed (92) hide show
  1. package/android/src/main/java/com/swmansion/audioapi/system/LockScreenManager.kt +25 -0
  2. package/android/src/main/java/com/swmansion/audioapi/system/MediaSessionCallback.kt +13 -0
  3. package/common/cpp/audioapi/HostObjects/AudioBufferBaseSourceNodeHostObject.h +60 -0
  4. package/common/cpp/audioapi/HostObjects/AudioBufferQueueSourceNodeHostObject.h +5 -67
  5. package/common/cpp/audioapi/HostObjects/AudioBufferSourceNodeHostObject.h +26 -56
  6. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +9 -0
  7. package/common/cpp/audioapi/HostObjects/CustomProcessorNodeHostObject.h +54 -0
  8. package/common/cpp/audioapi/core/BaseAudioContext.cpp +9 -0
  9. package/common/cpp/audioapi/core/BaseAudioContext.h +2 -0
  10. package/common/cpp/audioapi/core/effects/CustomProcessorNode.cpp +173 -0
  11. package/common/cpp/audioapi/core/effects/CustomProcessorNode.h +186 -0
  12. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +104 -0
  13. package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +54 -0
  14. package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.cpp +12 -129
  15. package/common/cpp/audioapi/core/sources/AudioBufferQueueSourceNode.h +8 -37
  16. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +4 -93
  17. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +4 -30
  18. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +1 -11
  19. package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +2 -3
  20. package/common/cpp/audioapi/core/sources/OscillatorNode.cpp +0 -5
  21. package/common/cpp/audioapi/core/sources/OscillatorNode.h +0 -1
  22. package/common/cpp/audioapi/core/utils/AudioNodeDestructor.cpp +3 -1
  23. package/common/cpp/audioapi/core/utils/AudioNodeManager.cpp +1 -1
  24. package/ios/audioapi/ios/system/AudioEngine.h +1 -0
  25. package/ios/audioapi/ios/system/AudioEngine.mm +14 -3
  26. package/ios/audioapi/ios/system/AudioSessionManager.h +1 -0
  27. package/ios/audioapi/ios/system/AudioSessionManager.mm +10 -0
  28. package/ios/audioapi/ios/system/NotificationManager.mm +2 -4
  29. package/lib/commonjs/api.js +7 -0
  30. package/lib/commonjs/api.js.map +1 -1
  31. package/lib/commonjs/core/AudioBufferBaseSourceNode.js +29 -0
  32. package/lib/commonjs/core/AudioBufferBaseSourceNode.js.map +1 -0
  33. package/lib/commonjs/core/AudioBufferQueueSourceNode.js +5 -22
  34. package/lib/commonjs/core/AudioBufferQueueSourceNode.js.map +1 -1
  35. package/lib/commonjs/core/AudioBufferSourceNode.js +4 -21
  36. package/lib/commonjs/core/AudioBufferSourceNode.js.map +1 -1
  37. package/lib/commonjs/core/AudioScheduledSourceNode.js.map +1 -1
  38. package/lib/commonjs/core/BaseAudioContext.js +4 -0
  39. package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
  40. package/lib/commonjs/core/CustomProcessorNode.js +23 -0
  41. package/lib/commonjs/core/CustomProcessorNode.js.map +1 -0
  42. package/lib/commonjs/web-core/AudioScheduledSourceNode.js +1 -4
  43. package/lib/commonjs/web-core/AudioScheduledSourceNode.js.map +1 -1
  44. package/lib/module/api.js +1 -0
  45. package/lib/module/api.js.map +1 -1
  46. package/lib/module/core/AudioBufferBaseSourceNode.js +23 -0
  47. package/lib/module/core/AudioBufferBaseSourceNode.js.map +1 -0
  48. package/lib/module/core/AudioBufferQueueSourceNode.js +5 -22
  49. package/lib/module/core/AudioBufferQueueSourceNode.js.map +1 -1
  50. package/lib/module/core/AudioBufferSourceNode.js +4 -21
  51. package/lib/module/core/AudioBufferSourceNode.js.map +1 -1
  52. package/lib/module/core/AudioScheduledSourceNode.js.map +1 -1
  53. package/lib/module/core/BaseAudioContext.js +4 -0
  54. package/lib/module/core/BaseAudioContext.js.map +1 -1
  55. package/lib/module/core/CustomProcessorNode.js +17 -0
  56. package/lib/module/core/CustomProcessorNode.js.map +1 -0
  57. package/lib/module/web-core/AudioScheduledSourceNode.js +1 -4
  58. package/lib/module/web-core/AudioScheduledSourceNode.js.map +1 -1
  59. package/lib/typescript/api.d.ts +1 -0
  60. package/lib/typescript/api.d.ts.map +1 -1
  61. package/lib/typescript/core/AudioBufferBaseSourceNode.d.ts +13 -0
  62. package/lib/typescript/core/AudioBufferBaseSourceNode.d.ts.map +1 -0
  63. package/lib/typescript/core/AudioBufferQueueSourceNode.d.ts +3 -12
  64. package/lib/typescript/core/AudioBufferQueueSourceNode.d.ts.map +1 -1
  65. package/lib/typescript/core/AudioBufferSourceNode.d.ts +2 -11
  66. package/lib/typescript/core/AudioBufferSourceNode.d.ts.map +1 -1
  67. package/lib/typescript/core/AudioScheduledSourceNode.d.ts +2 -2
  68. package/lib/typescript/core/AudioScheduledSourceNode.d.ts.map +1 -1
  69. package/lib/typescript/core/BaseAudioContext.d.ts +2 -0
  70. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  71. package/lib/typescript/core/CustomProcessorNode.d.ts +12 -0
  72. package/lib/typescript/core/CustomProcessorNode.d.ts.map +1 -0
  73. package/lib/typescript/events/types.d.ts +2 -7
  74. package/lib/typescript/events/types.d.ts.map +1 -1
  75. package/lib/typescript/interfaces.d.ts +16 -13
  76. package/lib/typescript/interfaces.d.ts.map +1 -1
  77. package/lib/typescript/types.d.ts +1 -0
  78. package/lib/typescript/types.d.ts.map +1 -1
  79. package/lib/typescript/web-core/AudioScheduledSourceNode.d.ts +2 -1
  80. package/lib/typescript/web-core/AudioScheduledSourceNode.d.ts.map +1 -1
  81. package/package.json +1 -1
  82. package/src/api.ts +1 -0
  83. package/src/core/AudioBufferBaseSourceNode.ts +33 -0
  84. package/src/core/AudioBufferQueueSourceNode.ts +3 -35
  85. package/src/core/AudioBufferSourceNode.ts +10 -33
  86. package/src/core/AudioScheduledSourceNode.ts +2 -2
  87. package/src/core/BaseAudioContext.ts +8 -0
  88. package/src/core/CustomProcessorNode.ts +28 -0
  89. package/src/events/types.ts +2 -8
  90. package/src/interfaces.ts +25 -23
  91. package/src/types.ts +2 -0
  92. package/src/web-core/AudioScheduledSourceNode.tsx +3 -6
@@ -0,0 +1,186 @@
1
+ #pragma once
2
+
3
+ #include <audioapi/core/AudioNode.h>
4
+ #include <audioapi/core/AudioParam.h>
5
+ #include <memory>
6
+ #include <string>
7
+ #include <cstring>
8
+ #include <functional>
9
+ #include <map>
10
+ #include <unordered_map>
11
+ #include <vector>
12
+ #include <any>
13
+ #include <utility>
14
+
15
+ namespace audioapi {
16
+
17
+ class AudioBus;
18
+
19
+ /**
20
+ * @brief Interface for defining custom audio processors that can be attached to nodes.
21
+ */
22
+ class CustomAudioProcessor {
23
+ public:
24
+ virtual ~CustomAudioProcessor() = default;
25
+
26
+ /**
27
+ * @brief Processes audio data in-place.
28
+ * @param channelData Array of float pointers for each channel.
29
+ * @param numChannels Number of audio channels.
30
+ * @param numFrames Number of frames per channel.
31
+ */
32
+ virtual void processInPlace(float** channelData, int numChannels, int numFrames) {
33
+ // Default: do nothing
34
+ }
35
+
36
+ /**
37
+ * @brief Processes audio data from input to output buffers.
38
+ * Default behavior copies input to output and then calls in-place processing.
39
+ * @param input Input audio buffers.
40
+ * @param output Output audio buffers.
41
+ * @param numChannels Number of channels.
42
+ * @param numFrames Number of frames per channel.
43
+ */
44
+ virtual void processThrough(float** input, float** output, int numChannels, int numFrames) {
45
+ for (int ch = 0; ch < numChannels; ++ch) {
46
+ std::memcpy(output[ch], input[ch], sizeof(float) * numFrames);
47
+ }
48
+ processInPlace(output, numChannels, numFrames);
49
+ }
50
+ };
51
+
52
+ /**
53
+ * @brief Audio node that wraps a user-defined processor for custom audio processing.
54
+ */
55
+ class CustomProcessorNode : public AudioNode {
56
+ public:
57
+ /**
58
+ * @brief Enumerates supported audio processing modes.
59
+ */
60
+ enum class ProcessorMode {
61
+ ProcessInPlace,
62
+ ProcessThrough
63
+ };
64
+
65
+ /**
66
+ * @brief Constructs a new CustomProcessorNode attached to a given context with a processor identifier.
67
+ * @param context Audio context this node belongs to.
68
+ * @param identifier The identifier of the processor to instantiate and bind.
69
+ */
70
+ CustomProcessorNode(BaseAudioContext* context, const std::string& identifier);
71
+
72
+ /**
73
+ * @brief Destroys the node and removes it from active tracking.
74
+ */
75
+ ~CustomProcessorNode();
76
+
77
+ /**
78
+ * @brief Gets the custom AudioParam associated with this node.
79
+ * @return Shared pointer to an AudioParam.
80
+ */
81
+ std::shared_ptr<AudioParam> getCustomProcessorParam() const;
82
+
83
+ /**
84
+ * @brief Gets the processor mode.
85
+ * @return The current processing mode as an enum.
86
+ */
87
+ ProcessorMode getProcessorMode() const;
88
+
89
+ /**
90
+ * @brief Sets the processor mode.
91
+ * @param processorMode Processing mode to apply.
92
+ */
93
+ void setProcessorMode(ProcessorMode processorMode);
94
+
95
+ /**
96
+ * @brief Registers a factory for creating processors for a given identifier.
97
+ * @param identifier Unique string key.
98
+ * @param factory Function that returns a shared CustomAudioProcessor.
99
+ */
100
+ static void registerProcessorFactory(
101
+ const std::string& identifier,
102
+ std::function<std::shared_ptr<CustomAudioProcessor>()> factory);
103
+
104
+ /**
105
+ * @brief Unregisters a processor factory.
106
+ * @param identifier Key to remove.
107
+ */
108
+ static void unregisterProcessorFactory(const std::string& identifier);
109
+
110
+ /**
111
+ * @brief Alias for control callbacks accepting arbitrary parameters.
112
+ */
113
+ using GenericControlHandler = std::function<void(const std::vector<std::any>&)>;
114
+
115
+ /**
116
+ * @brief Registers a control handler for automation (e.g., gain or filter changes).
117
+ * @param identifier Control name key.
118
+ * @param handler Function to handle dynamic updates.
119
+ */
120
+ static void registerControlHandler(const std::string& identifier, GenericControlHandler handler);
121
+
122
+ /**
123
+ * @brief Unregisters a control handler by identifier.
124
+ * @param identifier The key to remove.
125
+ */
126
+ static void unregisterControlHandler(const std::string& identifier);
127
+
128
+ /**
129
+ * @brief Invokes a control handler using variadic arguments.
130
+ * @tparam Args Parameter types.
131
+ * @param identifier Key associated with the control handler.
132
+ * @param args Arguments passed to the handler.
133
+ */
134
+ template <typename... Args>
135
+ static void applyControlToNode(const std::string& identifier, Args&&... args) {
136
+ auto it = s_controlHandlersByIdentifier.find(identifier);
137
+ if (it != s_controlHandlersByIdentifier.end()) {
138
+ std::vector<std::any> paramList = { std::forward<Args>(args)... };
139
+ it->second(paramList);
140
+ }
141
+ }
142
+
143
+ protected:
144
+ /**
145
+ * @brief Core audio processing callback invoked each render cycle.
146
+ * @param processingBus The audio bus containing buffers.
147
+ * @param framesToProcess Number of frames to process.
148
+ */
149
+ void processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
150
+
151
+ private:
152
+ /**
153
+ * @brief In-place audio processing.
154
+ * @param bus The shared audio bus buffer.
155
+ * @param frames Number of frames to process.
156
+ */
157
+ void processInPlace(const std::shared_ptr<AudioBus>& bus, int frames);
158
+
159
+ /**
160
+ * @brief Processes audio using separate input and output buffers.
161
+ * @param bus Audio bus used for both input and output access.
162
+ * @param frames Number of frames to process.
163
+ */
164
+ void processThrough(const std::shared_ptr<AudioBus>& bus, int frames);
165
+
166
+ /**
167
+ * @brief Ensures that preallocated output buffers match the required frame and channel dimensions.
168
+ * This avoids real-time heap allocations.
169
+ */
170
+ void ensurePreallocatedBuffers(int numChannels, int numFrames);
171
+
172
+ std::shared_ptr<AudioParam> customProcessorParam_; ///< Optional real-time modifiable parameter.
173
+ ProcessorMode processorMode_ = ProcessorMode::ProcessInPlace; ///< Determines processing style.
174
+ std::shared_ptr<CustomAudioProcessor> processor_; ///< Processor instance.
175
+
176
+ std::vector<std::vector<float>> preallocatedOutputBuffers_; ///< Storage for preallocated channel data.
177
+ std::vector<float*> preallocatedOutputPointers_; ///< Pointers to preallocatedOutputBuffers_ for processor API.
178
+
179
+ static void notifyProcessorChanged(const std::string& identifier); ///< Notify and update all nodes with given identifier.
180
+
181
+ static std::map<std::string, std::function<std::shared_ptr<CustomAudioProcessor>()>> s_processorFactoriesByIdentifier; ///< Global registry of processor factories.
182
+ static std::unordered_map<std::string, GenericControlHandler> s_controlHandlersByIdentifier; ///< Global registry of control handlers.
183
+ static std::unordered_map<std::string, std::vector<CustomProcessorNode*>> s_activeNodes; ///< Tracks active node instances by identifier.
184
+ };
185
+
186
+ } // namespace audioapi
@@ -0,0 +1,104 @@
1
+ #include <audioapi/core/AudioParam.h>
2
+ #include <audioapi/core/BaseAudioContext.h>
3
+ #include <audioapi/core/Constants.h>
4
+ #include <audioapi/core/sources/AudioBufferBaseSourceNode.h>
5
+ #include <audioapi/events/AudioEventHandlerRegistry.h>
6
+ #include <audioapi/utils/AudioArray.h>
7
+ #include <audioapi/utils/AudioBus.h>
8
+
9
+ namespace audioapi {
10
+ AudioBufferBaseSourceNode::AudioBufferBaseSourceNode(BaseAudioContext *context)
11
+ : AudioScheduledSourceNode(context), vReadIndex_(0.0) {
12
+ onPositionChangedInterval_ = static_cast<int>(context->getSampleRate() * 0.1);
13
+
14
+ detuneParam_ = std::make_shared<AudioParam>(
15
+ 0.0, MOST_NEGATIVE_SINGLE_FLOAT, MOST_POSITIVE_SINGLE_FLOAT, context);
16
+ playbackRateParam_ = std::make_shared<AudioParam>(
17
+ 1.0, MOST_NEGATIVE_SINGLE_FLOAT, MOST_POSITIVE_SINGLE_FLOAT, context);
18
+
19
+ playbackRateBus_ = std::make_shared<AudioBus>(
20
+ RENDER_QUANTUM_SIZE * 3, channelCount_, context_->getSampleRate());
21
+
22
+ stretch_ =
23
+ std::make_shared<signalsmith::stretch::SignalsmithStretch<float>>();
24
+ }
25
+
26
+ std::shared_ptr<AudioParam> AudioBufferBaseSourceNode::getDetuneParam() const {
27
+ return detuneParam_;
28
+ }
29
+
30
+ std::shared_ptr<AudioParam> AudioBufferBaseSourceNode::getPlaybackRateParam()
31
+ const {
32
+ return playbackRateParam_;
33
+ }
34
+
35
+ void AudioBufferBaseSourceNode::setOnPositionChangedCallbackId(
36
+ uint64_t callbackId) {
37
+ onPositionChangedCallbackId_ = callbackId;
38
+ }
39
+
40
+ void AudioBufferBaseSourceNode::setOnPositionChangedInterval(int interval) {
41
+ onPositionChangedInterval_ = static_cast<int>(
42
+ context_->getSampleRate() * static_cast<float>(interval) / 1000);
43
+ }
44
+
45
+ std::mutex &AudioBufferBaseSourceNode::getBufferLock() {
46
+ return bufferLock_;
47
+ }
48
+
49
+ void AudioBufferBaseSourceNode::sendOnPositionChangedEvent() {
50
+ if (onPositionChangedTime_ > onPositionChangedInterval_) {
51
+ std::unordered_map<std::string, EventValue> body = {
52
+ {"value", getCurrentPosition()}};
53
+
54
+ context_->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
55
+ "positionChanged", onPositionChangedCallbackId_, body);
56
+
57
+ onPositionChangedTime_ = 0;
58
+ }
59
+
60
+ onPositionChangedTime_ += RENDER_QUANTUM_SIZE;
61
+ }
62
+
63
+ void AudioBufferBaseSourceNode::processWithPitchCorrection(
64
+ const std::shared_ptr<AudioBus> &processingBus,
65
+ int framesToProcess) {
66
+ size_t startOffset = 0;
67
+ size_t offsetLength = 0;
68
+
69
+ auto time = context_->getCurrentTime();
70
+ auto playbackRate = std::clamp(
71
+ playbackRateParam_->processKRateParam(framesToProcess, time), 0.0f, 3.0f);
72
+ auto detune = std::clamp(
73
+ detuneParam_->processKRateParam(framesToProcess, time) / 100.0f,
74
+ -12.0f,
75
+ 12.0f);
76
+
77
+ playbackRateBus_->zero();
78
+
79
+ auto framesNeededToStretch =
80
+ static_cast<int>(playbackRate * static_cast<float>(framesToProcess));
81
+
82
+ updatePlaybackInfo(
83
+ playbackRateBus_, framesNeededToStretch, startOffset, offsetLength);
84
+
85
+ if (playbackRate == 0.0f || (!isPlaying() && !isStopScheduled())) {
86
+ processingBus->zero();
87
+ return;
88
+ }
89
+
90
+ processWithoutInterpolation(
91
+ playbackRateBus_, startOffset, offsetLength, playbackRate);
92
+
93
+ stretch_->process(
94
+ playbackRateBus_.get()[0],
95
+ framesNeededToStretch,
96
+ processingBus.get()[0],
97
+ framesToProcess);
98
+
99
+ if (detune != 0.0f) {
100
+ stretch_->setTransposeSemitones(detune);
101
+ }
102
+ }
103
+
104
+ } // namespace audioapi
@@ -0,0 +1,54 @@
1
+ #pragma once
2
+
3
+ #include <audioapi/core/sources/AudioScheduledSourceNode.h>
4
+ #include <audioapi/libs/signalsmith-stretch/signalsmith-stretch.h>
5
+
6
+ #include <memory>
7
+
8
+ namespace audioapi {
9
+
10
+ class AudioBus;
11
+ class AudioParam;
12
+
13
+ class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
14
+ public:
15
+ explicit AudioBufferBaseSourceNode(BaseAudioContext *context);
16
+
17
+ [[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
18
+ [[nodiscard]] std::shared_ptr<AudioParam> getPlaybackRateParam() const;
19
+
20
+ void setOnPositionChangedCallbackId(uint64_t callbackId);
21
+ void setOnPositionChangedInterval(int interval);
22
+
23
+ protected:
24
+ std::mutex bufferLock_;
25
+
26
+ // pitch correction
27
+ std::shared_ptr<signalsmith::stretch::SignalsmithStretch<float>> stretch_;
28
+ std::shared_ptr<AudioBus> playbackRateBus_;
29
+
30
+ // k-rate params
31
+ std::shared_ptr<AudioParam> detuneParam_;
32
+ std::shared_ptr<AudioParam> playbackRateParam_;
33
+
34
+ // internal helper
35
+ double vReadIndex_;
36
+
37
+ uint64_t onPositionChangedCallbackId_ = 0;
38
+ int onPositionChangedInterval_;
39
+ int onPositionChangedTime_ = 0;
40
+
41
+ std::mutex &getBufferLock();
42
+ virtual double getCurrentPosition() const = 0;
43
+
44
+ void sendOnPositionChangedEvent();
45
+ void processWithPitchCorrection(const std::shared_ptr<AudioBus> &processingBus,
46
+ int framesToProcess);
47
+ virtual void processWithoutInterpolation(
48
+ const std::shared_ptr<AudioBus>& processingBus,
49
+ size_t startOffset,
50
+ size_t offsetLength,
51
+ float playbackRate) = 0;
52
+ };
53
+
54
+ } // namespace audioapi
@@ -12,23 +12,10 @@ namespace audioapi {
12
12
 
13
13
  AudioBufferQueueSourceNode::AudioBufferQueueSourceNode(
14
14
  BaseAudioContext *context)
15
- : AudioScheduledSourceNode(context), vReadIndex_(0.0) {
15
+ : AudioBufferBaseSourceNode(context) {
16
16
  buffers_ = {};
17
-
18
- detuneParam_ = std::make_shared<AudioParam>(
19
- 0.0, MOST_NEGATIVE_SINGLE_FLOAT, MOST_POSITIVE_SINGLE_FLOAT, context);
20
- playbackRateParam_ = std::make_shared<AudioParam>(
21
- 1.0, MOST_NEGATIVE_SINGLE_FLOAT, MOST_POSITIVE_SINGLE_FLOAT, context);
22
-
23
- playbackRateBus_ = std::make_shared<AudioBus>(
24
- RENDER_QUANTUM_SIZE * 3, channelCount_, context_->getSampleRate());
25
-
26
- stretch_ =
27
- std::make_shared<signalsmith::stretch::SignalsmithStretch<float>>();
28
17
  stretch_->presetDefault(channelCount_, context_->getSampleRate(), true);
29
18
 
30
- onPositionChangedInterval_ = static_cast<int>(context_->getSampleRate() / 10);
31
-
32
19
  isInitialized_ = true;
33
20
  }
34
21
 
@@ -38,23 +25,6 @@ AudioBufferQueueSourceNode::~AudioBufferQueueSourceNode() {
38
25
  buffers_ = {};
39
26
  }
40
27
 
41
- std::shared_ptr<AudioParam> AudioBufferQueueSourceNode::getDetuneParam() const {
42
- return detuneParam_;
43
- }
44
-
45
- std::shared_ptr<AudioParam> AudioBufferQueueSourceNode::getPlaybackRateParam()
46
- const {
47
- return playbackRateParam_;
48
- }
49
-
50
- void AudioBufferQueueSourceNode::start(double when, double offset) {
51
- AudioScheduledSourceNode::start(when);
52
-
53
- if (offset >= 0.0) {
54
- vReadIndex_ = static_cast<double>(context_->getSampleRate() * offset);
55
- }
56
- }
57
-
58
28
  void AudioBufferQueueSourceNode::stop(double when) {
59
29
  AudioScheduledSourceNode::stop(when);
60
30
  isPaused_ = false;
@@ -67,10 +37,9 @@ void AudioBufferQueueSourceNode::pause() {
67
37
 
68
38
  void AudioBufferQueueSourceNode::enqueueBuffer(
69
39
  const std::shared_ptr<AudioBuffer> &buffer,
70
- int bufferId,
71
40
  bool isLastBuffer) {
72
41
  auto locker = Locker(getBufferLock());
73
- buffers_.emplace(bufferId, buffer);
42
+ buffers_.emplace(buffer);
74
43
 
75
44
  isLastBuffer_ = isLastBuffer;
76
45
  }
@@ -84,28 +53,10 @@ void AudioBufferQueueSourceNode::disable() {
84
53
  return;
85
54
  }
86
55
 
87
- audioapi::AudioNode::disable();
88
-
89
- std::string state = "stopped";
90
-
91
- // if it has not been stopped, it is ended
92
- if (stopTime_ < 0) {
93
- state = "ended";
94
- }
95
-
96
- std::unordered_map<std::string, EventValue> body = {
97
- {"value", getStopTime()}, {"state", state}, {"bufferId", bufferId_}};
98
-
99
- context_->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
100
- "ended", onEndedCallbackId_, body);
101
-
56
+ AudioScheduledSourceNode::disable();
102
57
  buffers_ = {};
103
58
  }
104
59
 
105
- std::mutex &AudioBufferQueueSourceNode::getBufferLock() {
106
- return bufferLock_;
107
- }
108
-
109
60
  void AudioBufferQueueSourceNode::processNode(
110
61
  const std::shared_ptr<AudioBus> &processingBus,
111
62
  int framesToProcess) {
@@ -119,97 +70,31 @@ void AudioBufferQueueSourceNode::processNode(
119
70
  processWithPitchCorrection(processingBus, framesToProcess);
120
71
 
121
72
  handleStopScheduled();
73
+ sendOnPositionChangedEvent();
122
74
  } else {
123
75
  processingBus->zero();
124
76
  }
125
77
  }
126
78
 
127
- double AudioBufferQueueSourceNode::getStopTime() const {
79
+ double AudioBufferQueueSourceNode::getCurrentPosition() const {
128
80
  return dsp::sampleFrameToTime(
129
- static_cast<int>(vReadIndex_), context_->getSampleRate());
130
- }
131
-
132
- void AudioBufferQueueSourceNode::setOnPositionChangedCallbackId(
133
- uint64_t callbackId) {
134
- onPositionChangedCallbackId_ = callbackId;
135
- }
136
-
137
- void AudioBufferQueueSourceNode::sendOnPositionChangedEvent() {
138
- if (onPositionChangedTime_ > onPositionChangedInterval_) {
139
- std::unordered_map<std::string, EventValue> body = {
140
- {"value", position_ + getStopTime()}};
141
-
142
- context_->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
143
- "positionChanged", onPositionChangedCallbackId_, body);
144
-
145
- onPositionChangedTime_ = 0;
146
- }
147
-
148
- onPositionChangedTime_ += RENDER_QUANTUM_SIZE;
149
- }
150
-
151
- void AudioBufferQueueSourceNode::setOnPositionChangedInterval(int interval) {
152
- onPositionChangedInterval_ = static_cast<int>(
153
- context_->getSampleRate() * static_cast<float>(interval) / 1000);
81
+ static_cast<int>(vReadIndex_), context_->getSampleRate()) +
82
+ playedBuffersDuration_;
154
83
  }
155
84
 
156
85
  /**
157
86
  * Helper functions
158
87
  */
159
88
 
160
- void AudioBufferQueueSourceNode::processWithPitchCorrection(
161
- const std::shared_ptr<AudioBus> &processingBus,
162
- int framesToProcess) {
163
- size_t startOffset = 0;
164
- size_t offsetLength = 0;
165
-
166
- auto time = context_->getCurrentTime();
167
- auto playbackRate = std::clamp(
168
- playbackRateParam_->processKRateParam(framesToProcess, time), 0.0f, 3.0f);
169
- auto detune = std::clamp(
170
- detuneParam_->processKRateParam(framesToProcess, time) / 100.0f,
171
- -12.0f,
172
- 12.0f);
173
-
174
- playbackRateBus_->zero();
175
-
176
- auto framesNeededToStretch =
177
- static_cast<int>(playbackRate * static_cast<float>(framesToProcess));
178
-
179
- updatePlaybackInfo(
180
- playbackRateBus_, framesNeededToStretch, startOffset, offsetLength);
181
-
182
- if (playbackRate == 0.0f || (!isPlaying() && !isStopScheduled())) {
183
- processingBus->zero();
184
- return;
185
- }
186
-
187
- // Send position changed event
188
- sendOnPositionChangedEvent();
189
-
190
- processWithoutInterpolation(playbackRateBus_, startOffset, offsetLength);
191
-
192
- stretch_->process(
193
- playbackRateBus_.get()[0],
194
- framesNeededToStretch,
195
- processingBus.get()[0],
196
- framesToProcess);
197
-
198
- if (detune != 0.0f) {
199
- stretch_->setTransposeSemitones(detune);
200
- }
201
- }
202
-
203
89
  void AudioBufferQueueSourceNode::processWithoutInterpolation(
204
90
  const std::shared_ptr<AudioBus> &processingBus,
205
91
  size_t startOffset,
206
- size_t offsetLength) {
92
+ size_t offsetLength,
93
+ float playbackRate) {
207
94
  auto readIndex = static_cast<size_t>(vReadIndex_);
208
95
  size_t writeIndex = startOffset;
209
96
 
210
- auto queueData = buffers_.front();
211
- bufferId_ = queueData.first;
212
- auto buffer = queueData.second;
97
+ auto buffer = buffers_.front();
213
98
 
214
99
  size_t framesLeft = offsetLength;
215
100
 
@@ -230,7 +115,7 @@ void AudioBufferQueueSourceNode::processWithoutInterpolation(
230
115
  framesLeft -= framesToCopy;
231
116
 
232
117
  if (readIndex >= buffer->getLength()) {
233
- position_ += buffer->getDuration();
118
+ playedBuffersDuration_ += buffer->getDuration();
234
119
  buffers_.pop();
235
120
 
236
121
  if (buffers_.empty()) {
@@ -242,9 +127,7 @@ void AudioBufferQueueSourceNode::processWithoutInterpolation(
242
127
  }
243
128
  break;
244
129
  } else {
245
- queueData = buffers_.front();
246
- bufferId_ = queueData.first;
247
- buffer = queueData.second;
130
+ buffer = buffers_.front();
248
131
 
249
132
  readIndex = 0;
250
133
  }
@@ -1,7 +1,7 @@
1
1
  #pragma once
2
2
 
3
3
  #include <audioapi/core/sources/AudioBuffer.h>
4
- #include <audioapi/core/sources/AudioScheduledSourceNode.h>
4
+ #include <audioapi/core/sources/AudioBufferBaseSourceNode.h>
5
5
  #include <audioapi/libs/signalsmith-stretch/signalsmith-stretch.h>
6
6
 
7
7
  #include <memory>
@@ -15,63 +15,34 @@ namespace audioapi {
15
15
  class AudioBus;
16
16
  class AudioParam;
17
17
 
18
- class AudioBufferQueueSourceNode : public AudioScheduledSourceNode {
18
+ class AudioBufferQueueSourceNode : public AudioBufferBaseSourceNode {
19
19
  public:
20
20
  explicit AudioBufferQueueSourceNode(BaseAudioContext *context);
21
21
  ~AudioBufferQueueSourceNode() override;
22
22
 
23
- [[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
24
- [[nodiscard]] std::shared_ptr<AudioParam> getPlaybackRateParam() const;
25
-
26
- void start(double when, double offset);
27
23
  void stop(double when) override;
28
24
  void pause();
29
25
 
30
- void enqueueBuffer(const std::shared_ptr<AudioBuffer> &buffer, int bufferId, bool isLastBuffer);
26
+ void enqueueBuffer(const std::shared_ptr<AudioBuffer> &buffer, bool isLastBuffer);
31
27
  void disable() override;
32
28
 
33
- void setOnPositionChangedCallbackId(uint64_t callbackId);
34
- void setOnPositionChangedInterval(int interval);
35
- void sendOnPositionChangedEvent();
36
-
37
29
  protected:
38
- std::mutex &getBufferLock();
39
30
  void processNode(const std::shared_ptr<AudioBus>& processingBus, int framesToProcess) override;
40
- double getStopTime() const override;
31
+ double getCurrentPosition() const override;
41
32
 
42
33
  private:
43
- std::mutex bufferLock_;
44
-
45
- // pitch correction
46
- std::shared_ptr<signalsmith::stretch::SignalsmithStretch<float>> stretch_;
47
- std::shared_ptr<AudioBus> playbackRateBus_;
48
-
49
- // k-rate params
50
- std::shared_ptr<AudioParam> detuneParam_;
51
- std::shared_ptr<AudioParam> playbackRateParam_;
52
-
53
- // internal helper
54
- double vReadIndex_;
55
-
56
34
  // User provided buffers
57
- std::queue<std::pair<int, std::shared_ptr<AudioBuffer>>> buffers_;
58
- int bufferId_ = 0;
35
+ std::queue<std::shared_ptr<AudioBuffer>> buffers_;
59
36
  bool isLastBuffer_ = false;
60
37
  bool isPaused_ = false;
61
38
 
62
- // positionChanged event props: callbackId, update interval in frames, time since last update in frames
63
- uint64_t onPositionChangedCallbackId_ = 0;
64
- int onPositionChangedInterval_;
65
- int onPositionChangedTime_ = 0;
66
- double position_ = 0;
67
-
68
- void processWithPitchCorrection(const std::shared_ptr<AudioBus> &processingBus,
69
- int framesToProcess);
39
+ double playedBuffersDuration_ = 0;
70
40
 
71
41
  void processWithoutInterpolation(
72
42
  const std::shared_ptr<AudioBus>& processingBus,
73
43
  size_t startOffset,
74
- size_t offsetLength);
44
+ size_t offsetLength,
45
+ float playbackRate) override;
75
46
  };
76
47
 
77
48
  } // namespace audioapi