node-web-audio-api 0.18.0 → 0.19.0

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 (49) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/TODOS.md +140 -12
  3. package/index.mjs +10 -5
  4. package/js/AnalyserNode.js +262 -48
  5. package/js/AudioBuffer.js +244 -0
  6. package/js/AudioBufferSourceNode.js +265 -41
  7. package/js/AudioContext.js +271 -28
  8. package/js/AudioDestinationNode.js +42 -100
  9. package/js/AudioListener.js +219 -0
  10. package/js/AudioNode.js +323 -0
  11. package/js/AudioParam.js +252 -39
  12. package/js/AudioScheduledSourceNode.js +105 -0
  13. package/js/BaseAudioContext.js +419 -0
  14. package/js/BiquadFilterNode.js +221 -29
  15. package/js/ChannelMergerNode.js +96 -22
  16. package/js/ChannelSplitterNode.js +96 -22
  17. package/js/ConstantSourceNode.js +92 -26
  18. package/js/ConvolverNode.js +161 -29
  19. package/js/DelayNode.js +115 -21
  20. package/js/DynamicsCompressorNode.js +198 -27
  21. package/js/GainNode.js +107 -21
  22. package/js/IIRFilterNode.js +139 -23
  23. package/js/MediaStreamAudioSourceNode.js +83 -24
  24. package/js/OfflineAudioContext.js +182 -34
  25. package/js/OscillatorNode.js +195 -32
  26. package/js/PannerNode.js +461 -56
  27. package/js/PeriodicWave.js +67 -3
  28. package/js/StereoPannerNode.js +107 -21
  29. package/js/WaveShaperNode.js +147 -29
  30. package/js/lib/cast.js +19 -0
  31. package/js/lib/errors.js +10 -55
  32. package/js/lib/events.js +20 -0
  33. package/js/lib/symbols.js +5 -0
  34. package/js/lib/utils.js +12 -12
  35. package/js/monkey-patch.js +32 -30
  36. package/node-web-audio-api.darwin-arm64.node +0 -0
  37. package/node-web-audio-api.darwin-x64.node +0 -0
  38. package/node-web-audio-api.linux-arm-gnueabihf.node +0 -0
  39. package/node-web-audio-api.linux-arm64-gnu.node +0 -0
  40. package/node-web-audio-api.linux-x64-gnu.node +0 -0
  41. package/node-web-audio-api.win32-arm64-msvc.node +0 -0
  42. package/node-web-audio-api.win32-x64-msvc.node +0 -0
  43. package/package.json +7 -4
  44. package/run-wpt.md +27 -0
  45. package/run-wpt.sh +5 -0
  46. package/js/AudioNode.mixin.js +0 -132
  47. package/js/AudioScheduledSourceNode.mixin.js +0 -67
  48. package/js/BaseAudioContext.mixin.js +0 -154
  49. package/js/EventTarget.mixin.js +0 -60
package/js/AudioParam.js CHANGED
@@ -17,116 +17,329 @@
17
17
  // -------------------------------------------------------------------------- //
18
18
  // -------------------------------------------------------------------------- //
19
19
 
20
- const { throwSanitizedError } = require('./lib/errors.js');
20
+ const conversions = require('webidl-conversions');
21
21
 
22
- const kNativeAudioParam = Symbol('node-web-audio-api:audio-param');
22
+ const {
23
+ toSanitizedSequence,
24
+ } = require('./lib/cast.js');
25
+ const {
26
+ throwSanitizedError,
27
+ } = require('./lib/errors.js');
28
+
29
+ const {
30
+ kEnumerableProperty,
31
+ kHiddenProperty,
32
+ } = require('./lib/utils.js');
33
+ const {
34
+ kNapiObj,
35
+ } = require('./lib/symbols.js');
23
36
 
