react-native-audio-api 0.11.0-nightly-befc3c6-20251202 → 0.11.0-nightly-1ca2db9-20251204
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 +0 -5
- package/android/src/main/cpp/audioapi/android/AudioAPIModule.h +0 -1
- package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +1 -4
- package/common/cpp/audioapi/AudioAPIModuleInstaller.h +0 -17
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +11 -0
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +1 -0
- package/common/cpp/audioapi/HostObjects/effects/DelayNodeHostObject.cpp +27 -0
- package/common/cpp/audioapi/HostObjects/effects/DelayNodeHostObject.h +21 -0
- package/common/cpp/audioapi/core/AudioNode.cpp +4 -0
- package/common/cpp/audioapi/core/AudioNode.h +3 -0
- package/common/cpp/audioapi/core/BaseAudioContext.cpp +7 -0
- package/common/cpp/audioapi/core/BaseAudioContext.h +2 -0
- package/common/cpp/audioapi/core/effects/ConvolverNode.cpp +1 -0
- package/common/cpp/audioapi/core/effects/DelayNode.cpp +101 -0
- package/common/cpp/audioapi/core/effects/DelayNode.h +39 -0
- package/common/cpp/audioapi/core/effects/IIRFilterNode.h +0 -1
- package/common/cpp/audioapi/core/utils/AudioNodeManager.cpp +3 -1
- package/common/cpp/test/src/DelayTest.cpp +108 -0
- package/ios/audioapi/ios/AudioAPIModule.mm +0 -2
- package/lib/commonjs/core/AudioNode.js +1 -1
- package/lib/commonjs/core/AudioNode.js.map +1 -1
- package/lib/commonjs/core/BaseAudioContext.js +5 -0
- package/lib/commonjs/core/BaseAudioContext.js.map +1 -1
- package/lib/commonjs/core/DelayNode.js +17 -0
- package/lib/commonjs/core/DelayNode.js.map +1 -0
- package/lib/commonjs/web-core/AudioContext.js +4 -0
- package/lib/commonjs/web-core/AudioContext.js.map +1 -1
- package/lib/commonjs/web-core/DelayNode.js +17 -0
- package/lib/commonjs/web-core/DelayNode.js.map +1 -0
- package/lib/commonjs/web-core/OfflineAudioContext.js +4 -0
- package/lib/commonjs/web-core/OfflineAudioContext.js.map +1 -1
- package/lib/module/core/AudioNode.js +1 -1
- package/lib/module/core/AudioNode.js.map +1 -1
- package/lib/module/core/BaseAudioContext.js +5 -0
- package/lib/module/core/BaseAudioContext.js.map +1 -1
- package/lib/module/core/DelayNode.js +11 -0
- package/lib/module/core/DelayNode.js.map +1 -0
- package/lib/module/web-core/AudioContext.js +4 -0
- package/lib/module/web-core/AudioContext.js.map +1 -1
- package/lib/module/web-core/DelayNode.js +11 -0
- package/lib/module/web-core/DelayNode.js.map +1 -0
- package/lib/module/web-core/OfflineAudioContext.js +4 -0
- package/lib/module/web-core/OfflineAudioContext.js.map +1 -1
- package/lib/typescript/core/AudioNode.d.ts +2 -1
- package/lib/typescript/core/AudioNode.d.ts.map +1 -1
- package/lib/typescript/core/BaseAudioContext.d.ts +2 -0
- package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/core/DelayNode.d.ts +9 -0
- package/lib/typescript/core/DelayNode.d.ts.map +1 -0
- package/lib/typescript/interfaces.d.ts +5 -0
- package/lib/typescript/interfaces.d.ts.map +1 -1
- package/lib/typescript/web-core/AudioContext.d.ts +2 -0
- package/lib/typescript/web-core/AudioContext.d.ts.map +1 -1
- package/lib/typescript/web-core/BaseAudioContext.d.ts +2 -0
- package/lib/typescript/web-core/BaseAudioContext.d.ts.map +1 -1
- package/lib/typescript/web-core/DelayNode.d.ts +8 -0
- package/lib/typescript/web-core/DelayNode.d.ts.map +1 -0
- package/lib/typescript/web-core/OfflineAudioContext.d.ts +2 -0
- package/lib/typescript/web-core/OfflineAudioContext.d.ts.map +1 -1
- package/package.json +3 -8
- package/src/core/AudioNode.ts +4 -3
- package/src/core/BaseAudioContext.ts +6 -0
- package/src/core/DelayNode.ts +13 -0
- package/src/interfaces.ts +6 -0
- package/src/web-core/AudioContext.tsx +5 -0
- package/src/web-core/BaseAudioContext.tsx +2 -0
- package/src/web-core/DelayNode.tsx +12 -0
- package/src/web-core/OfflineAudioContext.tsx +5 -0
|
@@ -50,7 +50,6 @@ void AudioAPIModule::registerNatives() {
|
|
|
50
50
|
makeNativeMethod(
|
|
51
51
|
"invokeHandlerWithEventNameAndEventBody",
|
|
52
52
|
AudioAPIModule::invokeHandlerWithEventNameAndEventBody),
|
|
53
|
-
makeNativeMethod("closeAllContexts", AudioAPIModule::closeAllContexts),
|
|
54
53
|
});
|
|
55
54
|
}
|
|
56
55
|
|
|
@@ -96,8 +95,4 @@ void AudioAPIModule::invokeHandlerWithEventNameAndEventBody(
|
|
|
96
95
|
audioEventHandlerRegistry_->invokeHandlerWithEventBody(eventName->toStdString(), body);
|
|
97
96
|
}
|
|
98
97
|
}
|
|
99
|
-
|
|
100
|
-
void AudioAPIModule::closeAllContexts() {
|
|
101
|
-
AudioAPIModuleInstaller::closeAllContexts();
|
|
102
|
-
}
|
|
103
98
|
} // namespace audioapi
|
|
@@ -34,7 +34,6 @@ class AudioAPIModule : public jni::HybridClass<AudioAPIModule> {
|
|
|
34
34
|
|
|
35
35
|
void injectJSIBindings();
|
|
36
36
|
void invokeHandlerWithEventNameAndEventBody(jni::alias_ref<jni::JString> eventName, jni::alias_ref<jni::JMap<jstring, jobject>> eventBody);
|
|
37
|
-
void closeAllContexts();
|
|
38
37
|
|
|
39
38
|
private:
|
|
40
39
|
friend HybridBase;
|
|
@@ -40,8 +40,6 @@ class AudioAPIModule(
|
|
|
40
40
|
eventBody: Map<String, Any>,
|
|
41
41
|
)
|
|
42
42
|
|
|
43
|
-
private external fun closeAllContexts()
|
|
44
|
-
|
|
45
43
|
init {
|
|
46
44
|
try {
|
|
47
45
|
System.loadLibrary("react-native-audio-api")
|
|
@@ -77,7 +75,7 @@ class AudioAPIModule(
|
|
|
77
75
|
}
|
|
78
76
|
|
|
79
77
|
override fun onHostDestroy() {
|
|
80
|
-
|
|
78
|
+
// do nothing
|
|
81
79
|
}
|
|
82
80
|
|
|
83
81
|
override fun initialize() {
|
|
@@ -85,7 +83,6 @@ class AudioAPIModule(
|
|
|
85
83
|
}
|
|
86
84
|
|
|
87
85
|
override fun invalidate() {
|
|
88
|
-
closeAllContexts()
|
|
89
86
|
reactContext.get()?.removeLifecycleEventListener(this)
|
|
90
87
|
// think about cleaning up resources, singletons etc.
|
|
91
88
|
}
|
|
@@ -23,9 +23,6 @@ namespace audioapi {
|
|
|
23
23
|
using namespace facebook;
|
|
24
24
|
|
|
25
25
|
class AudioAPIModuleInstaller {
|
|
26
|
-
private:
|
|
27
|
-
inline static std::vector<std::weak_ptr<AudioContext>> contexts_ = {};
|
|
28
|
-
|
|
29
26
|
public:
|
|
30
27
|
static void injectJSIBindings(
|
|
31
28
|
jsi::Runtime *jsiRuntime,
|
|
@@ -56,19 +53,6 @@ class AudioAPIModuleInstaller {
|
|
|
56
53
|
jsi::Object::createFromHostObject(*jsiRuntime, audioEventHandlerRegistryHostObject));
|
|
57
54
|
}
|
|
58
55
|
|
|
59
|
-
static void closeAllContexts() {
|
|
60
|
-
for (auto it = contexts_.begin(); it != contexts_.end(); ++it) {
|
|
61
|
-
auto weakContext = *it;
|
|
62
|
-
|
|
63
|
-
if (auto context = weakContext.lock()) {
|
|
64
|
-
context->close();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
it = contexts_.erase(it);
|
|
68
|
-
--it;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
56
|
private:
|
|
73
57
|
static jsi::Function getCreateAudioContextFunction(
|
|
74
58
|
jsi::Runtime *jsiRuntime,
|
|
@@ -97,7 +81,6 @@ class AudioAPIModuleInstaller {
|
|
|
97
81
|
|
|
98
82
|
audioContext = std::make_shared<AudioContext>(
|
|
99
83
|
sampleRate, audioEventHandlerRegistry, runtimeRegistry);
|
|
100
|
-
AudioAPIModuleInstaller::contexts_.push_back(audioContext);
|
|
101
84
|
|
|
102
85
|
auto audioContextHostObject =
|
|
103
86
|
std::make_shared<AudioContextHostObject>(audioContext, &runtime, jsCallInvoker);
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
#include <audioapi/HostObjects/destinations/AudioDestinationNodeHostObject.h>
|
|
7
7
|
#include <audioapi/HostObjects/effects/BiquadFilterNodeHostObject.h>
|
|
8
8
|
#include <audioapi/HostObjects/effects/ConvolverNodeHostObject.h>
|
|
9
|
+
#include <audioapi/HostObjects/effects/DelayNodeHostObject.h>
|
|
9
10
|
#include <audioapi/HostObjects/effects/GainNodeHostObject.h>
|
|
10
11
|
#include <audioapi/HostObjects/effects/IIRFilterNodeHostObject.h>
|
|
11
12
|
#include <audioapi/HostObjects/effects/PeriodicWaveHostObject.h>
|
|
@@ -47,6 +48,7 @@ BaseAudioContextHostObject::BaseAudioContextHostObject(
|
|
|
47
48
|
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createStreamer),
|
|
48
49
|
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createConstantSource),
|
|
49
50
|
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createGain),
|
|
51
|
+
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createDelay),
|
|
50
52
|
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createStereoPanner),
|
|
51
53
|
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createBiquadFilter),
|
|
52
54
|
JSI_EXPORT_FUNCTION(BaseAudioContextHostObject, createIIRFilter),
|
|
@@ -184,6 +186,15 @@ JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, createGain) {
|
|
|
184
186
|
return jsi::Object::createFromHostObject(runtime, gainHostObject);
|
|
185
187
|
}
|
|
186
188
|
|
|
189
|
+
JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, createDelay) {
|
|
190
|
+
auto maxDelayTime = static_cast<float>(args[0].getNumber());
|
|
191
|
+
auto delayNode = context_->createDelay(maxDelayTime);
|
|
192
|
+
auto delayNodeHostObject = std::make_shared<DelayNodeHostObject>(delayNode);
|
|
193
|
+
auto jsiObject = jsi::Object::createFromHostObject(runtime, delayNodeHostObject);
|
|
194
|
+
jsiObject.setExternalMemoryPressure(runtime, delayNodeHostObject->getSizeInBytes());
|
|
195
|
+
return jsiObject;
|
|
196
|
+
}
|
|
197
|
+
|
|
187
198
|
JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, createStereoPanner) {
|
|
188
199
|
auto stereoPanner = context_->createStereoPanner();
|
|
189
200
|
auto stereoPannerHostObject = std::make_shared<StereoPannerNodeHostObject>(stereoPanner);
|
|
@@ -43,6 +43,7 @@ class BaseAudioContextHostObject : public JsiHostObject {
|
|
|
43
43
|
JSI_HOST_FUNCTION_DECL(createPeriodicWave);
|
|
44
44
|
JSI_HOST_FUNCTION_DECL(createAnalyser);
|
|
45
45
|
JSI_HOST_FUNCTION_DECL(createConvolver);
|
|
46
|
+
JSI_HOST_FUNCTION_DECL(createDelay);
|
|
46
47
|
|
|
47
48
|
std::shared_ptr<BaseAudioContext> context_;
|
|
48
49
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#include <audioapi/HostObjects/effects/DelayNodeHostObject.h>
|
|
2
|
+
|
|
3
|
+
#include <audioapi/HostObjects/AudioParamHostObject.h>
|
|
4
|
+
#include <audioapi/core/BaseAudioContext.h>
|
|
5
|
+
#include <audioapi/core/effects/DelayNode.h>
|
|
6
|
+
#include <memory>
|
|
7
|
+
|
|
8
|
+
namespace audioapi {
|
|
9
|
+
|
|
10
|
+
DelayNodeHostObject::DelayNodeHostObject(const std::shared_ptr<DelayNode> &node)
|
|
11
|
+
: AudioNodeHostObject(node) {
|
|
12
|
+
addGetters(JSI_EXPORT_PROPERTY_GETTER(DelayNodeHostObject, delayTime));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
size_t DelayNodeHostObject::getSizeInBytes() const {
|
|
16
|
+
auto delayNode = std::static_pointer_cast<DelayNode>(node_);
|
|
17
|
+
return sizeof(float) * delayNode->context_->getSampleRate() *
|
|
18
|
+
delayNode->getDelayTimeParam()->getMaxValue();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
JSI_PROPERTY_GETTER_IMPL(DelayNodeHostObject, delayTime) {
|
|
22
|
+
auto delayNode = std::static_pointer_cast<DelayNode>(node_);
|
|
23
|
+
auto delayTimeParam = std::make_shared<AudioParamHostObject>(delayNode->getDelayTimeParam());
|
|
24
|
+
return jsi::Object::createFromHostObject(runtime, delayTimeParam);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
} // namespace audioapi
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <audioapi/HostObjects/AudioNodeHostObject.h>
|
|
4
|
+
|
|
5
|
+
#include <memory>
|
|
6
|
+
#include <vector>
|
|
7
|
+
|
|
8
|
+
namespace audioapi {
|
|
9
|
+
using namespace facebook;
|
|
10
|
+
|
|
11
|
+
class DelayNode;
|
|
12
|
+
|
|
13
|
+
class DelayNodeHostObject : public AudioNodeHostObject {
|
|
14
|
+
public:
|
|
15
|
+
explicit DelayNodeHostObject(const std::shared_ptr<DelayNode> &node);
|
|
16
|
+
|
|
17
|
+
[[nodiscard]] size_t getSizeInBytes() const;
|
|
18
|
+
|
|
19
|
+
JSI_PROPERTY_GETTER_DECL(delayTime);
|
|
20
|
+
};
|
|
21
|
+
} // namespace audioapi
|
|
@@ -38,6 +38,7 @@ class AudioNode : public std::enable_shared_from_this<AudioNode> {
|
|
|
38
38
|
bool checkIsAlreadyProcessed);
|
|
39
39
|
|
|
40
40
|
bool isEnabled() const;
|
|
41
|
+
bool requiresTailProcessing() const;
|
|
41
42
|
void enable();
|
|
42
43
|
virtual void disable();
|
|
43
44
|
|
|
@@ -45,6 +46,7 @@ class AudioNode : public std::enable_shared_from_this<AudioNode> {
|
|
|
45
46
|
friend class AudioNodeManager;
|
|
46
47
|
friend class AudioDestinationNode;
|
|
47
48
|
friend class ConvolverNode;
|
|
49
|
+
friend class DelayNodeHostObject;
|
|
48
50
|
|
|
49
51
|
BaseAudioContext *context_;
|
|
50
52
|
std::shared_ptr<AudioBus> audioBus_;
|
|
@@ -64,6 +66,7 @@ class AudioNode : public std::enable_shared_from_this<AudioNode> {
|
|
|
64
66
|
int numberOfEnabledInputNodes_ = 0;
|
|
65
67
|
bool isInitialized_ = false;
|
|
66
68
|
bool isEnabled_ = true;
|
|
69
|
+
bool requiresTailProcessing_ = false;
|
|
67
70
|
|
|
68
71
|
std::size_t lastRenderedFrame_{SIZE_MAX};
|
|
69
72
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#include <audioapi/core/destinations/AudioDestinationNode.h>
|
|
4
4
|
#include <audioapi/core/effects/BiquadFilterNode.h>
|
|
5
5
|
#include <audioapi/core/effects/ConvolverNode.h>
|
|
6
|
+
#include <audioapi/core/effects/DelayNode.h>
|
|
6
7
|
#include <audioapi/core/effects/GainNode.h>
|
|
7
8
|
#include <audioapi/core/effects/IIRFilterNode.h>
|
|
8
9
|
#include <audioapi/core/effects/StereoPannerNode.h>
|
|
@@ -140,6 +141,12 @@ std::shared_ptr<GainNode> BaseAudioContext::createGain() {
|
|
|
140
141
|
return gain;
|
|
141
142
|
}
|
|
142
143
|
|
|
144
|
+
std::shared_ptr<DelayNode> BaseAudioContext::createDelay(float maxDelayTime) {
|
|
145
|
+
auto delay = std::make_shared<DelayNode>(this, maxDelayTime);
|
|
146
|
+
nodeManager_->addProcessingNode(delay);
|
|
147
|
+
return delay;
|
|
148
|
+
}
|
|
149
|
+
|
|
143
150
|
std::shared_ptr<StereoPannerNode> BaseAudioContext::createStereoPanner() {
|
|
144
151
|
auto stereoPanner = std::make_shared<StereoPannerNode>(this);
|
|
145
152
|
nodeManager_->addProcessingNode(stereoPanner);
|
|
@@ -16,6 +16,7 @@ namespace audioapi {
|
|
|
16
16
|
|
|
17
17
|
class AudioBus;
|
|
18
18
|
class GainNode;
|
|
19
|
+
class DelayNode;
|
|
19
20
|
class AudioBuffer;
|
|
20
21
|
class PeriodicWave;
|
|
21
22
|
class OscillatorNode;
|
|
@@ -69,6 +70,7 @@ class BaseAudioContext {
|
|
|
69
70
|
std::shared_ptr<ConstantSourceNode> createConstantSource();
|
|
70
71
|
std::shared_ptr<StreamerNode> createStreamer();
|
|
71
72
|
std::shared_ptr<GainNode> createGain();
|
|
73
|
+
std::shared_ptr<DelayNode> createDelay(float maxDelayTime);
|
|
72
74
|
std::shared_ptr<StereoPannerNode> createStereoPanner();
|
|
73
75
|
std::shared_ptr<BiquadFilterNode> createBiquadFilter();
|
|
74
76
|
std::shared_ptr<IIRFilterNode> createIIRFilter(
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#include <audioapi/core/BaseAudioContext.h>
|
|
2
|
+
#include <audioapi/core/effects/DelayNode.h>
|
|
3
|
+
#include <audioapi/dsp/VectorMath.h>
|
|
4
|
+
#include <audioapi/utils/AudioArray.h>
|
|
5
|
+
#include <audioapi/utils/AudioBus.h>
|
|
6
|
+
#include <memory>
|
|
7
|
+
|
|
8
|
+
namespace audioapi {
|
|
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());
|
|
18
|
+
requiresTailProcessing_ = true;
|
|
19
|
+
isInitialized_ = true;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
std::shared_ptr<AudioParam> DelayNode::getDelayTimeParam() const {
|
|
23
|
+
return delayTimeParam_;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
void DelayNode::onInputDisabled() {
|
|
27
|
+
numberOfEnabledInputNodes_ -= 1;
|
|
28
|
+
if (isEnabled() && numberOfEnabledInputNodes_ == 0) {
|
|
29
|
+
signalledToStop_ = true;
|
|
30
|
+
remainingFrames_ = delayTimeParam_->getValue() * context_->getSampleRate();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
void DelayNode::delayBufferOperation(
|
|
35
|
+
const std::shared_ptr<AudioBus> &processingBus,
|
|
36
|
+
int framesToProcess,
|
|
37
|
+
size_t &operationStartingIndex,
|
|
38
|
+
DelayNode::BufferAction action) {
|
|
39
|
+
size_t processingBusStartIndex = 0;
|
|
40
|
+
|
|
41
|
+
// handle buffer wrap around
|
|
42
|
+
if (operationStartingIndex + framesToProcess > delayBuffer_->getSize()) {
|
|
43
|
+
int framesToEnd = operationStartingIndex + framesToProcess - delayBuffer_->getSize();
|
|
44
|
+
|
|
45
|
+
if (action == BufferAction::WRITE) {
|
|
46
|
+
delayBuffer_->sum(
|
|
47
|
+
processingBus.get(), processingBusStartIndex, operationStartingIndex, framesToEnd);
|
|
48
|
+
} else { // READ
|
|
49
|
+
processingBus->sum(
|
|
50
|
+
delayBuffer_.get(), operationStartingIndex, processingBusStartIndex, framesToEnd);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
operationStartingIndex = 0;
|
|
54
|
+
processingBusStartIndex += framesToEnd;
|
|
55
|
+
framesToProcess -= framesToEnd;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (action == BufferAction::WRITE) {
|
|
59
|
+
delayBuffer_->sum(
|
|
60
|
+
processingBus.get(), processingBusStartIndex, operationStartingIndex, framesToProcess);
|
|
61
|
+
processingBus->zero();
|
|
62
|
+
} else { // READ
|
|
63
|
+
processingBus->sum(
|
|
64
|
+
delayBuffer_.get(), operationStartingIndex, processingBusStartIndex, framesToProcess);
|
|
65
|
+
delayBuffer_->zero(operationStartingIndex, framesToProcess);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
operationStartingIndex += framesToProcess;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// delay buffer always has channelCount_ channels
|
|
72
|
+
// processing is split into two parts
|
|
73
|
+
// 1. writing to delay buffer (mixing if needed) from processing bus
|
|
74
|
+
// 2. reading from delay buffer to processing bus (mixing if needed) with delay
|
|
75
|
+
std::shared_ptr<AudioBus> DelayNode::processNode(
|
|
76
|
+
const std::shared_ptr<AudioBus> &processingBus,
|
|
77
|
+
int framesToProcess) {
|
|
78
|
+
// handling tail processing
|
|
79
|
+
if (signalledToStop_) {
|
|
80
|
+
if (remainingFrames_ <= 0) {
|
|
81
|
+
disable();
|
|
82
|
+
signalledToStop_ = false;
|
|
83
|
+
return processingBus;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
delayBufferOperation(processingBus, framesToProcess, readIndex_, DelayNode::BufferAction::READ);
|
|
87
|
+
remainingFrames_ -= framesToProcess;
|
|
88
|
+
return processingBus;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// normal processing
|
|
92
|
+
auto delayTime = delayTimeParam_->processKRateParam(framesToProcess, context_->getCurrentTime());
|
|
93
|
+
size_t writeIndex = static_cast<size_t>(readIndex_ + delayTime * context_->getSampleRate()) %
|
|
94
|
+
delayBuffer_->getSize();
|
|
95
|
+
delayBufferOperation(processingBus, framesToProcess, writeIndex, DelayNode::BufferAction::WRITE);
|
|
96
|
+
delayBufferOperation(processingBus, framesToProcess, readIndex_, DelayNode::BufferAction::READ);
|
|
97
|
+
|
|
98
|
+
return processingBus;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
} // namespace audioapi
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <audioapi/core/AudioNode.h>
|
|
4
|
+
#include <audioapi/core/AudioParam.h>
|
|
5
|
+
|
|
6
|
+
#include <functional>
|
|
7
|
+
#include <memory>
|
|
8
|
+
|
|
9
|
+
namespace audioapi {
|
|
10
|
+
|
|
11
|
+
class AudioBus;
|
|
12
|
+
|
|
13
|
+
class DelayNode : public AudioNode {
|
|
14
|
+
public:
|
|
15
|
+
explicit DelayNode(BaseAudioContext *context, float maxDelayTime);
|
|
16
|
+
|
|
17
|
+
[[nodiscard]] std::shared_ptr<AudioParam> getDelayTimeParam() const;
|
|
18
|
+
|
|
19
|
+
protected:
|
|
20
|
+
std::shared_ptr<AudioBus> processNode(
|
|
21
|
+
const std::shared_ptr<AudioBus> &processingBus,
|
|
22
|
+
int framesToProcess) override;
|
|
23
|
+
|
|
24
|
+
private:
|
|
25
|
+
void onInputDisabled() override;
|
|
26
|
+
enum class BufferAction { READ, WRITE };
|
|
27
|
+
void delayBufferOperation(
|
|
28
|
+
const std::shared_ptr<AudioBus> &processingBus,
|
|
29
|
+
int framesToProcess,
|
|
30
|
+
size_t &operationStartingIndex,
|
|
31
|
+
BufferAction action);
|
|
32
|
+
std::shared_ptr<AudioParam> delayTimeParam_;
|
|
33
|
+
std::shared_ptr<AudioBus> delayBuffer_;
|
|
34
|
+
size_t readIndex_ = 0;
|
|
35
|
+
bool signalledToStop_ = false;
|
|
36
|
+
int remainingFrames_ = 0;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
} // namespace audioapi
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#include <audioapi/core/AudioNode.h>
|
|
2
2
|
#include <audioapi/core/AudioParam.h>
|
|
3
3
|
#include <audioapi/core/effects/ConvolverNode.h>
|
|
4
|
+
#include <audioapi/core/effects/DelayNode.h>
|
|
4
5
|
#include <audioapi/core/sources/AudioScheduledSourceNode.h>
|
|
5
6
|
#include <audioapi/core/utils/AudioNodeManager.h>
|
|
6
7
|
#include <audioapi/core/utils/Locker.h>
|
|
@@ -219,7 +220,8 @@ inline bool AudioNodeManager::nodeCanBeDestructed(std::shared_ptr<U> const &node
|
|
|
219
220
|
// playing
|
|
220
221
|
if constexpr (std::is_base_of_v<AudioScheduledSourceNode, U>) {
|
|
221
222
|
return node.use_count() == 1 && (node->isUnscheduled() || node->isFinished());
|
|
222
|
-
} else if
|
|
223
|
+
} else if (node->requiresTailProcessing()) {
|
|
224
|
+
// if the node requires tail processing, its own implementation handles disabling it at the right time
|
|
223
225
|
return node.use_count() == 1 && !node->isEnabled();
|
|
224
226
|
}
|
|
225
227
|
return node.use_count() == 1;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#include <audioapi/core/OfflineAudioContext.h>
|
|
2
|
+
#include <audioapi/core/effects/DelayNode.h>
|
|
3
|
+
#include <audioapi/core/utils/worklets/SafeIncludes.h>
|
|
4
|
+
#include <audioapi/utils/AudioArray.h>
|
|
5
|
+
#include <audioapi/utils/AudioBus.h>
|
|
6
|
+
#include <gtest/gtest.h>
|
|
7
|
+
#include <test/src/MockAudioEventHandlerRegistry.h>
|
|
8
|
+
#include <memory>
|
|
9
|
+
|
|
10
|
+
using namespace audioapi;
|
|
11
|
+
|
|
12
|
+
class DelayTest : public ::testing::Test {
|
|
13
|
+
protected:
|
|
14
|
+
std::shared_ptr<MockAudioEventHandlerRegistry> eventRegistry;
|
|
15
|
+
std::unique_ptr<OfflineAudioContext> context;
|
|
16
|
+
static constexpr int sampleRate = 44100;
|
|
17
|
+
|
|
18
|
+
void SetUp() override {
|
|
19
|
+
eventRegistry = std::make_shared<MockAudioEventHandlerRegistry>();
|
|
20
|
+
context = std::make_unique<OfflineAudioContext>(
|
|
21
|
+
2, 5 * sampleRate, sampleRate, eventRegistry, RuntimeRegistry{});
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
class TestableDelayNode : public DelayNode {
|
|
26
|
+
public:
|
|
27
|
+
explicit TestableDelayNode(BaseAudioContext *context) : DelayNode(context, 1) {}
|
|
28
|
+
|
|
29
|
+
void setDelayTimeParam(float value) {
|
|
30
|
+
getDelayTimeParam()->setValue(value);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
std::shared_ptr<AudioBus> processNode(
|
|
34
|
+
const std::shared_ptr<AudioBus> &processingBus,
|
|
35
|
+
int framesToProcess) override {
|
|
36
|
+
return DelayNode::processNode(processingBus, framesToProcess);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
TEST_F(DelayTest, DelayCanBeCreated) {
|
|
41
|
+
auto delay = context->createDelay(1.0f);
|
|
42
|
+
ASSERT_NE(delay, nullptr);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
TEST_F(DelayTest, DelayWithZeroDelayOutputsInputSignal) {
|
|
46
|
+
static constexpr float DELAY_TIME = 0.0f;
|
|
47
|
+
static constexpr int FRAMES_TO_PROCESS = 4;
|
|
48
|
+
auto delayNode = std::make_shared<TestableDelayNode>(context.get());
|
|
49
|
+
delayNode->setDelayTimeParam(DELAY_TIME);
|
|
50
|
+
|
|
51
|
+
auto bus = std::make_shared<audioapi::AudioBus>(FRAMES_TO_PROCESS, 1, sampleRate);
|
|
52
|
+
for (size_t i = 0; i < bus->getSize(); ++i) {
|
|
53
|
+
bus->getChannel(0)->getData()[i] = i + 1;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
auto resultBus = delayNode->processNode(bus, FRAMES_TO_PROCESS);
|
|
57
|
+
for (size_t i = 0; i < FRAMES_TO_PROCESS; ++i) {
|
|
58
|
+
EXPECT_FLOAT_EQ((*resultBus->getChannel(0))[i], static_cast<float>(i + 1));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
TEST_F(DelayTest, DelayAppliesTimeShiftCorrectly) {
|
|
63
|
+
float DELAY_TIME = (128.0 / context->getSampleRate()) * 0.5;
|
|
64
|
+
static constexpr int FRAMES_TO_PROCESS = 128;
|
|
65
|
+
auto delayNode = std::make_shared<TestableDelayNode>(context.get());
|
|
66
|
+
delayNode->setDelayTimeParam(DELAY_TIME);
|
|
67
|
+
|
|
68
|
+
auto bus = std::make_shared<audioapi::AudioBus>(FRAMES_TO_PROCESS, 1, sampleRate);
|
|
69
|
+
for (size_t i = 0; i < bus->getSize(); ++i) {
|
|
70
|
+
bus->getChannel(0)->getData()[i] = i + 1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
auto resultBus = delayNode->processNode(bus, FRAMES_TO_PROCESS);
|
|
74
|
+
for (size_t i = 0; i < FRAMES_TO_PROCESS; ++i) {
|
|
75
|
+
if (i < FRAMES_TO_PROCESS / 2) { // First 64 samples should be zero due to delay
|
|
76
|
+
EXPECT_FLOAT_EQ((*resultBus->getChannel(0))[i], 0.0f);
|
|
77
|
+
} else {
|
|
78
|
+
EXPECT_FLOAT_EQ(
|
|
79
|
+
(*resultBus->getChannel(0))[i],
|
|
80
|
+
static_cast<float>(
|
|
81
|
+
i + 1 - FRAMES_TO_PROCESS / 2)); // Last 64 samples should be 1st part of bus
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
TEST_F(DelayTest, DelayHandlesTailCorrectly) {
|
|
87
|
+
float DELAY_TIME = (128.0 / context->getSampleRate()) * 0.5;
|
|
88
|
+
static constexpr int FRAMES_TO_PROCESS = 128;
|
|
89
|
+
auto delayNode = std::make_shared<TestableDelayNode>(context.get());
|
|
90
|
+
delayNode->setDelayTimeParam(DELAY_TIME);
|
|
91
|
+
|
|
92
|
+
auto bus = std::make_shared<audioapi::AudioBus>(FRAMES_TO_PROCESS, 1, sampleRate);
|
|
93
|
+
for (size_t i = 0; i < bus->getSize(); ++i) {
|
|
94
|
+
bus->getChannel(0)->getData()[i] = i + 1;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
delayNode->processNode(bus, FRAMES_TO_PROCESS);
|
|
98
|
+
auto resultBus = delayNode->processNode(bus, FRAMES_TO_PROCESS);
|
|
99
|
+
for (size_t i = 0; i < FRAMES_TO_PROCESS; ++i) {
|
|
100
|
+
if (i < FRAMES_TO_PROCESS / 2) { // First 64 samples should be 2nd part of bus
|
|
101
|
+
EXPECT_FLOAT_EQ(
|
|
102
|
+
(*resultBus->getChannel(0))[i], static_cast<float>(i + 1 + FRAMES_TO_PROCESS / 2));
|
|
103
|
+
} else {
|
|
104
|
+
EXPECT_FLOAT_EQ((*resultBus->getChannel(0))[i],
|
|
105
|
+
0.0f); // Last 64 samples should be zero
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_AudioParam","_interopRequireDefault","require","_errors","e","__esModule","default","AudioNode","constructor","context","node","numberOfInputs","numberOfOutputs","channelCount","channelCountMode","channelInterpretation","connect","destination","InvalidAccessError","AudioParam","audioParam","disconnect","exports"],"sourceRoot":"../../../src","sources":["core/AudioNode.ts"],"mappings":";;;;;;AACA,IAAAA,WAAA,GAAAC,sBAAA,CAAAC,OAAA;AAGA,IAAAC,OAAA,GAAAD,OAAA;AAA+C,SAAAD,uBAAAG,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAEhC,MAAMG,SAAS,CAAC;EAS7BC,WAAWA,CAACC,OAAyB,EAAEC,IAAgB,EAAE;IACvD,IAAI,CAACD,OAAO,GAAGA,OAAO;IACtB,IAAI,CAACC,IAAI,GAAGA,IAAI;IAChB,IAAI,CAACC,cAAc,GAAG,IAAI,CAACD,IAAI,CAACC,cAAc;IAC9C,IAAI,CAACC,eAAe,GAAG,IAAI,CAACF,IAAI,CAACE,eAAe;IAChD,IAAI,CAACC,YAAY,GAAG,IAAI,CAACH,IAAI,CAACG,YAAY;IAC1C,IAAI,CAACC,gBAAgB,GAAG,IAAI,CAACJ,IAAI,CAACI,gBAAgB;IAClD,IAAI,CAACC,qBAAqB,GAAG,IAAI,CAACL,IAAI,CAACK,qBAAqB;EAC9D;
|
|
1
|
+
{"version":3,"names":["_AudioParam","_interopRequireDefault","require","_errors","e","__esModule","default","AudioNode","constructor","context","node","numberOfInputs","numberOfOutputs","channelCount","channelCountMode","channelInterpretation","connect","destination","InvalidAccessError","AudioParam","audioParam","disconnect","exports"],"sourceRoot":"../../../src","sources":["core/AudioNode.ts"],"mappings":";;;;;;AACA,IAAAA,WAAA,GAAAC,sBAAA,CAAAC,OAAA;AAGA,IAAAC,OAAA,GAAAD,OAAA;AAA+C,SAAAD,uBAAAG,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAEhC,MAAMG,SAAS,CAAC;EAS7BC,WAAWA,CAACC,OAAyB,EAAEC,IAAgB,EAAE;IACvD,IAAI,CAACD,OAAO,GAAGA,OAAO;IACtB,IAAI,CAACC,IAAI,GAAGA,IAAI;IAChB,IAAI,CAACC,cAAc,GAAG,IAAI,CAACD,IAAI,CAACC,cAAc;IAC9C,IAAI,CAACC,eAAe,GAAG,IAAI,CAACF,IAAI,CAACE,eAAe;IAChD,IAAI,CAACC,YAAY,GAAG,IAAI,CAACH,IAAI,CAACG,YAAY;IAC1C,IAAI,CAACC,gBAAgB,GAAG,IAAI,CAACJ,IAAI,CAACI,gBAAgB;IAClD,IAAI,CAACC,qBAAqB,GAAG,IAAI,CAACL,IAAI,CAACK,qBAAqB;EAC9D;EAIOC,OAAOA,CAACC,WAAmC,EAAoB;IACpE,IAAI,IAAI,CAACR,OAAO,KAAKQ,WAAW,CAACR,OAAO,EAAE;MACxC,MAAM,IAAIS,0BAAkB,CAC1B,6DACF,CAAC;IACH;IAEA,IAAID,WAAW,YAAYE,mBAAU,EAAE;MACrC,IAAI,CAACT,IAAI,CAACM,OAAO,CAACC,WAAW,CAACG,UAAU,CAAC;IAC3C,CAAC,MAAM;MACL,IAAI,CAACV,IAAI,CAACM,OAAO,CAACC,WAAW,CAACP,IAAI,CAAC;MACnC,OAAOO,WAAW;IACpB;EACF;EAEOI,UAAUA,CAACJ,WAAoC,EAAQ;IAC5D,IAAIA,WAAW,YAAYE,mBAAU,EAAE;MACrC,IAAI,CAACT,IAAI,CAACW,UAAU,CAACJ,WAAW,CAACG,UAAU,CAAC;IAC9C,CAAC,MAAM;MACL,IAAI,CAACV,IAAI,CAACW,UAAU,CAACJ,WAAW,EAAEP,IAAI,CAAC;IACzC;EACF;AACF;AAACY,OAAA,CAAAhB,OAAA,GAAAC,SAAA","ignoreList":[]}
|
|
@@ -16,6 +16,7 @@ var _AudioDestinationNode = _interopRequireDefault(require("./AudioDestinationNo
|
|
|
16
16
|
var _BiquadFilterNode = _interopRequireDefault(require("./BiquadFilterNode"));
|
|
17
17
|
var _ConstantSourceNode = _interopRequireDefault(require("./ConstantSourceNode"));
|
|
18
18
|
var _ConvolverNode = _interopRequireDefault(require("./ConvolverNode"));
|
|
19
|
+
var _DelayNode = _interopRequireDefault(require("./DelayNode"));
|
|
19
20
|
var _GainNode = _interopRequireDefault(require("./GainNode"));
|
|
20
21
|
var _IIRFilterNode = _interopRequireDefault(require("./IIRFilterNode"));
|
|
21
22
|
var _OscillatorNode = _interopRequireDefault(require("./OscillatorNode"));
|
|
@@ -104,6 +105,10 @@ class BaseAudioContext {
|
|
|
104
105
|
createGain() {
|
|
105
106
|
return new _GainNode.default(this, this.context.createGain());
|
|
106
107
|
}
|
|
108
|
+
createDelay(maxDelayTime) {
|
|
109
|
+
const maxTime = maxDelayTime ?? 1.0;
|
|
110
|
+
return new _DelayNode.default(this, this.context.createDelay(maxTime));
|
|
111
|
+
}
|
|
107
112
|
createStereoPanner() {
|
|
108
113
|
return new _StereoPannerNode.default(this, this.context.createStereoPanner());
|
|
109
114
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_AudioAPIModule","_interopRequireDefault","require","_errors","_utils","_AnalyserNode","_AudioBuffer","_AudioBufferQueueSourceNode","_AudioBufferSourceNode","_AudioDecoder","_AudioDestinationNode","_BiquadFilterNode","_ConstantSourceNode","_ConvolverNode","_GainNode","_IIRFilterNode","_OscillatorNode","_PeriodicWave","_RecorderAdapterNode","_StereoPannerNode","_StreamerNode","_WorkletNode","_WorkletProcessingNode","_WorkletSourceNode","e","__esModule","default","BaseAudioContext","constructor","context","destination","AudioDestinationNode","sampleRate","currentTime","state","decodeAudioData","input","ArrayBuffer","TypeError","decodePCMInBase64","base64String","inputSampleRate","inputChannelCount","isInterleaved","createWorkletNode","callback","bufferLength","workletRuntime","NotSupportedError","assertWorkletsEnabled","shareableWorklet","AudioAPIModule","workletsModule","makeShareableCloneRecursive","audioBuffers","channelCount","floatAudioData","map","buffer","Float32Array","WorkletNode","createWorkletProcessingNode","inputBuffers","outputBuffers","framesToProcess","inputData","outputData","WorkletProcessingNode","createWorkletSourceNode","startOffset","WorkletSourceNode","createRecorderAdapter","RecorderAdapterNode","createOscillator","OscillatorNode","createStreamer","streamer","StreamerNode","createConstantSource","ConstantSourceNode","createGain","GainNode","createStereoPanner","StereoPannerNode","createBiquadFilter","BiquadFilterNode","createIIRFilter","options","feedforward","feedback","length","every","value","InvalidStateError","IIRFilterNode","createBufferSource","pitchCorrection","AudioBufferSourceNode","createBufferQueueSource","AudioBufferQueueSourceNode","createBuffer","numOfChannels","AudioBuffer","createPeriodicWave","real","imag","constraints","InvalidAccessError","disableNormalization","PeriodicWave","createAnalyser","AnalyserNode","createConvolver","numberOfChannels","ConvolverNode","exports"],"sourceRoot":"../../../src","sources":["core/BaseAudioContext.ts"],"mappings":";;;;;;AAAA,IAAAA,eAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,OAAA,GAAAD,OAAA;AAcA,IAAAE,MAAA,GAAAF,OAAA;AACA,IAAAG,aAAA,GAAAJ,sBAAA,CAAAC,OAAA;AACA,IAAAI,YAAA,GAAAL,sBAAA,CAAAC,OAAA;AACA,IAAAK,2BAAA,GAAAN,sBAAA,CAAAC,OAAA;AACA,IAAAM,sBAAA,GAAAP,sBAAA,CAAAC,OAAA;AACA,IAAAO,aAAA,GAAAP,OAAA;AACA,IAAAQ,qBAAA,GAAAT,sBAAA,CAAAC,OAAA;AACA,IAAAS,iBAAA,GAAAV,sBAAA,CAAAC,OAAA;AACA,IAAAU,mBAAA,GAAAX,sBAAA,CAAAC,OAAA;AACA,IAAAW,cAAA,GAAAZ,sBAAA,CAAAC,OAAA;AACA,IAAAY,
|
|
1
|
+
{"version":3,"names":["_AudioAPIModule","_interopRequireDefault","require","_errors","_utils","_AnalyserNode","_AudioBuffer","_AudioBufferQueueSourceNode","_AudioBufferSourceNode","_AudioDecoder","_AudioDestinationNode","_BiquadFilterNode","_ConstantSourceNode","_ConvolverNode","_DelayNode","_GainNode","_IIRFilterNode","_OscillatorNode","_PeriodicWave","_RecorderAdapterNode","_StereoPannerNode","_StreamerNode","_WorkletNode","_WorkletProcessingNode","_WorkletSourceNode","e","__esModule","default","BaseAudioContext","constructor","context","destination","AudioDestinationNode","sampleRate","currentTime","state","decodeAudioData","input","ArrayBuffer","TypeError","decodePCMInBase64","base64String","inputSampleRate","inputChannelCount","isInterleaved","createWorkletNode","callback","bufferLength","workletRuntime","NotSupportedError","assertWorkletsEnabled","shareableWorklet","AudioAPIModule","workletsModule","makeShareableCloneRecursive","audioBuffers","channelCount","floatAudioData","map","buffer","Float32Array","WorkletNode","createWorkletProcessingNode","inputBuffers","outputBuffers","framesToProcess","inputData","outputData","WorkletProcessingNode","createWorkletSourceNode","startOffset","WorkletSourceNode","createRecorderAdapter","RecorderAdapterNode","createOscillator","OscillatorNode","createStreamer","streamer","StreamerNode","createConstantSource","ConstantSourceNode","createGain","GainNode","createDelay","maxDelayTime","maxTime","DelayNode","createStereoPanner","StereoPannerNode","createBiquadFilter","BiquadFilterNode","createIIRFilter","options","feedforward","feedback","length","every","value","InvalidStateError","IIRFilterNode","createBufferSource","pitchCorrection","AudioBufferSourceNode","createBufferQueueSource","AudioBufferQueueSourceNode","createBuffer","numOfChannels","AudioBuffer","createPeriodicWave","real","imag","constraints","InvalidAccessError","disableNormalization","PeriodicWave","createAnalyser","AnalyserNode","createConvolver","numberOfChannels","ConvolverNode","exports"],"sourceRoot":"../../../src","sources":["core/BaseAudioContext.ts"],"mappings":"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","ignoreList":[]}
|