react-native-audio-api 0.10.0-nightly-034f768-20251020 → 0.10.0-nightly-75aa9d0-20251022
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/build.gradle +1 -0
- package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +12 -5
- package/common/cpp/audioapi/HostObjects/effects/BiquadFilterNodeHostObject.cpp +1 -1
- package/common/cpp/audioapi/core/BaseAudioContext.cpp +12 -6
- package/common/cpp/audioapi/core/BaseAudioContext.h +14 -3
- package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +69 -32
- package/common/cpp/audioapi/core/effects/BiquadFilterNode.h +37 -1
- package/common/cpp/audioapi/core/effects/WorkletNode.cpp +31 -32
- package/common/cpp/audioapi/core/effects/WorkletNode.h +4 -7
- package/common/cpp/audioapi/core/effects/WorkletProcessingNode.cpp +12 -13
- package/common/cpp/audioapi/core/effects/WorkletProcessingNode.h +2 -5
- package/common/cpp/audioapi/core/sources/WorkletSourceNode.cpp +12 -13
- package/common/cpp/audioapi/core/sources/WorkletSourceNode.h +2 -5
- package/common/cpp/audioapi/core/utils/Constants.h +2 -1
- package/common/cpp/audioapi/core/utils/worklets/SafeIncludes.h +32 -3
- package/common/cpp/audioapi/core/utils/worklets/WorkletsRunner.cpp +75 -2
- package/common/cpp/audioapi/core/utils/worklets/WorkletsRunner.h +50 -36
- package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp +2 -3
- package/common/cpp/test/CMakeLists.txt +3 -0
- package/common/cpp/test/src/biquad/BiquadFilterChromium.cpp +389 -0
- package/common/cpp/test/src/biquad/BiquadFilterChromium.h +64 -0
- package/common/cpp/test/src/biquad/BiquadFilterTest.cpp +284 -0
- package/common/cpp/test/src/biquad/BiquadFilterTest.h +40 -0
- package/lib/commonjs/api.js +43 -0
- package/lib/commonjs/api.js.map +1 -1
- package/lib/commonjs/api.web.js +50 -0
- package/lib/commonjs/api.web.js.map +1 -1
- package/lib/commonjs/core/AudioContext.js +0 -4
- package/lib/commonjs/core/AudioContext.js.map +1 -1
- package/lib/commonjs/core/OfflineAudioContext.js +0 -4
- package/lib/commonjs/core/OfflineAudioContext.js.map +1 -1
- package/lib/commonjs/utils/index.js +1 -0
- package/lib/commonjs/utils/index.js.map +1 -1
- package/lib/commonjs/web-core/AudioScheduledSourceNode.js.map +1 -1
- package/lib/module/api.js +1 -0
- package/lib/module/api.js.map +1 -1
- package/lib/module/api.web.js +1 -0
- package/lib/module/api.web.js.map +1 -1
- package/lib/module/core/AudioContext.js +0 -4
- package/lib/module/core/AudioContext.js.map +1 -1
- package/lib/module/core/OfflineAudioContext.js +0 -4
- package/lib/module/core/OfflineAudioContext.js.map +1 -1
- package/lib/module/utils/index.js +1 -0
- package/lib/module/utils/index.js.map +1 -1
- package/lib/module/web-core/AudioScheduledSourceNode.js.map +1 -1
- package/lib/typescript/api.d.ts +1 -0
- package/lib/typescript/api.d.ts.map +1 -1
- package/lib/typescript/api.web.d.ts +1 -0
- package/lib/typescript/api.web.d.ts.map +1 -1
- package/lib/typescript/core/AudioContext.d.ts +0 -1
- package/lib/typescript/core/AudioContext.d.ts.map +1 -1
- package/lib/typescript/core/OfflineAudioContext.d.ts +0 -1
- package/lib/typescript/core/OfflineAudioContext.d.ts.map +1 -1
- package/lib/typescript/web-core/AudioBufferSourceNode.d.ts +2 -2
- package/lib/typescript/web-core/AudioBufferSourceNode.d.ts.map +1 -1
- package/lib/typescript/web-core/AudioScheduledSourceNode.d.ts +1 -1
- package/lib/typescript/web-core/AudioScheduledSourceNode.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/api.ts +10 -0
- package/src/api.web.ts +10 -0
- package/src/core/AudioContext.ts +0 -5
- package/src/core/OfflineAudioContext.ts +0 -5
- package/src/utils/index.ts +1 -0
- package/src/web-core/AudioBufferSourceNode.tsx +2 -2
- package/src/web-core/AudioScheduledSourceNode.tsx +1 -1
package/android/build.gradle
CHANGED
|
@@ -77,14 +77,15 @@ JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, createWorkletSourceNode) {
|
|
|
77
77
|
runtime, args[0]);
|
|
78
78
|
std::weak_ptr<worklets::WorkletRuntime> workletRuntime;
|
|
79
79
|
auto shouldUseUiRuntime = args[1].getBool();
|
|
80
|
+
auto shouldLockRuntime = shouldUseUiRuntime;
|
|
80
81
|
if (shouldUseUiRuntime) {
|
|
81
82
|
workletRuntime = context_->runtimeRegistry_.uiRuntime;
|
|
82
83
|
} else {
|
|
83
84
|
workletRuntime = context_->runtimeRegistry_.audioRuntime;
|
|
84
85
|
}
|
|
85
86
|
|
|
86
|
-
auto workletSourceNode =
|
|
87
|
-
|
|
87
|
+
auto workletSourceNode = context_->createWorkletSourceNode(
|
|
88
|
+
shareableWorklet, workletRuntime, shouldLockRuntime);
|
|
88
89
|
auto workletSourceNodeHostObject =
|
|
89
90
|
std::make_shared<WorkletSourceNodeHostObject>(workletSourceNode);
|
|
90
91
|
return jsi::Object::createFromHostObject(
|
|
@@ -101,6 +102,7 @@ JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, createWorkletNode) {
|
|
|
101
102
|
|
|
102
103
|
std::weak_ptr<worklets::WorkletRuntime> workletRuntime;
|
|
103
104
|
auto shouldUseUiRuntime = args[1].getBool();
|
|
105
|
+
auto shouldLockRuntime = shouldUseUiRuntime;
|
|
104
106
|
if (shouldUseUiRuntime) {
|
|
105
107
|
workletRuntime = context_->runtimeRegistry_.uiRuntime;
|
|
106
108
|
} else {
|
|
@@ -110,7 +112,11 @@ JSI_HOST_FUNCTION_IMPL(BaseAudioContextHostObject, createWorkletNode) {
|
|
|
110
112
|
auto inputChannelCount = static_cast<size_t>(args[3].getNumber());
|
|
111
113
|
|
|
112
114
|
auto workletNode = context_->createWorkletNode(
|
|
113
|
-
shareableWorklet,
|
|
115
|
+
shareableWorklet,
|
|
116
|
+
workletRuntime,
|
|
117
|
+
bufferLength,
|
|
118
|
+
inputChannelCount,
|
|
119
|
+
shouldLockRuntime);
|
|
114
120
|
auto workletNodeHostObject =
|
|
115
121
|
std::make_shared<WorkletNodeHostObject>(workletNode);
|
|
116
122
|
return jsi::Object::createFromHostObject(runtime, workletNodeHostObject);
|
|
@@ -128,14 +134,15 @@ JSI_HOST_FUNCTION_IMPL(
|
|
|
128
134
|
|
|
129
135
|
std::weak_ptr<worklets::WorkletRuntime> workletRuntime;
|
|
130
136
|
auto shouldUseUiRuntime = args[1].getBool();
|
|
137
|
+
auto shouldLockRuntime = shouldUseUiRuntime;
|
|
131
138
|
if (shouldUseUiRuntime) {
|
|
132
139
|
workletRuntime = context_->runtimeRegistry_.uiRuntime;
|
|
133
140
|
} else {
|
|
134
141
|
workletRuntime = context_->runtimeRegistry_.audioRuntime;
|
|
135
142
|
}
|
|
136
143
|
|
|
137
|
-
auto workletProcessingNode =
|
|
138
|
-
|
|
144
|
+
auto workletProcessingNode = context_->createWorkletProcessingNode(
|
|
145
|
+
shareableWorklet, workletRuntime, shouldLockRuntime);
|
|
139
146
|
auto workletProcessingNodeHostObject =
|
|
140
147
|
std::make_shared<WorkletProcessingNodeHostObject>(workletProcessingNode);
|
|
141
148
|
return jsi::Object::createFromHostObject(
|
|
@@ -67,7 +67,7 @@ JSI_HOST_FUNCTION_IMPL(BiquadFilterNodeHostObject, getFrequencyResponse) {
|
|
|
67
67
|
.getArrayBuffer(runtime);
|
|
68
68
|
auto frequencyArray =
|
|
69
69
|
reinterpret_cast<float *>(arrayBufferFrequency.data(runtime));
|
|
70
|
-
auto length = static_cast<
|
|
70
|
+
auto length = static_cast<size_t>(arrayBufferFrequency.size(runtime));
|
|
71
71
|
|
|
72
72
|
auto arrayBufferMag = args[1]
|
|
73
73
|
.getObject(runtime)
|
|
@@ -67,9 +67,11 @@ std::shared_ptr<AudioDestinationNode> BaseAudioContext::getDestination() {
|
|
|
67
67
|
|
|
68
68
|
std::shared_ptr<WorkletSourceNode> BaseAudioContext::createWorkletSourceNode(
|
|
69
69
|
std::shared_ptr<worklets::SerializableWorklet> &shareableWorklet,
|
|
70
|
-
std::weak_ptr<worklets::WorkletRuntime> runtime
|
|
70
|
+
std::weak_ptr<worklets::WorkletRuntime> runtime,
|
|
71
|
+
bool shouldLockRuntime) {
|
|
72
|
+
WorkletsRunner workletRunner(runtime, shareableWorklet, shouldLockRuntime);
|
|
71
73
|
auto workletSourceNode =
|
|
72
|
-
std::make_shared<WorkletSourceNode>(this,
|
|
74
|
+
std::make_shared<WorkletSourceNode>(this, std::move(workletRunner));
|
|
73
75
|
nodeManager_->addSourceNode(workletSourceNode);
|
|
74
76
|
return workletSourceNode;
|
|
75
77
|
}
|
|
@@ -78,9 +80,11 @@ std::shared_ptr<WorkletNode> BaseAudioContext::createWorkletNode(
|
|
|
78
80
|
std::shared_ptr<worklets::SerializableWorklet> &shareableWorklet,
|
|
79
81
|
std::weak_ptr<worklets::WorkletRuntime> runtime,
|
|
80
82
|
size_t bufferLength,
|
|
81
|
-
size_t inputChannelCount
|
|
83
|
+
size_t inputChannelCount,
|
|
84
|
+
bool shouldLockRuntime) {
|
|
85
|
+
WorkletsRunner workletRunner(runtime, shareableWorklet, shouldLockRuntime);
|
|
82
86
|
auto workletNode = std::make_shared<WorkletNode>(
|
|
83
|
-
this,
|
|
87
|
+
this, bufferLength, inputChannelCount, std::move(workletRunner));
|
|
84
88
|
nodeManager_->addProcessingNode(workletNode);
|
|
85
89
|
return workletNode;
|
|
86
90
|
}
|
|
@@ -88,9 +92,11 @@ std::shared_ptr<WorkletNode> BaseAudioContext::createWorkletNode(
|
|
|
88
92
|
std::shared_ptr<WorkletProcessingNode>
|
|
89
93
|
BaseAudioContext::createWorkletProcessingNode(
|
|
90
94
|
std::shared_ptr<worklets::SerializableWorklet> &shareableWorklet,
|
|
91
|
-
std::weak_ptr<worklets::WorkletRuntime> runtime
|
|
95
|
+
std::weak_ptr<worklets::WorkletRuntime> runtime,
|
|
96
|
+
bool shouldLockRuntime) {
|
|
97
|
+
WorkletsRunner workletRunner(runtime, shareableWorklet, shouldLockRuntime);
|
|
92
98
|
auto workletProcessingNode =
|
|
93
|
-
std::make_shared<WorkletProcessingNode>(this,
|
|
99
|
+
std::make_shared<WorkletProcessingNode>(this, std::move(workletRunner));
|
|
94
100
|
nodeManager_->addProcessingNode(workletProcessingNode);
|
|
95
101
|
return workletProcessingNode;
|
|
96
102
|
}
|
|
@@ -47,9 +47,20 @@ class BaseAudioContext {
|
|
|
47
47
|
std::shared_ptr<AudioDestinationNode> getDestination();
|
|
48
48
|
|
|
49
49
|
std::shared_ptr<RecorderAdapterNode> createRecorderAdapter();
|
|
50
|
-
std::shared_ptr<WorkletSourceNode> createWorkletSourceNode(
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
std::shared_ptr<WorkletSourceNode> createWorkletSourceNode(
|
|
51
|
+
std::shared_ptr<worklets::SerializableWorklet> &shareableWorklet,
|
|
52
|
+
std::weak_ptr<worklets::WorkletRuntime> runtime,
|
|
53
|
+
bool shouldLockRuntime = true);
|
|
54
|
+
std::shared_ptr<WorkletNode> createWorkletNode(
|
|
55
|
+
std::shared_ptr<worklets::SerializableWorklet> &shareableWorklet,
|
|
56
|
+
std::weak_ptr<worklets::WorkletRuntime> runtime,
|
|
57
|
+
size_t bufferLength,
|
|
58
|
+
size_t inputChannelCount,
|
|
59
|
+
bool shouldLockRuntime = true);
|
|
60
|
+
std::shared_ptr<WorkletProcessingNode> createWorkletProcessingNode(
|
|
61
|
+
std::shared_ptr<worklets::SerializableWorklet> &shareableWorklet,
|
|
62
|
+
std::weak_ptr<worklets::WorkletRuntime> runtime,
|
|
63
|
+
bool shouldLockRuntime = true);
|
|
53
64
|
std::shared_ptr<OscillatorNode> createOscillator();
|
|
54
65
|
std::shared_ptr<ConstantSourceNode> createConstantSource();
|
|
55
66
|
std::shared_ptr<StreamerNode> createStreamer();
|
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2010 Google Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Redistribution and use in source and binary forms, with or without
|
|
5
|
+
* modification, are permitted provided that the following conditions
|
|
6
|
+
* are met:
|
|
7
|
+
*
|
|
8
|
+
* 1. Redistributions of source code must retain the above copyright
|
|
9
|
+
* notice, this list of conditions and the following disclaimer.
|
|
10
|
+
* 2. Redistributions in binary form must reproduce the above copyright
|
|
11
|
+
* notice, this list of conditions and the following disclaimer in the
|
|
12
|
+
* documentation and/or other materials provided with the distribution.
|
|
13
|
+
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
|
|
14
|
+
* its contributors may be used to endorse or promote products derived
|
|
15
|
+
* from this software without specific prior written permission.
|
|
16
|
+
*
|
|
17
|
+
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
|
|
18
|
+
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
19
|
+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
20
|
+
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
|
21
|
+
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
22
|
+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
23
|
+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
24
|
+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
25
|
+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
26
|
+
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
+
*/
|
|
28
|
+
|
|
1
29
|
#include <audioapi/core/BaseAudioContext.h>
|
|
2
30
|
#include <audioapi/core/effects/BiquadFilterNode.h>
|
|
3
31
|
#include <audioapi/utils/AudioArray.h>
|
|
@@ -13,14 +41,14 @@ BiquadFilterNode::BiquadFilterNode(BaseAudioContext *context)
|
|
|
13
41
|
frequencyParam_ = std::make_shared<AudioParam>(
|
|
14
42
|
350.0, 0.0f, context->getNyquistFrequency(), context);
|
|
15
43
|
detuneParam_ = std::make_shared<AudioParam>(
|
|
16
|
-
0.
|
|
44
|
+
0.0f,
|
|
17
45
|
-1200 * LOG2_MOST_POSITIVE_SINGLE_FLOAT,
|
|
18
46
|
1200 * LOG2_MOST_POSITIVE_SINGLE_FLOAT,
|
|
19
47
|
context);
|
|
20
48
|
QParam_ = std::make_shared<AudioParam>(
|
|
21
|
-
1.
|
|
49
|
+
1.0f, MOST_NEGATIVE_SINGLE_FLOAT, MOST_POSITIVE_SINGLE_FLOAT, context);
|
|
22
50
|
gainParam_ = std::make_shared<AudioParam>(
|
|
23
|
-
0.
|
|
51
|
+
0.0f,
|
|
24
52
|
MOST_NEGATIVE_SINGLE_FLOAT,
|
|
25
53
|
40 * LOG10_MOST_POSITIVE_SINGLE_FLOAT,
|
|
26
54
|
context);
|
|
@@ -76,27 +104,35 @@ void BiquadFilterNode::getFrequencyResponse(
|
|
|
76
104
|
const float *frequencyArray,
|
|
77
105
|
float *magResponseOutput,
|
|
78
106
|
float *phaseResponseOutput,
|
|
79
|
-
const
|
|
107
|
+
const size_t length) {
|
|
108
|
+
#ifndef AUDIO_API_TEST_SUITE
|
|
80
109
|
applyFilter();
|
|
110
|
+
#endif
|
|
81
111
|
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
112
|
+
// Use double precision for later calculations
|
|
113
|
+
double b0 = static_cast<double>(b0_);
|
|
114
|
+
double b1 = static_cast<double>(b1_);
|
|
115
|
+
double b2 = static_cast<double>(b2_);
|
|
116
|
+
double a1 = static_cast<double>(a1_);
|
|
117
|
+
double a2 = static_cast<double>(a2_);
|
|
118
|
+
|
|
119
|
+
float nyquist = context_->getNyquistFrequency();
|
|
88
120
|
|
|
89
121
|
for (size_t i = 0; i < length; i++) {
|
|
90
|
-
|
|
122
|
+
// Convert from frequency in Hz to normalized frequency [0, 1]
|
|
123
|
+
float normalizedFreq = frequencyArray[i] / nyquist;
|
|
124
|
+
|
|
125
|
+
if (normalizedFreq < 0.0f || normalizedFreq > 1.0f) {
|
|
126
|
+
// Out-of-bounds frequencies should return NaN.
|
|
91
127
|
magResponseOutput[i] = std::nanf("");
|
|
92
128
|
phaseResponseOutput[i] = std::nanf("");
|
|
93
129
|
continue;
|
|
94
130
|
}
|
|
95
131
|
|
|
96
|
-
|
|
97
|
-
auto z = std::complex<
|
|
132
|
+
double omega = -PI * normalizedFreq;
|
|
133
|
+
auto z = std::complex<double>(std::cos(omega), std::sin(omega));
|
|
98
134
|
auto response = (b0 + (b1 + b2 * z) * z) /
|
|
99
|
-
(std::complex<
|
|
135
|
+
(std::complex<double>(1, 0) + (a1 + a2 * z) * z);
|
|
100
136
|
magResponseOutput[i] = static_cast<float>(std::abs(response));
|
|
101
137
|
phaseResponseOutput[i] =
|
|
102
138
|
static_cast<float>(atan2(imag(response), real(response)));
|
|
@@ -120,17 +156,16 @@ void BiquadFilterNode::setNormalizedCoefficients(
|
|
|
120
156
|
|
|
121
157
|
void BiquadFilterNode::setLowpassCoefficients(float frequency, float Q) {
|
|
122
158
|
// Limit frequency to [0, 1] range
|
|
123
|
-
if (frequency >= 1.
|
|
159
|
+
if (frequency >= 1.0f) {
|
|
124
160
|
setNormalizedCoefficients(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
125
161
|
return;
|
|
126
162
|
}
|
|
127
163
|
|
|
128
|
-
if (frequency <= 0.
|
|
164
|
+
if (frequency <= 0.0f) {
|
|
129
165
|
setNormalizedCoefficients(0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
130
166
|
return;
|
|
131
167
|
}
|
|
132
168
|
|
|
133
|
-
Q = std::max(0.0f, Q);
|
|
134
169
|
float g = std::pow(10.0f, 0.05f * Q);
|
|
135
170
|
|
|
136
171
|
float theta = PI * frequency;
|
|
@@ -143,16 +178,15 @@ void BiquadFilterNode::setLowpassCoefficients(float frequency, float Q) {
|
|
|
143
178
|
}
|
|
144
179
|
|
|
145
180
|
void BiquadFilterNode::setHighpassCoefficients(float frequency, float Q) {
|
|
146
|
-
if (frequency >= 1.
|
|
181
|
+
if (frequency >= 1.0f) {
|
|
147
182
|
setNormalizedCoefficients(0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
148
183
|
return;
|
|
149
184
|
}
|
|
150
|
-
if (frequency <= 0.
|
|
185
|
+
if (frequency <= 0.0f) {
|
|
151
186
|
setNormalizedCoefficients(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
152
187
|
return;
|
|
153
188
|
}
|
|
154
189
|
|
|
155
|
-
Q = std::max(0.0f, Q);
|
|
156
190
|
float g = std::pow(10.0f, 0.05f * Q);
|
|
157
191
|
|
|
158
192
|
float theta = PI * frequency;
|
|
@@ -166,13 +200,13 @@ void BiquadFilterNode::setHighpassCoefficients(float frequency, float Q) {
|
|
|
166
200
|
|
|
167
201
|
void BiquadFilterNode::setBandpassCoefficients(float frequency, float Q) {
|
|
168
202
|
// Limit frequency to [0, 1] range
|
|
169
|
-
if (frequency <= 0.
|
|
203
|
+
if (frequency <= 0.0f || frequency >= 1.0f) {
|
|
170
204
|
setNormalizedCoefficients(0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
171
205
|
return;
|
|
172
206
|
}
|
|
173
207
|
|
|
174
208
|
// Limit Q to positive values
|
|
175
|
-
if (Q <= 0.
|
|
209
|
+
if (Q <= 0.0f) {
|
|
176
210
|
setNormalizedCoefficients(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
177
211
|
return;
|
|
178
212
|
}
|
|
@@ -188,12 +222,12 @@ void BiquadFilterNode::setBandpassCoefficients(float frequency, float Q) {
|
|
|
188
222
|
void BiquadFilterNode::setLowshelfCoefficients(float frequency, float gain) {
|
|
189
223
|
float A = std::pow(10.0f, gain / 40.0f);
|
|
190
224
|
|
|
191
|
-
if (frequency >= 1.
|
|
225
|
+
if (frequency >= 1.0f) {
|
|
192
226
|
setNormalizedCoefficients(A * A, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
193
227
|
return;
|
|
194
228
|
}
|
|
195
229
|
|
|
196
|
-
if (frequency <= 0.
|
|
230
|
+
if (frequency <= 0.0f) {
|
|
197
231
|
setNormalizedCoefficients(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
198
232
|
return;
|
|
199
233
|
}
|
|
@@ -215,12 +249,12 @@ void BiquadFilterNode::setLowshelfCoefficients(float frequency, float gain) {
|
|
|
215
249
|
void BiquadFilterNode::setHighshelfCoefficients(float frequency, float gain) {
|
|
216
250
|
float A = std::pow(10.0f, gain / 40.0f);
|
|
217
251
|
|
|
218
|
-
if (frequency >= 1.
|
|
252
|
+
if (frequency >= 1.0f) {
|
|
219
253
|
setNormalizedCoefficients(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
220
254
|
return;
|
|
221
255
|
}
|
|
222
256
|
|
|
223
|
-
if (frequency <= 0.
|
|
257
|
+
if (frequency <= 0.0f) {
|
|
224
258
|
setNormalizedCoefficients(A * A, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
225
259
|
return;
|
|
226
260
|
}
|
|
@@ -247,12 +281,12 @@ void BiquadFilterNode::setPeakingCoefficients(
|
|
|
247
281
|
float gain) {
|
|
248
282
|
float A = std::pow(10.0f, gain / 40.0f);
|
|
249
283
|
|
|
250
|
-
if (frequency <= 0.
|
|
284
|
+
if (frequency <= 0.0f || frequency >= 1.0f) {
|
|
251
285
|
setNormalizedCoefficients(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
252
286
|
return;
|
|
253
287
|
}
|
|
254
288
|
|
|
255
|
-
if (Q <= 0.
|
|
289
|
+
if (Q <= 0.0f) {
|
|
256
290
|
setNormalizedCoefficients(A * A, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
257
291
|
return;
|
|
258
292
|
}
|
|
@@ -271,12 +305,12 @@ void BiquadFilterNode::setPeakingCoefficients(
|
|
|
271
305
|
}
|
|
272
306
|
|
|
273
307
|
void BiquadFilterNode::setNotchCoefficients(float frequency, float Q) {
|
|
274
|
-
if (frequency <= 0.
|
|
308
|
+
if (frequency <= 0.0f || frequency >= 1.0f) {
|
|
275
309
|
setNormalizedCoefficients(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
276
310
|
return;
|
|
277
311
|
}
|
|
278
312
|
|
|
279
|
-
if (Q <= 0.
|
|
313
|
+
if (Q <= 0.0f) {
|
|
280
314
|
setNormalizedCoefficients(0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
281
315
|
return;
|
|
282
316
|
}
|
|
@@ -290,12 +324,12 @@ void BiquadFilterNode::setNotchCoefficients(float frequency, float Q) {
|
|
|
290
324
|
}
|
|
291
325
|
|
|
292
326
|
void BiquadFilterNode::setAllpassCoefficients(float frequency, float Q) {
|
|
293
|
-
if (frequency <= 0.
|
|
327
|
+
if (frequency <= 0.0f || frequency >= 1.0f) {
|
|
294
328
|
setNormalizedCoefficients(1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
295
329
|
return;
|
|
296
330
|
}
|
|
297
331
|
|
|
298
|
-
if (Q <= 0.
|
|
332
|
+
if (Q <= 0.0f) {
|
|
299
333
|
setNormalizedCoefficients(-1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f);
|
|
300
334
|
return;
|
|
301
335
|
}
|
|
@@ -318,6 +352,9 @@ void BiquadFilterNode::applyFilter() {
|
|
|
318
352
|
auto Q = QParam_->processKRateParam(RENDER_QUANTUM_SIZE, currentTime);
|
|
319
353
|
auto gain = gainParam_->processKRateParam(RENDER_QUANTUM_SIZE, currentTime);
|
|
320
354
|
|
|
355
|
+
// NyquistFrequency is half of the sample rate.
|
|
356
|
+
// Normalized frequency is therefore:
|
|
357
|
+
// frequency / (sampleRate / 2) = (2 * frequency) / sampleRate
|
|
321
358
|
float normalizedFrequency = frequency / context_->getNyquistFrequency();
|
|
322
359
|
if (detune != 0.0f) {
|
|
323
360
|
normalizedFrequency *= std::pow(2.0f, detune / 1200.0f);
|
|
@@ -1,8 +1,39 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2010 Google Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* Redistribution and use in source and binary forms, with or without
|
|
5
|
+
* modification, are permitted provided that the following conditions
|
|
6
|
+
* are met:
|
|
7
|
+
*
|
|
8
|
+
* 1. Redistributions of source code must retain the above copyright
|
|
9
|
+
* notice, this list of conditions and the following disclaimer.
|
|
10
|
+
* 2. Redistributions in binary form must reproduce the above copyright
|
|
11
|
+
* notice, this list of conditions and the following disclaimer in the
|
|
12
|
+
* documentation and/or other materials provided with the distribution.
|
|
13
|
+
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
|
|
14
|
+
* its contributors may be used to endorse or promote products derived
|
|
15
|
+
* from this software without specific prior written permission.
|
|
16
|
+
*
|
|
17
|
+
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
|
|
18
|
+
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
19
|
+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
20
|
+
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
|
21
|
+
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
22
|
+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
23
|
+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
24
|
+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
25
|
+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
26
|
+
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
27
|
+
*/
|
|
28
|
+
|
|
1
29
|
#pragma once
|
|
2
30
|
|
|
3
31
|
#include <audioapi/core/AudioNode.h>
|
|
4
32
|
#include <audioapi/core/AudioParam.h>
|
|
5
33
|
#include <audioapi/core/types/BiquadFilterType.h>
|
|
34
|
+
#ifdef AUDIO_API_TEST_SUITE
|
|
35
|
+
#include <gtest/gtest_prod.h>
|
|
36
|
+
#endif
|
|
6
37
|
|
|
7
38
|
#include <algorithm>
|
|
8
39
|
#include <cmath>
|
|
@@ -17,6 +48,11 @@ namespace audioapi {
|
|
|
17
48
|
class AudioBus;
|
|
18
49
|
|
|
19
50
|
class BiquadFilterNode : public AudioNode {
|
|
51
|
+
#ifdef AUDIO_API_TEST_SUITE
|
|
52
|
+
friend class BiquadFilterTest;
|
|
53
|
+
FRIEND_TEST(BiquadFilterTest, GetFrequencyResponse);
|
|
54
|
+
#endif
|
|
55
|
+
|
|
20
56
|
public:
|
|
21
57
|
explicit BiquadFilterNode(BaseAudioContext *context);
|
|
22
58
|
|
|
@@ -30,7 +66,7 @@ class BiquadFilterNode : public AudioNode {
|
|
|
30
66
|
const float *frequencyArray,
|
|
31
67
|
float *magResponseOutput,
|
|
32
68
|
float *phaseResponseOutput,
|
|
33
|
-
|
|
69
|
+
size_t length);
|
|
34
70
|
|
|
35
71
|
protected:
|
|
36
72
|
std::shared_ptr<AudioBus> processNode(
|
|
@@ -4,13 +4,11 @@ namespace audioapi {
|
|
|
4
4
|
|
|
5
5
|
WorkletNode::WorkletNode(
|
|
6
6
|
BaseAudioContext *context,
|
|
7
|
-
std::shared_ptr<worklets::SerializableWorklet> &worklet,
|
|
8
|
-
std::weak_ptr<worklets::WorkletRuntime> runtime,
|
|
9
7
|
size_t bufferLength,
|
|
10
|
-
size_t inputChannelCount
|
|
8
|
+
size_t inputChannelCount,
|
|
9
|
+
WorkletsRunner &&runtime)
|
|
11
10
|
: AudioNode(context),
|
|
12
|
-
workletRunner_(runtime),
|
|
13
|
-
shareableWorklet_(worklet),
|
|
11
|
+
workletRunner_(std::move(runtime)),
|
|
14
12
|
bufferLength_(bufferLength),
|
|
15
13
|
inputChannelCount_(inputChannelCount),
|
|
16
14
|
curBuffIndex_(0) {
|
|
@@ -40,35 +38,36 @@ std::shared_ptr<AudioBus> WorkletNode::processNode(
|
|
|
40
38
|
curBuffIndex_ += shouldProcess;
|
|
41
39
|
|
|
42
40
|
/// If we filled the entire buffer, we need to execute the worklet
|
|
43
|
-
if (curBuffIndex_
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
41
|
+
if (curBuffIndex_ != bufferLength_) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
// Reset buffer index, channel buffers and execute worklet
|
|
45
|
+
curBuffIndex_ = 0;
|
|
46
|
+
workletRunner_.executeOnRuntimeSync([this, channelCount_](
|
|
47
|
+
jsi::Runtime &uiRuntimeRaw) {
|
|
48
|
+
/// Arguments preparation
|
|
49
|
+
auto jsArray = jsi::Array(uiRuntimeRaw, channelCount_);
|
|
50
|
+
for (size_t ch = 0; ch < channelCount_; ch++) {
|
|
51
|
+
auto audioArray = std::make_shared<AudioArray>(bufferLength_);
|
|
52
|
+
audioArray->copy(bus_->getChannel(ch));
|
|
53
|
+
auto sharedAudioArray = std::make_shared<AudioArrayBuffer>(audioArray);
|
|
54
|
+
auto sharedAudioArraySize = sharedAudioArray->size();
|
|
55
|
+
auto arrayBuffer =
|
|
56
|
+
jsi::ArrayBuffer(uiRuntimeRaw, std::move(sharedAudioArray));
|
|
57
|
+
arrayBuffer.setExternalMemoryPressure(
|
|
58
|
+
uiRuntimeRaw, sharedAudioArraySize);
|
|
59
|
+
jsArray.setValueAtIndex(uiRuntimeRaw, ch, std::move(arrayBuffer));
|
|
60
|
+
}
|
|
62
61
|
|
|
63
|
-
|
|
62
|
+
bus_->zero();
|
|
64
63
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
64
|
+
/// Call the worklet
|
|
65
|
+
workletRunner_.callUnsafe(
|
|
66
|
+
std::move(jsArray),
|
|
67
|
+
jsi::Value(uiRuntimeRaw, static_cast<int>(channelCount_)));
|
|
68
|
+
|
|
69
|
+
return jsi::Value::undefined();
|
|
70
|
+
});
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
return processingBus;
|
|
@@ -19,10 +19,9 @@ class WorkletNode : public AudioNode {
|
|
|
19
19
|
public:
|
|
20
20
|
explicit WorkletNode(
|
|
21
21
|
BaseAudioContext *context,
|
|
22
|
-
std::shared_ptr<worklets::SerializableWorklet> &worklet,
|
|
23
|
-
std::weak_ptr<worklets::WorkletRuntime> runtime,
|
|
24
22
|
size_t bufferLength,
|
|
25
|
-
size_t inputChannelCount
|
|
23
|
+
size_t inputChannelCount,
|
|
24
|
+
WorkletsRunner &&workletRunner
|
|
26
25
|
) : AudioNode(context) {}
|
|
27
26
|
|
|
28
27
|
protected:
|
|
@@ -36,10 +35,9 @@ class WorkletNode : public AudioNode {
|
|
|
36
35
|
public:
|
|
37
36
|
explicit WorkletNode(
|
|
38
37
|
BaseAudioContext *context,
|
|
39
|
-
std::shared_ptr<worklets::SerializableWorklet> &worklet,
|
|
40
|
-
std::weak_ptr<worklets::WorkletRuntime> runtime,
|
|
41
38
|
size_t bufferLength,
|
|
42
|
-
size_t inputChannelCount
|
|
39
|
+
size_t inputChannelCount,
|
|
40
|
+
WorkletsRunner &&workletRunner
|
|
43
41
|
);
|
|
44
42
|
|
|
45
43
|
~WorkletNode() override = default;
|
|
@@ -50,7 +48,6 @@ class WorkletNode : public AudioNode {
|
|
|
50
48
|
|
|
51
49
|
private:
|
|
52
50
|
WorkletsRunner workletRunner_;
|
|
53
|
-
std::shared_ptr<worklets::SerializableWorklet> shareableWorklet_;
|
|
54
51
|
std::shared_ptr<AudioBus> bus_;
|
|
55
52
|
|
|
56
53
|
/// @brief Length of the byte buffer that will be passed to the AudioArrayBuffer
|
|
@@ -5,9 +5,8 @@ namespace audioapi {
|
|
|
5
5
|
|
|
6
6
|
WorkletProcessingNode::WorkletProcessingNode(
|
|
7
7
|
BaseAudioContext *context,
|
|
8
|
-
|
|
9
|
-
std::
|
|
10
|
-
: AudioNode(context), workletRunner_(runtime), shareableWorklet_(worklet) {
|
|
8
|
+
WorkletsRunner &&workletRunner)
|
|
9
|
+
: AudioNode(context), workletRunner_(std::move(workletRunner)) {
|
|
11
10
|
isInitialized_ = true;
|
|
12
11
|
|
|
13
12
|
// Pre-allocate buffers for max 128 frames and 2 channels (stereo)
|
|
@@ -42,8 +41,8 @@ std::shared_ptr<AudioBus> WorkletProcessingNode::processNode(
|
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
// Execute the worklet
|
|
45
|
-
auto result = workletRunner_.
|
|
46
|
-
[this, channelCount, framesToProcess](jsi::Runtime &rt) {
|
|
44
|
+
auto result = workletRunner_.executeOnRuntimeSync(
|
|
45
|
+
[this, channelCount, framesToProcess](jsi::Runtime &rt) -> jsi::Value {
|
|
47
46
|
auto inputJsArray = jsi::Array(rt, channelCount);
|
|
48
47
|
auto outputJsArray = jsi::Array(rt, channelCount);
|
|
49
48
|
|
|
@@ -58,14 +57,14 @@ std::shared_ptr<AudioBus> WorkletProcessingNode::processNode(
|
|
|
58
57
|
outputJsArray.setValueAtIndex(rt, ch, outputArrayBuffer);
|
|
59
58
|
}
|
|
60
59
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
// We call unsafely here because we are already on the runtime thread
|
|
61
|
+
// and the runtime is locked by executeOnRuntimeSync (if
|
|
62
|
+
// shouldLockRuntime is true)
|
|
63
|
+
return workletRunner_.callUnsafe(
|
|
64
|
+
inputJsArray,
|
|
65
|
+
outputJsArray,
|
|
66
|
+
jsi::Value(rt, static_cast<int>(framesToProcess)),
|
|
67
|
+
jsi::Value(rt, this->context_->getCurrentTime()));
|
|
69
68
|
});
|
|
70
69
|
|
|
71
70
|
// Copy processed output data back to the processing bus or zero on failure
|
|
@@ -18,8 +18,7 @@ class WorkletProcessingNode : public AudioNode {
|
|
|
18
18
|
public:
|
|
19
19
|
explicit WorkletProcessingNode(
|
|
20
20
|
BaseAudioContext *context,
|
|
21
|
-
|
|
22
|
-
std::weak_ptr<worklets::WorkletRuntime> runtime
|
|
21
|
+
WorkletsRunner &&workletRunner
|
|
23
22
|
) : AudioNode(context) {}
|
|
24
23
|
|
|
25
24
|
protected:
|
|
@@ -33,8 +32,7 @@ class WorkletProcessingNode : public AudioNode {
|
|
|
33
32
|
public:
|
|
34
33
|
explicit WorkletProcessingNode(
|
|
35
34
|
BaseAudioContext *context,
|
|
36
|
-
|
|
37
|
-
std::weak_ptr<worklets::WorkletRuntime> runtime
|
|
35
|
+
WorkletsRunner &&workletRunner
|
|
38
36
|
);
|
|
39
37
|
|
|
40
38
|
protected:
|
|
@@ -42,7 +40,6 @@ class WorkletProcessingNode : public AudioNode {
|
|
|
42
40
|
|
|
43
41
|
private:
|
|
44
42
|
WorkletsRunner workletRunner_;
|
|
45
|
-
std::shared_ptr<worklets::SerializableWorklet> shareableWorklet_;
|
|
46
43
|
std::vector<std::shared_ptr<AudioArrayBuffer>> inputBuffsHandles_;
|
|
47
44
|
std::vector<std::shared_ptr<AudioArrayBuffer>> outputBuffsHandles_;
|
|
48
45
|
};
|