24
37
  class AudioParam {
25
- constructor(nativeAudioParam) {
26
- this[kNativeAudioParam] = nativeAudioParam;
38
+ constructor(options) {
39
+ // Make constructor "private"
40
+ if (
41
+ (typeof options !== 'object') ||
42
+ !(kNapiObj in options) ||
43
+ options[kNapiObj]['Symbol.toStringTag'] !== 'AudioParam'
44
+ ) {
45
+ throw new TypeError('Illegal constructor');
46
+ }
47
+
48
+ Object.defineProperty(this, kNapiObj, {
49
+ value: options[kNapiObj],
50
+ ...kHiddenProperty,
51
+ });
27
52
  }
28
- // getters
29
53
 
30
54
  get value() {
31
- return this[kNativeAudioParam].value;
55
+ if (!(this instanceof AudioParam)) {
56
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioParam\'');
57
+ }
58
+
59
+ return this[kNapiObj].value;
60
+ }
61
+
62
+ set value(value) {
63
+ if (!(this instanceof AudioParam)) {
64
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioParam\'');
65
+ }
66
+
67
+ value = conversions['float'](value, {
68
+ context: `Failed to set the 'value' property on 'AudioParam': The provided float value`,
69
+ });
70
+
71
+ try {
72
+ this[kNapiObj].value = value;
73
+ } catch (err) {
74
+ throwSanitizedError(err);
75
+ }
32
76
  }
33
77
 
34
78
  get automationRate() {
35
- return this[kNativeAudioParam].automationRate;
79
+ if (!(this instanceof AudioParam)) {
80
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioParam\'');
81
+ }
82
+
83
+ return this[kNapiObj].automationRate;
84
+ }
85
+
86
+ set automationRate(value) {
87
+ if (!(this instanceof AudioParam)) {
88
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioParam\'');
89
+ }
90
+
91
+ if (!['a-rate', 'k-rate'].includes(value)) {
92
+ console.warn(`Failed to set the 'automationRate' property on 'AudioParam': Value '${value}' is not a valid 'AutomationRate' enum value`);
93
+ return;
94
+ }
95
+
96
+ try {
97
+ this[kNapiObj].automationRate = value;
98
+ } catch (err) {
99
+ throwSanitizedError(err);
100
+ }
36
101
  }
37
102
 
38
103
  get defaultValue() {
39
- return this[kNativeAudioParam].defaultValue;
104
+ if (!(this instanceof AudioParam)) {
105
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioParam\'');
106
+ }
107
+
108
+ return this[kNapiObj].defaultValue;
40
109
  }
41
110
 
42
111
  get minValue() {
43
- return this[kNativeAudioParam].minValue;
112
+ if (!(this instanceof AudioParam)) {
113
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioParam\'');
114
+ }
115
+
116
+ return this[kNapiObj].minValue;
44
117
  }
45
118
 
46
119
  get maxValue() {
47
- return this[kNativeAudioParam].maxValue;
120
+ if (!(this instanceof AudioParam)) {
121
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioParam\'');
122
+ }
123
+
124
+ return this[kNapiObj].maxValue;
48
125
  }
49
126
 
50
- // setters
127
+ setValueAtTime(value, startTime) {
128
+ if (!(this instanceof AudioParam)) {
129
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioParam\'');
130
+ }
51
131
 
