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.
Files changed (65) hide show
  1. package/android/build.gradle +1 -0
  2. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.cpp +12 -5
  3. package/common/cpp/audioapi/HostObjects/effects/BiquadFilterNodeHostObject.cpp +1 -1
  4. package/common/cpp/audioapi/core/BaseAudioContext.cpp +12 -6
  5. package/common/cpp/audioapi/core/BaseAudioContext.h +14 -3
  6. package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +69 -32
  7. package/common/cpp/audioapi/core/effects/BiquadFilterNode.h +37 -1
  8. package/common/cpp/audioapi/core/effects/WorkletNode.cpp +31 -32
  9. package/common/cpp/audioapi/core/effects/WorkletNode.h +4 -7
  10. package/common/cpp/audioapi/core/effects/WorkletProcessingNode.cpp +12 -13
  11. package/common/cpp/audioapi/core/effects/WorkletProcessingNode.h +2 -5
  12. package/common/cpp/audioapi/core/sources/WorkletSourceNode.cpp +12 -13
  13. package/common/cpp/audioapi/core/sources/WorkletSourceNode.h +2 -5
  14. package/common/cpp/audioapi/core/utils/Constants.h +2 -1
  15. package/common/cpp/audioapi/core/utils/worklets/SafeIncludes.h +32 -3
  16. package/common/cpp/audioapi/core/utils/worklets/WorkletsRunner.cpp +75 -2
  17. package/common/cpp/audioapi/core/utils/worklets/WorkletsRunner.h +50 -36
  18. package/common/cpp/audioapi/libs/ffmpeg/FFmpegDecoding.cpp +2 -3
  19. package/common/cpp/test/CMakeLists.txt +3 -0
  20. package/common/cpp/test/src/biquad/BiquadFilterChromium.cpp +389 -0
  21. package/common/cpp/test/src/biquad/BiquadFilterChromium.h +64 -0
  22. package/common/cpp/test/src/biquad/BiquadFilterTest.cpp +284 -0
  23. package/common/cpp/test/src/biquad/BiquadFilterTest.h +40 -0
  24. package/lib/commonjs/api.js +43 -0
  25. package/lib/commonjs/api.js.map +1 -1
  26. package/lib/commonjs/api.web.js +50 -0
  27. package/lib/commonjs/api.web.js.map +1 -1
  28. package/lib/commonjs/core/AudioContext.js +0 -4
  29. package/lib/commonjs/core/AudioContext.js.map +1 -1
  30. package/lib/commonjs/core/OfflineAudioContext.js +0 -4
  31. package/lib/commonjs/core/OfflineAudioContext.js.map +1 -1
  32. package/lib/commonjs/utils/index.js +1 -0
  33. package/lib/commonjs/utils/index.js.map +1 -1
  34. package/lib/commonjs/web-core/AudioScheduledSourceNode.js.map +1 -1
  35. package/lib/module/api.js +1 -0
  36. package/lib/module/api.js.map +1 -1
  37. package/lib/module/api.web.js +1 -0
  38. package/lib/module/api.web.js.map +1 -1
  39. package/lib/module/core/AudioContext.js +0 -4
  40. package/lib/module/core/AudioContext.js.map +1 -1
  41. package/lib/module/core/OfflineAudioContext.js +0 -4
  42. package/lib/module/core/OfflineAudioContext.js.map +1 -1
  43. package/lib/module/utils/index.js +1 -0
  44. package/lib/module/utils/index.js.map +1 -1
  45. package/lib/module/web-core/AudioScheduledSourceNode.js.map +1 -1
  46. package/lib/typescript/api.d.ts +1 -0
  47. package/lib/typescript/api.d.ts.map +1 -1
  48. package/lib/typescript/api.web.d.ts +1 -0
  49. package/lib/typescript/api.web.d.ts.map +1 -1
  50. package/lib/typescript/core/AudioContext.d.ts +0 -1
  51. package/lib/typescript/core/AudioContext.d.ts.map +1 -1
  52. package/lib/typescript/core/OfflineAudioContext.d.ts +0 -1
  53. package/lib/typescript/core/OfflineAudioContext.d.ts.map +1 -1
  54. package/lib/typescript/web-core/AudioBufferSourceNode.d.ts +2 -2
  55. package/lib/typescript/web-core/AudioBufferSourceNode.d.ts.map +1 -1
  56. package/lib/typescript/web-core/AudioScheduledSourceNode.d.ts +1 -1
  57. package/lib/typescript/web-core/AudioScheduledSourceNode.d.ts.map +1 -1
  58. package/package.json +8 -8
  59. package/src/api.ts +10 -0
  60. package/src/api.web.ts +10 -0
  61. package/src/core/AudioContext.ts +0 -5
  62. package/src/core/OfflineAudioContext.ts +0 -5
  63. package/src/utils/index.ts +1 -0
  64. package/src/web-core/AudioBufferSourceNode.tsx +2 -2
  65. package/src/web-core/AudioScheduledSourceNode.tsx +1 -1
