react-native-audio-api 0.6.3-rc.1 → 0.6.4-nightly-a960beb-20250703
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/android/src/main/cpp/audioapi/android/AudioAPIModule.cpp +11 -3
- package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +1 -1
- package/android/src/main/java/com/swmansion/audioapi/system/AudioFocusListener.kt +5 -5
- package/android/src/main/java/com/swmansion/audioapi/system/LockScreenManager.kt +1 -2
- package/common/cpp/audioapi/HostObjects/AudioBufferBaseSourceNodeHostObject.h +8 -1
- package/common/cpp/audioapi/core/AudioContext.cpp +2 -1
- package/common/cpp/audioapi/core/AudioContext.h +1 -1
- package/common/cpp/audioapi/core/AudioParam.cpp +17 -5
- package/common/cpp/audioapi/core/AudioParam.h +3 -0
- package/common/cpp/audioapi/core/BaseAudioContext.cpp +7 -1
- package/common/cpp/audioapi/core/BaseAudioContext.h +5 -2
- package/common/cpp/audioapi/core/OfflineAudioContext.cpp +2 -1
- package/common/cpp/audioapi/core/OfflineAudioContext.h +1 -1
- package/common/cpp/audioapi/core/effects/PeriodicWave.cpp +1 -1
- package/common/cpp/audioapi/core/inputs/AudioRecorder.cpp +4 -2
- package/common/cpp/audioapi/core/inputs/AudioRecorder.h +1 -0
- package/common/cpp/audioapi/core/sources/AudioBuffer.h +1 -0
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.cpp +15 -1
- package/common/cpp/audioapi/core/sources/AudioBufferBaseSourceNode.h +7 -4
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.cpp +13 -2
- package/common/cpp/audioapi/core/sources/AudioScheduledSourceNode.h +1 -0
- package/common/cpp/audioapi/core/utils/AudioNodeDestructor.h +1 -0
- package/common/cpp/audioapi/core/utils/AudioNodeManager.h +1 -2
- package/common/cpp/audioapi/dsp/AudioUtils.cpp +1 -1
- package/common/cpp/audioapi/events/AudioEventHandlerRegistry.cpp +80 -29
- package/common/cpp/audioapi/events/AudioEventHandlerRegistry.h +9 -5
- package/common/cpp/audioapi/events/IAudioEventHandlerRegistry.h +25 -0
- package/common/cpp/audioapi/utils/AudioArray.h +1 -0
- package/common/cpp/audioapi/utils/CircularAudioArray.h +1 -0
- package/common/cpp/test/CMakeLists.txt +79 -0
- package/common/cpp/test/MockAudioEventHandlerRegistry.h +22 -0
- package/common/cpp/test/OscillatorTest.cpp +22 -0
- package/common/cpp/test/RunTests.sh +26 -0
- package/ios/audioapi/ios/AudioAPIModule.mm +11 -12
- package/lib/commonjs/core/AudioBufferBaseSourceNode.js +10 -6
- package/lib/commonjs/core/AudioBufferBaseSourceNode.js.map +1 -1
- package/lib/commonjs/core/AudioScheduledSourceNode.js +6 -2
- package/lib/commonjs/core/AudioScheduledSourceNode.js.map +1 -1
- package/lib/module/core/AudioBufferBaseSourceNode.js +10 -6
- package/lib/module/core/AudioBufferBaseSourceNode.js.map +1 -1
- package/lib/module/core/AudioScheduledSourceNode.js +6 -2
- package/lib/module/core/AudioScheduledSourceNode.js.map +1 -1
- package/lib/typescript/core/AudioBufferBaseSourceNode.d.ts +6 -3
- package/lib/typescript/core/AudioBufferBaseSourceNode.d.ts.map +1 -1
- package/lib/typescript/core/AudioScheduledSourceNode.d.ts +2 -0
- package/lib/typescript/core/AudioScheduledSourceNode.d.ts.map +1 -1
- package/package.json +9 -9
- package/src/core/AudioBufferBaseSourceNode.ts +20 -7
- package/src/core/AudioScheduledSourceNode.ts +9 -1
|
@@ -58,11 +58,19 @@ void AudioAPIModule::invokeHandlerWithEventNameAndEventBody(
|
|
|
58
58
|
} else if (value->isInstanceOf(jni::JFloat::javaClassStatic())) {
|
|
59
59
|
body[name] = jni::static_ref_cast<jni::JFloat>(value)->value();
|
|
60
60
|
} else if (value->isInstanceOf(jni::JBoolean::javaClassStatic())) {
|
|
61
|
-
|
|
61
|
+
auto booleanValue = jni::static_ref_cast<jni::JBoolean>(value)->value();
|
|
62
|
+
|
|
63
|
+
if (booleanValue) {
|
|
64
|
+
body[name] = true;
|
|
65
|
+
} else {
|
|
66
|
+
body[name] = false;
|
|
67
|
+
}
|
|
62
68
|
}
|
|
63
69
|
}
|
|
64
70
|
|
|
65
|
-
audioEventHandlerRegistry_
|
|
66
|
-
|
|
71
|
+
if (audioEventHandlerRegistry_ != nullptr) {
|
|
72
|
+
audioEventHandlerRegistry_->invokeHandlerWithEventBody(
|
|
73
|
+
eventName->toStdString(), body);
|
|
74
|
+
}
|
|
67
75
|
}
|
|
68
76
|
} // namespace audioapi
|
|
@@ -13,7 +13,7 @@ class AudioFocusListener(
|
|
|
13
13
|
private val audioAPIModule: WeakReference<AudioAPIModule>,
|
|
14
14
|
private val lockScreenManager: WeakReference<LockScreenManager>,
|
|
15
15
|
) : AudioManager.OnAudioFocusChangeListener {
|
|
16
|
-
private var playOnAudioFocus = false
|
|
16
|
+
private var playOnAudioFocus: Boolean = false
|
|
17
17
|
private var focusRequest: AudioFocusRequest? = null
|
|
18
18
|
|
|
19
19
|
override fun onAudioFocusChange(focusChange: Int) {
|
|
@@ -23,7 +23,7 @@ class AudioFocusListener(
|
|
|
23
23
|
playOnAudioFocus = false
|
|
24
24
|
val body =
|
|
25
25
|
HashMap<String, Any>().apply {
|
|
26
|
-
put("
|
|
26
|
+
put("type", "began")
|
|
27
27
|
put("shouldResume", false)
|
|
28
28
|
}
|
|
29
29
|
audioAPIModule.get()?.invokeHandlerWithEventNameAndEventBody("interruption", body)
|
|
@@ -32,7 +32,7 @@ class AudioFocusListener(
|
|
|
32
32
|
playOnAudioFocus = lockScreenManager.get()?.isPlaying == true
|
|
33
33
|
val body =
|
|
34
34
|
HashMap<String, Any>().apply {
|
|
35
|
-
put("
|
|
35
|
+
put("type", "began")
|
|
36
36
|
put("shouldResume", playOnAudioFocus)
|
|
37
37
|
}
|
|
38
38
|
audioAPIModule.get()?.invokeHandlerWithEventNameAndEventBody("interruption", body)
|
|
@@ -41,14 +41,14 @@ class AudioFocusListener(
|
|
|
41
41
|
if (playOnAudioFocus) {
|
|
42
42
|
val body =
|
|
43
43
|
HashMap<String, Any>().apply {
|
|
44
|
-
put("
|
|
44
|
+
put("type", "ended")
|
|
45
45
|
put("shouldResume", true)
|
|
46
46
|
}
|
|
47
47
|
audioAPIModule.get()?.invokeHandlerWithEventNameAndEventBody("interruption", body)
|
|
48
48
|
} else {
|
|
49
49
|
val body =
|
|
50
50
|
HashMap<String, Any>().apply {
|
|
51
|
-
put("
|
|
51
|
+
put("type", "ended")
|
|
52
52
|
put("shouldResume", false)
|
|
53
53
|
}
|
|
54
54
|
audioAPIModule.get()?.invokeHandlerWithEventNameAndEventBody("interruption", body)
|
|
@@ -12,7 +12,6 @@ import androidx.media.app.NotificationCompat.MediaStyle
|
|
|
12
12
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
13
13
|
import com.facebook.react.bridge.ReadableMap
|
|
14
14
|
import com.facebook.react.bridge.ReadableType
|
|
15
|
-
import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper.Companion.instance
|
|
16
15
|
import com.swmansion.audioapi.R
|
|
17
16
|
import java.io.IOException
|
|
18
17
|
import java.lang.ref.WeakReference
|
|
@@ -250,7 +249,7 @@ class LockScreenManager(
|
|
|
250
249
|
// If we are running the app in debug mode, the "local" image will be served from htt://localhost:8080, so we need to check for this case and load those images from URL
|
|
251
250
|
if (local && !url.startsWith("http")) {
|
|
252
251
|
// Gets the drawable from the RN's helper for local resources
|
|
253
|
-
val helper = instance
|
|
252
|
+
val helper = com.facebook.react.views.imagehelper.ResourceDrawableIdHelper.instance
|
|
254
253
|
val image = helper.getResourceDrawable(reactContext.get()!!, url)
|
|
255
254
|
|
|
256
255
|
bitmap =
|
|
@@ -18,7 +18,8 @@ class AudioBufferBaseSourceNodeHostObject
|
|
|
18
18
|
: AudioScheduledSourceNodeHostObject(node) {
|
|
19
19
|
addGetters(
|
|
20
20
|
JSI_EXPORT_PROPERTY_GETTER(AudioBufferBaseSourceNodeHostObject, detune),
|
|
21
|
-
JSI_EXPORT_PROPERTY_GETTER(AudioBufferBaseSourceNodeHostObject, playbackRate)
|
|
21
|
+
JSI_EXPORT_PROPERTY_GETTER(AudioBufferBaseSourceNodeHostObject, playbackRate),
|
|
22
|
+
JSI_EXPORT_PROPERTY_GETTER(AudioBufferBaseSourceNodeHostObject, onPositionChangedInterval));
|
|
22
23
|
|
|
23
24
|
addSetters(
|
|
24
25
|
JSI_EXPORT_PROPERTY_SETTER(AudioBufferBaseSourceNodeHostObject, onPositionChanged),
|
|
@@ -49,6 +50,12 @@ class AudioBufferBaseSourceNodeHostObject
|
|
|
49
50
|
sourceNode->setOnPositionChangedCallbackId(std::stoull(value.getString(runtime).utf8(runtime)));
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
JSI_PROPERTY_GETTER(onPositionChangedInterval) {
|
|
54
|
+
auto sourceNode =
|
|
55
|
+
std::static_pointer_cast<AudioBufferBaseSourceNode>(node_);
|
|
56
|
+
return jsi::Value(sourceNode->getOnPositionChangedInterval());
|
|
57
|
+
}
|
|
58
|
+
|
|
52
59
|
JSI_PROPERTY_SETTER(onPositionChangedInterval) {
|
|
53
60
|
auto sourceNode =
|
|
54
61
|
std::static_pointer_cast<AudioBufferBaseSourceNode>(node_);
|
|
@@ -13,7 +13,8 @@ namespace audioapi {
|
|
|
13
13
|
AudioContext::AudioContext(
|
|
14
14
|
float sampleRate,
|
|
15
15
|
bool initSuspended,
|
|
16
|
-
const std::shared_ptr<
|
|
16
|
+
const std::shared_ptr<IAudioEventHandlerRegistry>
|
|
17
|
+
&audioEventHandlerRegistry)
|
|
17
18
|
: BaseAudioContext(audioEventHandlerRegistry) {
|
|
18
19
|
#ifdef ANDROID
|
|
19
20
|
audioPlayer_ = std::make_shared<AudioPlayer>(this->renderAudio(), sampleRate);
|
|
@@ -14,7 +14,7 @@ class IOSAudioPlayer;
|
|
|
14
14
|
|
|
15
15
|
class AudioContext : public BaseAudioContext {
|
|
16
16
|
public:
|
|
17
|
-
explicit AudioContext(float sampleRate, bool initSuspended, const std::shared_ptr<
|
|
17
|
+
explicit AudioContext(float sampleRate, bool initSuspended, const std::shared_ptr<IAudioEventHandlerRegistry> &audioEventHandlerRegistry);
|
|
18
18
|
~AudioContext() override;
|
|
19
19
|
|
|
20
20
|
void close();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#include <audioapi/core/AudioParam.h>
|
|
2
2
|
#include <audioapi/core/BaseAudioContext.h>
|
|
3
|
+
#include <audioapi/core/utils/Locker.h>
|
|
3
4
|
#include <audioapi/dsp/AudioUtils.h>
|
|
4
5
|
#include <audioapi/dsp/VectorMath.h>
|
|
5
6
|
#include <audioapi/utils/AudioArray.h>
|
|
@@ -17,11 +18,10 @@ AudioParam::AudioParam(
|
|
|
17
18
|
minValue_(minValue),
|
|
18
19
|
maxValue_(maxValue),
|
|
19
20
|
context_(context),
|
|
20
|
-
audioBus_(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
context->getSampleRate())) {
|
|
21
|
+
audioBus_(std::make_shared<AudioBus>(
|
|
22
|
+
RENDER_QUANTUM_SIZE,
|
|
23
|
+
1,
|
|
24
|
+
context->getSampleRate())) {
|
|
25
25
|
startTime_ = 0;
|
|
26
26
|
endTime_ = 0;
|
|
27
27
|
startValue_ = value_;
|
|
@@ -47,11 +47,16 @@ float AudioParam::getMaxValue() const {
|
|
|
47
47
|
return maxValue_;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
std::mutex &AudioParam::getQueueLock() {
|
|
51
|
+
return queueLock_;
|
|
52
|
+
}
|
|
53
|
+
|
|
50
54
|
void AudioParam::setValue(float value) {
|
|
51
55
|
value_ = std::clamp(value, minValue_, maxValue_);
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
float AudioParam::getValueAtTime(double time) {
|
|
59
|
+
Locker lock(getQueueLock());
|
|
55
60
|
if (endTime_ < time && !eventsQueue_.empty()) {
|
|
56
61
|
auto event = eventsQueue_.front();
|
|
57
62
|
startTime_ = event.getStartTime();
|
|
@@ -84,6 +89,7 @@ void AudioParam::setValueAtTime(float value, double startTime) {
|
|
|
84
89
|
return endValue;
|
|
85
90
|
};
|
|
86
91
|
|
|
92
|
+
Locker lock(getQueueLock());
|
|
87
93
|
auto event = ParamChangeEvent(
|
|
88
94
|
startTime,
|
|
89
95
|
startTime,
|
|
@@ -117,6 +123,7 @@ void AudioParam::linearRampToValueAtTime(float value, double endTime) {
|
|
|
117
123
|
return endValue;
|
|
118
124
|
};
|
|
119
125
|
|
|
126
|
+
Locker lock(getQueueLock());
|
|
120
127
|
auto event = ParamChangeEvent(
|
|
121
128
|
getQueueEndTime(),
|
|
122
129
|
endTime,
|
|
@@ -151,6 +158,7 @@ void AudioParam::exponentialRampToValueAtTime(float value, double endTime) {
|
|
|
151
158
|
return endValue;
|
|
152
159
|
};
|
|
153
160
|
|
|
161
|
+
Locker lock(getQueueLock());
|
|
154
162
|
auto event = ParamChangeEvent(
|
|
155
163
|
getQueueEndTime(),
|
|
156
164
|
endTime,
|
|
@@ -181,6 +189,7 @@ void AudioParam::setTargetAtTime(
|
|
|
181
189
|
(startValue - target) * exp(-(time - startTime) / timeConstant));
|
|
182
190
|
};
|
|
183
191
|
|
|
192
|
+
Locker lock(getQueueLock());
|
|
184
193
|
auto event = ParamChangeEvent(
|
|
185
194
|
startTime,
|
|
186
195
|
startTime,
|
|
@@ -225,6 +234,7 @@ void AudioParam::setValueCurveAtTime(
|
|
|
225
234
|
return endValue;
|
|
226
235
|
};
|
|
227
236
|
|
|
237
|
+
Locker lock(getQueueLock());
|
|
228
238
|
auto event = ParamChangeEvent(
|
|
229
239
|
startTime,
|
|
230
240
|
startTime + duration,
|
|
@@ -236,6 +246,7 @@ void AudioParam::setValueCurveAtTime(
|
|
|
236
246
|
}
|
|
237
247
|
|
|
238
248
|
void AudioParam::cancelScheduledValues(double cancelTime) {
|
|
249
|
+
Locker lock(getQueueLock());
|
|
239
250
|
auto it = eventsQueue_.rbegin();
|
|
240
251
|
while (it->getEndTime() >= cancelTime) {
|
|
241
252
|
if (it->getStartTime() >= cancelTime ||
|
|
@@ -248,6 +259,7 @@ void AudioParam::cancelScheduledValues(double cancelTime) {
|
|
|
248
259
|
}
|
|
249
260
|
|
|
250
261
|
void AudioParam::cancelAndHoldAtTime(double cancelTime) {
|
|
262
|
+
Locker lock(getQueueLock());
|
|
251
263
|
auto it = eventsQueue_.rbegin();
|
|
252
264
|
while (it->getEndTime() >= cancelTime) {
|
|
253
265
|
if (it->getStartTime() >= cancelTime) {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
#include <vector>
|
|
11
11
|
#include <unordered_set>
|
|
12
12
|
#include <cstddef>
|
|
13
|
+
#include <mutex>
|
|
13
14
|
|
|
14
15
|
namespace audioapi {
|
|
15
16
|
|
|
@@ -50,6 +51,7 @@ class AudioParam {
|
|
|
50
51
|
std::deque<ParamChangeEvent> eventsQueue_;
|
|
51
52
|
std::unordered_set<AudioNode *> inputNodes_;
|
|
52
53
|
std::shared_ptr<AudioBus> audioBus_;
|
|
54
|
+
std::mutex queueLock_;
|
|
53
55
|
|
|
54
56
|
double startTime_;
|
|
55
57
|
double endTime_;
|
|
@@ -58,6 +60,7 @@ class AudioParam {
|
|
|
58
60
|
std::function<float(double, double, float, float, double)> calculateValue_;
|
|
59
61
|
std::vector<std::shared_ptr<AudioBus>> inputBuses_ = {};
|
|
60
62
|
|
|
63
|
+
std::mutex &getQueueLock();
|
|
61
64
|
double getQueueEndTime();
|
|
62
65
|
float getQueueEndValue();
|
|
63
66
|
void updateQueue(ParamChangeEvent &event);
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
namespace audioapi {
|
|
20
20
|
|
|
21
21
|
BaseAudioContext::BaseAudioContext(
|
|
22
|
-
const std::shared_ptr<
|
|
22
|
+
const std::shared_ptr<IAudioEventHandlerRegistry>
|
|
23
23
|
&audioEventHandlerRegistry) {
|
|
24
24
|
nodeManager_ = std::make_shared<AudioNodeManager>();
|
|
25
25
|
destination_ = std::make_shared<AudioDestinationNode>(this);
|
|
@@ -119,6 +119,7 @@ std::shared_ptr<AnalyserNode> BaseAudioContext::createAnalyser() {
|
|
|
119
119
|
|
|
120
120
|
std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioDataSource(
|
|
121
121
|
const std::string &path) {
|
|
122
|
+
#ifndef AUDIO_API_TEST_SUITE
|
|
122
123
|
auto audioBus = audioDecoder_->decodeWithFilePath(path);
|
|
123
124
|
|
|
124
125
|
if (!audioBus) {
|
|
@@ -126,11 +127,13 @@ std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioDataSource(
|
|
|
126
127
|
}
|
|
127
128
|
|
|
128
129
|
return std::make_shared<AudioBuffer>(audioBus);
|
|
130
|
+
#endif // AUDIO_API_TEST_SUITE
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioData(
|
|
132
134
|
const void *data,
|
|
133
135
|
size_t size) {
|
|
136
|
+
#ifndef AUDIO_API_TEST_SUITE
|
|
134
137
|
auto audioBus = audioDecoder_->decodeWithMemoryBlock(data, size);
|
|
135
138
|
|
|
136
139
|
if (!audioBus) {
|
|
@@ -138,10 +141,12 @@ std::shared_ptr<AudioBuffer> BaseAudioContext::decodeAudioData(
|
|
|
138
141
|
}
|
|
139
142
|
|
|
140
143
|
return std::make_shared<AudioBuffer>(audioBus);
|
|
144
|
+
#endif // AUDIO_API_TEST_SUITE
|
|
141
145
|
}
|
|
142
146
|
|
|
143
147
|
std::shared_ptr<AudioBuffer> BaseAudioContext::decodeWithPCMInBase64(
|
|
144
148
|
const std::string &data) {
|
|
149
|
+
#ifndef AUDIO_API_TEST_SUITE
|
|
145
150
|
auto audioBus = audioDecoder_->decodeWithPCMInBase64(data);
|
|
146
151
|
|
|
147
152
|
if (!audioBus) {
|
|
@@ -149,6 +154,7 @@ std::shared_ptr<AudioBuffer> BaseAudioContext::decodeWithPCMInBase64(
|
|
|
149
154
|
}
|
|
150
155
|
|
|
151
156
|
return std::make_shared<AudioBuffer>(audioBus);
|
|
157
|
+
#endif // AUDIO_API_TEST_SUITE
|
|
152
158
|
}
|
|
153
159
|
|
|
154
160
|
AudioNodeManager *BaseAudioContext::getNodeManager() {
|
|
@@ -29,10 +29,11 @@ class AudioBufferQueueSourceNode;
|
|
|
29
29
|
class AudioDecoder;
|
|
30
30
|
class AnalyserNode;
|
|
31
31
|
class AudioEventHandlerRegistry;
|
|
32
|
+
class IAudioEventHandlerRegistry;
|
|
32
33
|
|
|
33
34
|
class BaseAudioContext {
|
|
34
35
|
public:
|
|
35
|
-
explicit BaseAudioContext(const std::shared_ptr<
|
|
36
|
+
explicit BaseAudioContext(const std::shared_ptr<IAudioEventHandlerRegistry> &audioEventHandlerRegistry);
|
|
36
37
|
virtual ~BaseAudioContext() = default;
|
|
37
38
|
|
|
38
39
|
std::string getState();
|
|
@@ -56,9 +57,11 @@ class BaseAudioContext {
|
|
|
56
57
|
int length);
|
|
57
58
|
std::shared_ptr<AnalyserNode> createAnalyser();
|
|
58
59
|
|
|
60
|
+
#ifndef TESTING
|
|
59
61
|
std::shared_ptr<AudioBuffer> decodeAudioDataSource(const std::string &path);
|
|
60
62
|
std::shared_ptr<AudioBuffer> decodeAudioData(const void *data, size_t size);
|
|
61
63
|
std::shared_ptr<AudioBuffer> decodeWithPCMInBase64(const std::string &data);
|
|
64
|
+
#endif //TESTING
|
|
62
65
|
|
|
63
66
|
std::shared_ptr<PeriodicWave> getBasicWaveForm(OscillatorType type);
|
|
64
67
|
[[nodiscard]] float getNyquistFrequency() const;
|
|
@@ -86,7 +89,7 @@ class BaseAudioContext {
|
|
|
86
89
|
std::shared_ptr<PeriodicWave> cachedTriangleWave_ = nullptr;
|
|
87
90
|
|
|
88
91
|
public:
|
|
89
|
-
std::shared_ptr<
|
|
92
|
+
std::shared_ptr<IAudioEventHandlerRegistry> audioEventHandlerRegistry_;
|
|
90
93
|
};
|
|
91
94
|
|
|
92
95
|
} // namespace audioapi
|
|
@@ -22,7 +22,8 @@ OfflineAudioContext::OfflineAudioContext(
|
|
|
22
22
|
int numberOfChannels,
|
|
23
23
|
size_t length,
|
|
24
24
|
float sampleRate,
|
|
25
|
-
const std::shared_ptr<
|
|
25
|
+
const std::shared_ptr<IAudioEventHandlerRegistry>
|
|
26
|
+
&audioEventHandlerRegistry)
|
|
26
27
|
: BaseAudioContext(audioEventHandlerRegistry),
|
|
27
28
|
length_(length),
|
|
28
29
|
numberOfChannels_(numberOfChannels),
|
|
@@ -14,7 +14,7 @@ using OfflineAudioContextResultCallback = std::function<void(std::shared_ptr<Aud
|
|
|
14
14
|
|
|
15
15
|
class OfflineAudioContext : public BaseAudioContext {
|
|
16
16
|
public:
|
|
17
|
-
explicit OfflineAudioContext(int numberOfChannels, size_t length, float sampleRate, const std::shared_ptr<
|
|
17
|
+
explicit OfflineAudioContext(int numberOfChannels, size_t length, float sampleRate, const std::shared_ptr<IAudioEventHandlerRegistry> &audioEventHandlerRegistry);
|
|
18
18
|
~OfflineAudioContext() override;
|
|
19
19
|
|
|
20
20
|
void resume();
|
|
@@ -118,7 +118,7 @@ int PeriodicWave::getNumberOfPartialsPerRange(int rangeIndex) const {
|
|
|
118
118
|
auto centsToCull = static_cast<float>(rangeIndex) * CentsPerRange;
|
|
119
119
|
|
|
120
120
|
// A value from 0 -> 1 representing what fraction of the partials to keep.
|
|
121
|
-
auto cullingScale = std::
|
|
121
|
+
auto cullingScale = std::pow(2, -centsToCull / 1200);
|
|
122
122
|
|
|
123
123
|
// The very top range will have all the partials culled.
|
|
124
124
|
int numberOfPartials =
|
|
@@ -36,8 +36,10 @@ void AudioRecorder::invokeOnAudioReadyCallback(
|
|
|
36
36
|
body.insert({"numFrames", numFrames});
|
|
37
37
|
body.insert({"when", when});
|
|
38
38
|
|
|
39
|
-
audioEventHandlerRegistry_
|
|
40
|
-
|
|
39
|
+
if (audioEventHandlerRegistry_ != nullptr) {
|
|
40
|
+
audioEventHandlerRegistry_->invokeHandlerWithEventBody(
|
|
41
|
+
"audioReady", onAudioReadyCallbackId_, body);
|
|
42
|
+
}
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
void AudioRecorder::sendRemainingData() {
|
|
@@ -23,6 +23,15 @@ AudioBufferBaseSourceNode::AudioBufferBaseSourceNode(BaseAudioContext *context)
|
|
|
23
23
|
std::make_shared<signalsmith::stretch::SignalsmithStretch<float>>();
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
AudioBufferBaseSourceNode::~AudioBufferBaseSourceNode() {
|
|
27
|
+
if (onPositionChangedCallbackId_ != 0 &&
|
|
28
|
+
context_->audioEventHandlerRegistry_ != nullptr) {
|
|
29
|
+
context_->audioEventHandlerRegistry_->unregisterHandler(
|
|
30
|
+
"positionChanged", onPositionChangedCallbackId_);
|
|
31
|
+
onPositionChangedCallbackId_ = 0;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
26
35
|
std::shared_ptr<AudioParam> AudioBufferBaseSourceNode::getDetuneParam() const {
|
|
27
36
|
return detuneParam_;
|
|
28
37
|
}
|
|
@@ -42,13 +51,18 @@ void AudioBufferBaseSourceNode::setOnPositionChangedInterval(int interval) {
|
|
|
42
51
|
context_->getSampleRate() * static_cast<float>(interval) / 1000);
|
|
43
52
|
}
|
|
44
53
|
|
|
54
|
+
int AudioBufferBaseSourceNode::getOnPositionChangedInterval() {
|
|
55
|
+
return onPositionChangedInterval_;
|
|
56
|
+
}
|
|
57
|
+
|
|
45
58
|
std::mutex &AudioBufferBaseSourceNode::getBufferLock() {
|
|
46
59
|
return bufferLock_;
|
|
47
60
|
}
|
|
48
61
|
|
|
49
62
|
void AudioBufferBaseSourceNode::sendOnPositionChangedEvent() {
|
|
50
63
|
if (onPositionChangedCallbackId_ != 0 &&
|
|
51
|
-
onPositionChangedTime_ > onPositionChangedInterval_
|
|
64
|
+
onPositionChangedTime_ > onPositionChangedInterval_ &&
|
|
65
|
+
context_->audioEventHandlerRegistry_ != nullptr) {
|
|
52
66
|
std::unordered_map<std::string, EventValue> body = {
|
|
53
67
|
{"value", getCurrentPosition()}};
|
|
54
68
|
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
#include <audioapi/libs/signalsmith-stretch/signalsmith-stretch.h>
|
|
5
5
|
|
|
6
6
|
#include <memory>
|
|
7
|
+
#include <mutex>
|
|
7
8
|
|
|
8
9
|
namespace audioapi {
|
|
9
10
|
|
|
@@ -13,12 +14,14 @@ class AudioParam;
|
|
|
13
14
|
class AudioBufferBaseSourceNode : public AudioScheduledSourceNode {
|
|
14
15
|
public:
|
|
15
16
|
explicit AudioBufferBaseSourceNode(BaseAudioContext *context);
|
|
17
|
+
virtual ~AudioBufferBaseSourceNode();
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
[[nodiscard]] std::shared_ptr<AudioParam> getDetuneParam() const;
|
|
20
|
+
[[nodiscard]] std::shared_ptr<AudioParam> getPlaybackRateParam() const;
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
void setOnPositionChangedCallbackId(uint64_t callbackId);
|
|
23
|
+
void setOnPositionChangedInterval(int interval);
|
|
24
|
+
[[nodiscard]] int getOnPositionChangedInterval();
|
|
22
25
|
|
|
23
26
|
protected:
|
|
24
27
|
std::mutex bufferLock_;
|
|
@@ -16,6 +16,15 @@ AudioScheduledSourceNode::AudioScheduledSourceNode(BaseAudioContext *context)
|
|
|
16
16
|
numberOfInputs_ = 0;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
AudioScheduledSourceNode::~AudioScheduledSourceNode() {
|
|
20
|
+
if (onEndedCallbackId_ != 0 &&
|
|
21
|
+
context_->audioEventHandlerRegistry_ != nullptr) {
|
|
22
|
+
context_->audioEventHandlerRegistry_->unregisterHandler(
|
|
23
|
+
"ended", onEndedCallbackId_);
|
|
24
|
+
onEndedCallbackId_ = 0;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
19
28
|
void AudioScheduledSourceNode::start(double when) {
|
|
20
29
|
playbackState_ = PlaybackState::SCHEDULED;
|
|
21
30
|
startTime_ = when;
|
|
@@ -149,8 +158,10 @@ void AudioScheduledSourceNode::updatePlaybackInfo(
|
|
|
149
158
|
void AudioScheduledSourceNode::disable() {
|
|
150
159
|
AudioNode::disable();
|
|
151
160
|
|
|
152
|
-
context_->audioEventHandlerRegistry_
|
|
153
|
-
|
|
161
|
+
if (context_->audioEventHandlerRegistry_ != nullptr) {
|
|
162
|
+
context_->audioEventHandlerRegistry_->invokeHandlerWithEventBody(
|
|
163
|
+
"ended", onEndedCallbackId_, {});
|
|
164
|
+
}
|
|
154
165
|
}
|
|
155
166
|
|
|
156
167
|
void AudioScheduledSourceNode::handleStopScheduled() {
|
|
@@ -27,6 +27,7 @@ class AudioScheduledSourceNode : public AudioNode {
|
|
|
27
27
|
// FINISHED: The node has finished playing.
|
|
28
28
|
enum class PlaybackState { UNSCHEDULED, SCHEDULED, PLAYING, STOP_SCHEDULED, FINISHED };
|
|
29
29
|
explicit AudioScheduledSourceNode(BaseAudioContext *context);
|
|
30
|
+
virtual ~AudioScheduledSourceNode();
|
|
30
31
|
|
|
31
32
|
void start(double when);
|
|
32
33
|
virtual void stop(double when);
|
|
@@ -20,8 +20,6 @@ class AudioNodeManager {
|
|
|
20
20
|
AudioNodeManager() = default;
|
|
21
21
|
~AudioNodeManager();
|
|
22
22
|
|
|
23
|
-
std::mutex &getGraphLock();
|
|
24
|
-
|
|
25
23
|
void preProcessGraph();
|
|
26
24
|
|
|
27
25
|
void addPendingNodeConnection(
|
|
@@ -62,6 +60,7 @@ class AudioNodeManager {
|
|
|
62
60
|
ConnectionType>>
|
|
63
61
|
audioParamToConnect_;
|
|
64
62
|
|
|
63
|
+
std::mutex &getGraphLock();
|
|
65
64
|
void settlePendingConnections();
|
|
66
65
|
void cleanupNode(const std::shared_ptr<AudioNode> &node);
|
|
67
66
|
void prepareNodesForDestruction();
|