52
- set value(value) {
53
- try {
54
- this[kNativeAudioParam].value = value;
55
- } catch (err) {
56
- throwSanitizedError(err);
132
+ if (arguments.length < 2) {
133
+ throw new TypeError(`Failed to execute 'setValueAtTime' on 'AudioParam': 2 argument required, but only ${arguments.length} present`);
57
134
  }
58
- }
59
135
 
60
- set automationRate(value) {
136
+ value = conversions['float'](value, {
137
+ context: `Failed to execute 'setValueAtTime' on 'AudioParam': Parameter 1`,
138
+ });
139
+
140
+ startTime = conversions['double'](startTime, {
141
+ context: `Failed to execute 'setValueAtTime' on 'AudioParam': Parameter 2`,
142
+ });
143
+
61
144
  try {
62
- this[kNativeAudioParam].automationRate = value;
145
+ this[kNapiObj].setValueAtTime(value, startTime);
63
146
  } catch (err) {
64
147
  throwSanitizedError(err);
65
148
  }
149
+
150
+ return this;
66
151
  }
67
152
 
68
- // methods
153
+ linearRampToValueAtTime(value, endTime) {
154
+ if (!(this instanceof AudioParam)) {
155
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioParam\'');
156
+ }
157
+
158
+ if (arguments.length < 2) {
159
+ throw new TypeError(`Failed to execute 'linearRampToValueAtTime' on 'AudioParam': 2 argument required, but only ${arguments.length} present`);
160
+ }
161
+
162
+ value = conversions['float'](value, {
163
+ context: `Failed to execute 'linearRampToValueAtTime' on 'AudioParam': Parameter 1`,
164
+ });
165
+
166
+ endTime = conversions['double'](endTime, {
167
+ context: `Failed to execute 'linearRampToValueAtTime' on 'AudioParam': Parameter 2`,
168
+ });
69
169
 
70
- setValueAtTime(...args) {
71
170
  try {
72
- return this[kNativeAudioParam].setValueAtTime(...args);
171
+ this[kNapiObj].linearRampToValueAtTime(value, endTime);
73
172
  } catch (err) {
74
173
  throwSanitizedError(err);
75
174
  }
175
+
176
+ return this;
76
177
  }
77
178
 
78
- linearRampToValueAtTime(...args) {
179
+ exponentialRampToValueAtTime(value, endTime) {
180
+ if (!(this instanceof AudioParam)) {
181
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioParam\'');
182
+ }
183
+
184
+ if (arguments.length < 2) {
185
+ throw new TypeError(`Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': 2 argument required, but only ${arguments.length} present`);
186
+ }
187
+
188
+ value = conversions['float'](value, {
189
+ context: `Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': Parameter 1`,
190
+ });
191
+
192
+ endTime = conversions['double'](endTime, {
193
+ context: `Failed to execute 'exponentialRampToValueAtTime' on 'AudioParam': Parameter 2`,
194
+ });
195
+
79
196
  try {
80
- return this[kNativeAudioParam].linearRampToValueAtTime(...args);
197
+ this[kNapiObj].exponentialRampToValueAtTime(value, endTime);
81
198
  } catch (err) {
82
199
  throwSanitizedError(err);
83
200
  }
201
+
202
+ return this;
84
203
  }
85
204
 
86
- exponentialRampToValueAtTime(...args) {
205
+ setTargetAtTime(target, startTime, timeConstant) {
206
+ if (!(this instanceof AudioParam)) {
207
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioParam\'');
208
+ }
209
+
210
+ if (arguments.length < 3) {
211
+ throw new TypeError(`Failed to execute 'setTargetAtTime' on 'AudioParam': 3 argument required, but only ${arguments.length} present`);
212
+ }
213
+
214
+ target = conversions['float'](target, {
215
+ context: `Failed to execute 'setTargetAtTime' on 'AudioParam': Parameter 1`,
216
+ });
217
+
218
+ startTime = conversions['double'](startTime, {
219
+ context: `Failed to execute 'setTargetAtTime' on 'AudioParam': Parameter 2`,
220
+ });
221
+
222
+ timeConstant = conversions['float'](timeConstant, {
223
+ context: `Failed to execute 'setTargetAtTime' on 'AudioParam': Parameter 3`,
224
+ });
225
+
87
226
  try {
88
- return this[kNativeAudioParam].exponentialRampToValueAtTime(...args);
227
+ this[kNapiObj].setTargetAtTime(target, startTime, timeConstant);
89
228
  } catch (err) {
90
229
  throwSanitizedError(err);
91
230
  }
231
+
232
+ return this;
92
233
  }
93
234
 
94
- setTargetAtTime(...args) {
235
+ setValueCurveAtTime(values, startTime, duration) {
236
+ if (!(this instanceof AudioParam)) {
237
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioParam\'');
238
+ }
239
+
240
+ if (arguments.length < 3) {
241
+ throw new TypeError(`Failed to execute 'setValueCurveAtTime' on 'AudioParam': 3 argument required, but only ${arguments.length} present`);
242
+ }
243
+
95
244
  try {
96
- return this[kNativeAudioParam].setTargetAtTime(...args);
245
+ values = toSanitizedSequence(values, Float32Array);
97
246
  } catch (err) {
98
- throwSanitizedError(err);
247
+ throw new TypeError(`Failed to execute 'setValueCurveAtTime': Parameter 1 ${err.message}`);
99
248
  }
100
- }
101
249
 
102
- setValueCurveAtTime(...args) {
250
+ startTime = conversions['double'](startTime, {
251
+ context: `Failed to execute 'setValueCurveAtTime' on 'AudioParam': Parameter 2`,
252
+ });
253
+
254
+ duration = conversions['double'](duration, {
255
+ context: `Failed to execute 'setValueCurveAtTime' on 'AudioParam': Parameter 3`,
256
+ });
257
+
103
258
  try {
104
- return this[kNativeAudioParam].setValueCurveAtTime(...args);
259
+ this[kNapiObj].setValueCurveAtTime(values, startTime, duration);
105
260
  } catch (err) {
106
261
  throwSanitizedError(err);
107
262
  }
263
+
264
+ return this;
108
265
  }
109
266
 
110
- cancelScheduledValues(...args) {
267
+ cancelScheduledValues(cancelTime) {
268
+ if (!(this instanceof AudioParam)) {
269
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioParam\'');
270
+ }
271
+
272
+ if (arguments.length < 1) {
273
+ throw new TypeError(`Failed to execute 'cancelScheduledValues' on 'AudioParam': 1 argument required, but only ${arguments.length} present`);
274
+ }
275
+
276
+ cancelTime = conversions['double'](cancelTime, {
277
+ context: `Failed to execute 'cancelScheduledValues' on 'AudioParam': Parameter 1`,
278
+ });
279
+
111
280
  try {
112
- return this[kNativeAudioParam].cancelScheduledValues(...args);
281
+ this[kNapiObj].cancelScheduledValues(cancelTime);
113
282
  } catch (err) {
114
283
  throwSanitizedError(err);
115
284
  }
285
+
286
+ return this;
116
287
  }
117
288
 
118
- cancelAndHoldAtTime(...args) {
289
+ cancelAndHoldAtTime(cancelTime) {
290
+ if (!(this instanceof AudioParam)) {
291
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioParam\'');
292
+ }
293
+
294
+ if (arguments.length < 1) {
295
+ throw new TypeError(`Failed to execute 'cancelAndHoldAtTime' on 'AudioParam': 1 argument required, but only ${arguments.length} present`);
296
+ }
297
+
298
+ cancelTime = conversions['double'](cancelTime, {
299
+ context: `Failed to execute 'cancelAndHoldAtTime' on 'AudioParam': Parameter 1`,
300
+ });
301
+
119
302
  try {
120
- return this[kNativeAudioParam].cancelAndHoldAtTime(...args);
303
+ this[kNapiObj].cancelAndHoldAtTime(cancelTime);
121
304
  } catch (err) {
122
305
  throwSanitizedError(err);
123
306
  }
307
+
308
+ return this;
124
309
  }
125
310
 
126
311
  }