@@ -165,6 +165,7 @@ android {
165
165
  "**/libfolly_runtime.so",
166
166
  "**/libglog.so",
167
167
  "**/libhermes.so",
168
+ "**/libhermesvm.so",
168
169
  "**/libhermes-executor-debug.so",
169
170
  "**/libhermes_executor.so",
170
171
  "**/libhermestooling.so",
@@ -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
- context_->createWorkletSourceNode(shareableWorklet, workletRuntime);
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, workletRuntime, bufferLength, inputChannelCount);
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
- context_->createWorkletProcessingNode(shareableWorklet, workletRuntime);
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<int>(arrayBufferFrequency.size(runtime));
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, shareableWorklet, runtime);
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, shareableWorklet, runtime, bufferLength, inputChannelCount);
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, shareableWorklet, runtime);
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(std::shared_ptr<worklets::SerializableWorklet> &shareableWorklet, std::weak_ptr<worklets::WorkletRuntime> runtime);
51
- std::shared_ptr<WorkletNode> createWorkletNode(std::shared_ptr<worklets::SerializableWorklet> &shareableWorklet, std::weak_ptr<worklets::WorkletRuntime> runtime, size_t bufferLength, size_t inputChannelCount);
52
- std::shared_ptr<WorkletProcessingNode> createWorkletProcessingNode(std::shared_ptr<worklets::SerializableWorklet> &shareableWorklet, std::weak_ptr<worklets::WorkletRuntime> runtime);
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.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.0, MOST_NEGATIVE_SINGLE_FLOAT, MOST_POSITIVE_SINGLE_FLOAT, context);
49
+ 1.0f, MOST_NEGATIVE_SINGLE_FLOAT, MOST_POSITIVE_SINGLE_FLOAT, context);
22
50
  gainParam_ = std::make_shared<AudioParam>(
23
- 0.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 int length) {
107
+ const size_t length) {
108
+ #ifndef AUDIO_API_TEST_SUITE
80
109
  applyFilter();
110
+ #endif
81
111
 
82
- // Local copies for micro-optimization
83
- float b0 = b0_;
84
- float b1 = b1_;
85
- float b2 = b2_;
86
- float a1 = a1_;
87
- float a2 = a2_;
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
- if (frequencyArray[i] < 0.0 || frequencyArray[i] > 1.0) {
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
- auto omega = -PI * frequencyArray[i] / context_->getNyquistFrequency();
97
- auto z = std::complex<float>(cos(omega), sin(omega));
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<float>(1, 0) + (a1 + a2 * z) * z);
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.0) {
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.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.0) {
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.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.0 || frequency >= 1.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.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.0) {
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.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.0) {
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.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.0 || frequency >= 1.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.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.0 || frequency >= 1.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.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.0 || frequency >= 1.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.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
- int length);
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_ == bufferLength_) {
44
- // Reset buffer index, channel buffers and execute worklet
45
- curBuffIndex_ = 0;
46
- workletRunner_.executeOnRuntimeGuardedSync(
47
- [this, channelCount_](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 =
54
- std::make_shared<AudioArrayBuffer>(audioArray);
55
- auto sharedAudioArraySize = sharedAudioArray->size();
56
- auto arrayBuffer =
57
- jsi::ArrayBuffer(uiRuntimeRaw, std::move(sharedAudioArray));
58
- arrayBuffer.setExternalMemoryPressure(
59
- uiRuntimeRaw, sharedAudioArraySize);
60
- jsArray.setValueAtIndex(uiRuntimeRaw, ch, std::move(arrayBuffer));
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
- bus_->zero();
62
+ bus_->zero();
64
63
 
65
- workletRunner_.executeWorklet(
66
- shareableWorklet_,
67
- std::move(jsArray),
68
- jsi::Value(uiRuntimeRaw, static_cast<int>(channelCount_)));
69
- return jsi::Value::undefined();
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
- std::shared_ptr<worklets::SerializableWorklet> &worklet,
9
- std::weak_ptr<worklets::WorkletRuntime> runtime)
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_.executeOnRuntimeGuardedSync(
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
- return workletRunner_
62
- .executeWorklet(
63
- shareableWorklet_,
64
- inputJsArray,
65
- outputJsArray,
66
- jsi::Value(rt, static_cast<int>(framesToProcess)),
67
- jsi::Value(rt, this->context_->getCurrentTime()))
68
- .value_or(jsi::Value::undefined());
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
- std::shared_ptr<worklets::SerializableWorklet> &worklet,
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
- std::shared_ptr<worklets::SerializableWorklet> &worklet,
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
  };