node-web-audio-api 0.20.0 → 0.21.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.
@@ -0,0 +1,87 @@
1
+ const { platform, arch } = process;
2
+
3
+ let nativeBinding = null;
4
+ let loadError = null;
5
+
6
+ switch (platform) {
7
+ case 'win32':
8
+ switch (arch) {
9
+ case 'x64':
10
+ try {
11
+ nativeBinding = require('./node-web-audio-api.win32-x64-msvc.node');
12
+ } catch (e) {
13
+ loadError = e;
14
+ }
15
+ break;
16
+ case 'arm64':
17
+ try {
18
+ nativeBinding = require('./node-web-audio-api.win32-arm64-msvc.node');
19
+ } catch (e) {
20
+ loadError = e;
21
+ }
22
+ break;
23
+ default:
24
+ throw new Error(`Unsupported architecture on Windows: ${arch}`);
25
+ }
26
+ break;
27
+ case 'darwin':
28
+ switch (arch) {
29
+ case 'x64':
30
+ try {
31
+ nativeBinding = require('./node-web-audio-api.darwin-x64.node');
32
+ } catch (e) {
33
+ loadError = e;
34
+ }
35
+ break;
36
+ case 'arm64':
37
+ try {
38
+ nativeBinding = require('./node-web-audio-api.darwin-arm64.node');
39
+ } catch (e) {
40
+ loadError = e;
41
+ }
42
+ break;
43
+ default:
44
+ throw new Error(`Unsupported architecture on macOS: ${arch}`);
45
+ }
46
+ break;
47
+ case 'linux':
48
+ switch (arch) {
49
+ case 'x64':
50
+ try {
51
+ nativeBinding = require('./node-web-audio-api.linux-x64-gnu.node');
52
+ } catch (e) {
53
+ loadError = e;
54
+ }
55
+ break;
56
+ case 'arm64':
57
+ try {
58
+ nativeBinding = require('./node-web-audio-api.linux-arm64-gnu.node');
59
+ } catch (e) {
60
+ loadError = e;
61
+ }
62
+ break;
63
+ case 'arm':
64
+ try {
65
+ nativeBinding = require('./node-web-audio-api.linux-arm-gnueabihf.node');
66
+ } catch (e) {
67
+ loadError = e;
68
+ }
69
+ break;
70
+ default:
71
+ throw new Error(`Unsupported architecture on Linux: ${arch}`);
72
+ }
73
+ break;
74
+ default:
75
+ throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`);
76
+ }
77
+
78
+ if (!nativeBinding) {
79
+ if (loadError) {
80
+ throw loadError;
81
+ }
82
+
83
+ throw new Error(`Failed to load native binding for OS: ${platform}, architecture: ${arch}`);
84
+ }
85
+
86
+ module.exports = nativeBinding;
87
+
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-web-audio-api",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "author": "Benjamin Matuszewski",
5
5
  "description": "Node.js bindings for web-audio-api-rs using napi-rs",
6
6
  "exports": {
@@ -73,6 +73,8 @@
73
73
  "dependencies": {
74
74
  "@napi-rs/cli": "^2.14.3",
75
75
  "@node-rs/helper": "^1.3.3",
76
+ "caller": "^1.1.0",
77
+ "node-fetch": "^3.3.2",
76
78
  "webidl-conversions": "^7.0.0"
77
79
  }
78
80
  }
package/TODOS.md DELETED
@@ -1,143 +0,0 @@
1
- # TODO
2
-
3
- ## MISC
4
-
5
- - [x] decode audio data in dedicated thread
6
- - [x] Use node DOMExeption <https://nodejs.org/api/globals.html#domexception>
7
- - [x] connect / disconnect
8
- - [x] _napi_ review tsfn store implementation _or remove_
9
- - [x] implement ScriptProcesorNode _on going_
10
- - [x] _napi_ clean internal audio_buffer __internal_caller__, use JsNull instead
11
- - [x] Refactor Events:
12
- + [x] extend Event for all specific event types
13
- + [x] Register AudioScheduledSourceNode listener only on start
14
-
15
- - [ ] reuse event objects across calls
16
-
17
- -> proxy EventListener
18
-
19
- - [ ] wpt: mock for `URL.createObjectURL`
20
- - [ ] wpt: mock for `requestAnimationFrame` cf. https://github.com/nodejs/help/issues/2483
21
- - [ ] make sure we don't try to use `in` operator on null values
22
-
23
- - [ ] _rust_ AudioParam failing tests
24
- - [ ] _rust_ AudioBufferSourceNode failing tests
25
- - [ ] _rust_ IIRFilter node
26
-
27
- - [ ] refactor - Add context string in `throwSanitizedError` and to `toSanitizedSequence`
28
- - [ ] Rust - review Symbol.toStringTag https://github.com/nodejs/node/issues/41358
29
- cf. https://github.com/nodejs/node/issues/41358#issuecomment-1003595890
30
- ```
31
- // fails...
32
- let symbols = ctx
33
- .env
34
- .get_global()?
35
- .get_named_property::<JsUnknown>("Symbol")?
36
- .coerce_to_object()?;
37
- let to_string_tag = symbols.get_named_property("toStringTag")?;
38
-
39
- js_this.set_property(to_string_tag, &ctx.env.create_string("AudioContext")?);
40
-
41
- // ----
42
- 151 | js_this.set_property(to_string_tag, &ctx.env.create_string("AudioContext")?);
43
- | ------------ ^^^^^^^^^^^^^ the trait `napi::NapiRaw` is not implemented for `()`
44
- ```
45
-
46
- - [ ] wpt bot
47
- - [ ] wpt - handle loading of 4-channels sound file
48
-
49
- - [ ] _rust_ decodeAudioData should throw EncodingError
50
- - review JS side when done
51
-
52
- - [-] AnalyserNode -> requires script processor and request animation frame
53
-
54
- - [x] DelayNode
55
- - [x] protect AudioBuffer arguments
56
- - [x] AudioNode setters (handle enum types, cf audio param too)
57
- - [x] This is weird `jsExport.AudioBuffer = require('./AudioBuffer.js').AudioBuffer(nativeBinding.AudioBuffer);`
58
- - [x] Ended event in AudioScheduledSourceNode for offline audio context
59
-
60
- - cf. util.types.isSharedArrayBuffer(value)
61
-
62
- ## Notes
63
-
64
- - wpt/webaudio/the-audio-api/the-dynamicscompressornode-interface/dynamicscompressor-basic.html sometimes pass, sometimes fail because audio context is resumed
65
-
66
- ------------------------------------------------------------------------
67
-
68
- ## `onstatechnage` and `onsinkchange`
69
-
70
- ### https://webaudio.github.io/web-audio-api/#eventdef-baseaudiocontext-statechange
71
-
72
- > A newly-created AudioContext will always begin in the suspended state, and a state change event will be fired whenever the state changes to a different state. This event is fired before the complete event is fired.
73
-
74
- ### https://webaudio.github.io/web-audio-api/#dom-audiocontext-onsinkchange
75
-
76
- > NOTE: This is not dispatched for the initial device selection in the construction of AudioContext. The statechange event is available to check the readiness of the initial output device.
77
-
78
- cf. the-audiocontext-interface/audiocontext-sinkid-state-change.https.html
79
-
80
- ### Notes
81
-
82
- We should explicitly resume context at startup, just as a context created in a console or localhost
83
-
84
- What happens when sinkId is changed while context is suspended? It seems that it is resumed:
85
-
86
- ```rs
87
- Startup { graph } => {
88
- debug_assert!(self.graph.is_none());
89
- self.graph = Some(graph);
90
- self.set_state(AudioContextState::Running);
91
- }
92
- ```
93
-
94
- @todo - create a test bed
95
-
96
- - testing AudioContextOptions.sinkId requires this fix
97
- the-audiocontext-interface/audiocontext-sinkid-constructor.https.html
98
- - setting sink on supended audioContext test too
99
- the-audiocontext-interface/audiocontext-sinkid-state-change.https.html
100
-
101
- ------------------------------------------------------------------------
102
-
103
- ## Issue in spec / wpt
104
-
105
- - [ ] review waveshaper curve (need to be able to set back to null)
106
- <https://webaudio.github.io/web-audio-api/#dom-waveshapernode-curve>
107
- To set the curve attribute, execute these steps:
108
- - Let new curve be a Float32Array to be assigned to curve or null. .
109
- - If new curve is not null and [[curve set]] is true, throw an InvalidStateError and abort these steps.
110
- - If new curve is not null, set [[curve set]] to true.
111
- - Assign new curve to the curve attribute.
112
-
113
- -> Spec is not inline with wpt tests, both chrome and firefox accept setting curve several times (which makes sens...), without passing to null first
114
- -> Curve defined as sequence<float> in arguments but as Float32Array in attributes
115
- -> Means that we can't pass non finite values in ctor but we can with setter
116
-
117
- - [ ] AudioDestination::numberOfOutputs
118
- - implementation and wpt report 0
119
- cf. webaudio/the-audio-api/the-audionode-interface/audionode.html
120
- - spec specifies 1: https://webaudio.github.io/web-audio-api/#AudioDestinationNode
121
-
122
- - [ ] Analyser::fftSize
123
- - wpt defines that when set to -1 it should throw an IndexSizeError, when not a type error as it is defined as unsigned long?
124
- cf. the-analysernode-interface/realtimeanalyser-fft-sizing.html
125
- cf. https://webidl.spec.whatwg.org/#js-attributes
126
- setter step 4.6
127
- - same with getChannelData
128
-
129
- - [ ] wpt - propose patch to remove patch regarding `audiobuffersource-multi-channels-expected.wav`in XMLHttpRequest Mock
130
-
131
- - [ ] Propose a test for decodeAudioData
132
- "Let error be a DOMException whose name is EncodingError."
133
-
134
- - [ ] ScriptProcessorNode rehabilitation
135
- - padenot mail vs spec
136
-
137
- ------------------------------------------------------------------------
138
-
139
- ls wpt/webaudio/the-audio-api/the-audiocontext-interface | xargs -I {} ./run-wpt.sh {}
140
- ls wpt/webaudio/the-audio-api/the-dynamicscompressornode-interface | xargs -I {} ./run-wpt.sh {}
141
-
142
-
143
- 971
@@ -1,84 +0,0 @@
1
- // -------------------------------------------------------------------------- //
2
- // -------------------------------------------------------------------------- //
3
- // //
4
- // //
5
- // //
6
- // ██╗ ██╗ █████╗ ██████╗ ███╗ ██╗██╗███╗ ██╗ ██████╗ //
7
- // ██║ ██║██╔══██╗██╔══██╗████╗ ██║██║████╗ ██║██╔════╝ //
8
- // ██║ █╗ ██║███████║██████╔╝██╔██╗ ██║██║██╔██╗ ██║██║ ███╗ //
9
- // ██║███╗██║██╔══██║██╔══██╗██║╚██╗██║██║██║╚██╗██║██║ ██║ //
10
- // ╚███╔███╔╝██║ ██║██║ ██║██║ ╚████║██║██║ ╚████║╚██████╔╝ //
11
- // ╚══╝╚══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝╚═╝╚═╝ ╚═══╝ ╚═════╝ //
12
- // //
13
- // //
14
- // - This file has been generated --------------------------- //
15
- // //
16
- // //
17
- // -------------------------------------------------------------------------- //
18
- // -------------------------------------------------------------------------- //
19
-
20
- module.exports = function monkeyPatch(nativeBinding) {
21
- let jsExport = {};
22
-
23
- // --------------------------------------------------------------------------
24
- // Events
25
- // --------------------------------------------------------------------------
26
- jsExport.OfflineAudioCompletionEvent = require('./Events').OfflineAudioCompletionEvent;
27
- jsExport.AudioProcessingEvent = require('./Events').AudioProcessingEvent;
28
- // --------------------------------------------------------------------------
29
- // Create Web Audio API facade
30
- // --------------------------------------------------------------------------
31
- jsExport.BaseAudioContext = require('./BaseAudioContext.js')(jsExport, nativeBinding);
32
- jsExport.AudioContext = require('./AudioContext.js')(jsExport, nativeBinding);
33
- jsExport.OfflineAudioContext = require('./OfflineAudioContext.js')(jsExport, nativeBinding);
34
-
35
- jsExport.ScriptProcessorNode = require('./ScriptProcessorNode.js')(jsExport, nativeBinding);
36
- jsExport.AnalyserNode = require('./AnalyserNode.js')(jsExport, nativeBinding);
37
- jsExport.AudioBufferSourceNode = require('./AudioBufferSourceNode.js')(jsExport, nativeBinding);
38
- jsExport.BiquadFilterNode = require('./BiquadFilterNode.js')(jsExport, nativeBinding);
39
- jsExport.ChannelMergerNode = require('./ChannelMergerNode.js')(jsExport, nativeBinding);
40
- jsExport.ChannelSplitterNode = require('./ChannelSplitterNode.js')(jsExport, nativeBinding);
41
- jsExport.ConstantSourceNode = require('./ConstantSourceNode.js')(jsExport, nativeBinding);
42
- jsExport.ConvolverNode = require('./ConvolverNode.js')(jsExport, nativeBinding);
43
- jsExport.DelayNode = require('./DelayNode.js')(jsExport, nativeBinding);
44
- jsExport.DynamicsCompressorNode = require('./DynamicsCompressorNode.js')(jsExport, nativeBinding);
45
- jsExport.GainNode = require('./GainNode.js')(jsExport, nativeBinding);
46
- jsExport.IIRFilterNode = require('./IIRFilterNode.js')(jsExport, nativeBinding);
47
- jsExport.MediaStreamAudioSourceNode = require('./MediaStreamAudioSourceNode.js')(jsExport, nativeBinding);
48
- jsExport.OscillatorNode = require('./OscillatorNode.js')(jsExport, nativeBinding);
49
- jsExport.PannerNode = require('./PannerNode.js')(jsExport, nativeBinding);
50
- jsExport.StereoPannerNode = require('./StereoPannerNode.js')(jsExport, nativeBinding);
51
- jsExport.WaveShaperNode = require('./WaveShaperNode.js')(jsExport, nativeBinding);
52
-
53
- jsExport.AudioNode = require('./AudioNode.js');
54
- jsExport.AudioScheduledSourceNode = require('./AudioScheduledSourceNode.js');
55
- jsExport.AudioParam = require('./AudioParam.js');
56
- jsExport.AudioDestinationNode = require('./AudioDestinationNode.js');
57
- jsExport.AudioListener = require('./AudioListener.js');
58
-
59
- jsExport.PeriodicWave = require('./PeriodicWave.js')(jsExport, nativeBinding);
60
- jsExport.AudioBuffer = require('./AudioBuffer.js')(jsExport, nativeBinding);
61
-
62
- // --------------------------------------------------------------------------
63
- // Promisify MediaDevices API
64
- // --------------------------------------------------------------------------
65
- jsExport.mediaDevices = {};
66
-
67
- const enumerateDevicesSync = nativeBinding.mediaDevices.enumerateDevices;
68
- jsExport.mediaDevices.enumerateDevices = async function enumerateDevices() {
69
- const list = enumerateDevicesSync();
70
- return Promise.resolve(list);
71
- };
72
-
73
- const getUserMediaSync = nativeBinding.mediaDevices.getUserMedia;
74
- jsExport.mediaDevices.getUserMedia = async function getUserMedia(options) {
75
- if (options === undefined) {
76
- throw new TypeError('Failed to execute "getUserMedia" on "MediaDevices": audio must be requested');
77
- }
78
-
79
- const stream = getUserMediaSync(options);
80
- return Promise.resolve(stream);
81
- };
82
-
83
- return jsExport;
84
- };
package/run-wpt.md DELETED
@@ -1,27 +0,0 @@
1
- create file run-wpt.sh and chmod +x run-wpt.sh:
2
-
3
- ```
4
- #!/bin/bash
5
- echo $1
6
- echo ~~~~~~~~~~~~~~~~~
7
- node ./.scripts/wpt-harness.mjs --filter "$1" 2>&1 | grep -A 3 RESULTS
8
- echo
9
- ```
10
-
11
- dissect the full suite per directory:
12
-
13
- ```
14
- ls wpt/webaudio/the-audio-api | xargs -I {} ./run-wpt.sh {}
15
- ```
16
-
17
- check the specific file results in a dir:
18
-
19
- ```
20
- ls wpt/webaudio/the-audio-api/the-oscillatornode-interface | xargs -I {} ./run-wpt.sh {}
21
- ```
22
-
23
- ls wpt/webaudio/the-audio-api/the-audiocontext-interface | xargs -I {} ./run-wpt.sh {}
24
-
25
- processing-model
26
-
27
- ls wpt/webaudio/the-audio-api/processing-model | xargs -I {} ./run-wpt.sh {}
package/simple-test.cjs DELETED
@@ -1,20 +0,0 @@
1
- const { AudioContext, mediaDevices } = require('./index.cjs');
2
-
3
- const audioContext = new AudioContext();
4
-
5
- setInterval(() => {
6
- const now = audioContext.currentTime;
7
-
8
- const env = audioContext.createGain();
9
- env.connect(audioContext.destination);
10
- env.gain.value = 0;
11
- env.gain.setValueAtTime(0, now);
12
- env.gain.linearRampToValueAtTime(0.1, now + 0.02);
13
- env.gain.exponentialRampToValueAtTime(0.0001, now + 1);
14
-
15
- const osc = audioContext.createOscillator();
16
- osc.frequency.value = 200 + Math.random() * 2800;
17
- osc.connect(env);
18
- osc.start(now);
19
- osc.stop(now + 1);
20
- }, 100);
package/simple-test.mjs DELETED
@@ -1,20 +0,0 @@
1
- import { AudioContext, mediaDevices } from './index.mjs';
2
-
3
- const audioContext = new AudioContext();
4
-
5
- setInterval(() => {
6
- const now = audioContext.currentTime;
7
-
8
- const env = audioContext.createGain();
9
- env.connect(audioContext.destination);
10
- env.gain.value = 0;
11
- env.gain.setValueAtTime(0, now);
12
- env.gain.linearRampToValueAtTime(0.1, now + 0.02);
13
- env.gain.exponentialRampToValueAtTime(0.0001, now + 1);
14
-
15
- const osc = audioContext.createOscillator();
16
- osc.frequency.value = 200 + Math.random() * 2800;
17
- osc.connect(env);
18
- osc.start(now);
19
- osc.stop(now + 1);
20
- }, 100);