127
312
 
128
- module.exports.kNativeAudioParam = kNativeAudioParam;
129
- module.exports.AudioParam = AudioParam;
313
+ Object.defineProperties(AudioParam, {
314
+ length: {
315
+ __proto__: null,
316
+ writable: false,
317
+ enumerable: false,
318
+ configurable: true,
319
+ value: 0,
320
+ },
321
+ });
130
322
 
323
+ Object.defineProperties(AudioParam.prototype, {
324
+ [Symbol.toStringTag]: {
325
+ __proto__: null,
326
+ writable: false,
327
+ enumerable: false,
328
+ configurable: true,
329
+ value: 'AudioParam',
330
+ },
331
+ value: kEnumerableProperty,
332
+ automationRate: kEnumerableProperty,
333
+ defaultValue: kEnumerableProperty,
334
+ minValue: kEnumerableProperty,
335
+ maxValue: kEnumerableProperty,
336
+ setValueAtTime: kEnumerableProperty,
337
+ linearRampToValueAtTime: kEnumerableProperty,
338
+ exponentialRampToValueAtTime: kEnumerableProperty,
339
+ setTargetAtTime: kEnumerableProperty,
340
+ setValueCurveAtTime: kEnumerableProperty,
341
+ cancelScheduledValues: kEnumerableProperty,
342
+ cancelAndHoldAtTime: kEnumerableProperty,
343
+ });
131
344
 
132
-
345
+ module.exports = AudioParam;
@@ -0,0 +1,105 @@
1
+ const conversions = require('webidl-conversions');
2
+
3
+ const {
4
+ throwSanitizedError,
5
+ } = require('./lib/errors.js');
6
+ const {
7
+ isFunction,
8
+ kEnumerableProperty,
9
+ } = require('./lib/utils.js');
10
+ const {
11
+ kNapiObj,
12
+ } = require('./lib/symbols.js');
13
+
14
+ const AudioNode = require('./AudioNode.js');
15
+
16
+ class AudioScheduledSourceNode extends AudioNode {
17
+ #onended = null;
18
+
19
+ constructor(context, options) {
20
+ // Make constructor "private"
21
+ if (
22
+ (typeof options !== 'object')
23
+ || !(kNapiObj in options)
24
+ ) {
25
+ throw new TypeError('Illegal constructor');
26
+ }
27
+
28
+ super(context, options);
29
+ }
30
+
31
+ get onended() {
32
+ if (!(this instanceof AudioScheduledSourceNode)) {
33
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioScheduledSourceNode\'');
34
+ }
35
+
36
+ return this.#onended;
37
+ }
38
+
39
+ set onended(value) {
40
+ if (!(this instanceof AudioScheduledSourceNode)) {
41
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioScheduledSourceNode\'');
42
+ }
43
+
44
+ if (isFunction(value) || value === null) {
45
+ this.#onended = value;
46
+ }
47
+ }
48
+
49
+ start(when = 0) {
50
+ if (!(this instanceof AudioScheduledSourceNode)) {
51
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioScheduledSourceNode\'');
52
+ }
53
+
54
+ when = conversions['double'](when, {
55
+ context: `Failed to execute 'start' on 'AudioScheduledSourceNode': Parameter 1`,
56
+ });
57
+
58
+ try {
59
+ return this[kNapiObj].start(when);
60
+ } catch (err) {
61
+ throwSanitizedError(err);
62
+ }
63
+ }
64
+
65
+ stop(when = 0) {
66
+ if (!(this instanceof AudioScheduledSourceNode)) {
67
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioScheduledSourceNode\'');
68
+ }
69
+
70
+ when = conversions['double'](when, {
71
+ context: `Failed to execute 'stop' on 'AudioScheduledSourceNode': Parameter 1`,
72
+ });
73
+
74
+ try {
75
+ return this[kNapiObj].stop(when);
76
+ } catch (err) {
77
+ throwSanitizedError(err);
78
+ }
79
+ }
80
+ }
81
+
82
+ Object.defineProperties(AudioScheduledSourceNode, {
83
+ length: {
84
+ __proto__: null,
85
+ writable: false,
86
+ enumerable: false,
87
+ configurable: true,
88
+ value: 0,
89
+ },
90
+ });
91
+
92
+ Object.defineProperties(AudioScheduledSourceNode.prototype, {
93
+ [Symbol.toStringTag]: {
94
+ __proto__: null,
95
+ writable: false,
96
+ enumerable: false,
97
+ configurable: true,
98
+ value: 'AudioScheduledSourceNode',
99
+ },
100
+ onended: kEnumerableProperty,
101
+ start: kEnumerableProperty,
102
+ stop: kEnumerableProperty,
103
+ });
104
+
105
+ module.exports = AudioScheduledSourceNode;