node-web-audio-api 0.14.0 → 0.16.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 (39) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +1 -1
  3. package/README.md +35 -17
  4. package/index.cjs +1 -1
  5. package/index.mjs +2 -1
  6. package/js/AnalyserNode.js +135 -0
  7. package/js/AudioBufferSourceNode.js +105 -0
  8. package/js/AudioContext.js +60 -0
  9. package/js/AudioNode.mixin.js +121 -0
  10. package/js/AudioParam.js +132 -0
  11. package/js/AudioScheduledSourceNode.mixin.js +67 -0
  12. package/js/BaseAudioContext.mixin.js +140 -0
  13. package/js/BiquadFilterNode.js +75 -0
  14. package/js/ChannelMergerNode.js +51 -0
  15. package/js/ChannelSplitterNode.js +51 -0
  16. package/js/ConstantSourceNode.js +56 -0
  17. package/js/ConvolverNode.js +75 -0
  18. package/js/DelayNode.js +52 -0
  19. package/js/DynamicsCompressorNode.js +60 -0
  20. package/js/EventTarget.mixin.js +59 -0
  21. package/js/GainNode.js +52 -0
  22. package/js/IIRFilterNode.js +59 -0
  23. package/js/OfflineAudioContext.js +45 -0
  24. package/js/OscillatorNode.js +77 -0
  25. package/js/PannerNode.js +169 -0
  26. package/js/StereoPannerNode.js +52 -0
  27. package/js/WaveShaperNode.js +75 -0
  28. package/js/lib/errors.js +108 -0
  29. package/js/lib/utils.js +16 -0
  30. package/js/monkey-patch.js +67 -0
  31. package/node-web-audio-api.darwin-arm64.node +0 -0
  32. package/node-web-audio-api.darwin-x64.node +0 -0
  33. package/node-web-audio-api.linux-arm-gnueabihf.node +0 -0
  34. package/node-web-audio-api.linux-arm64-gnu.node +0 -0
  35. package/node-web-audio-api.linux-x64-gnu.node +0 -0
  36. package/node-web-audio-api.win32-arm64-msvc.node +0 -0
  37. package/node-web-audio-api.win32-x64-msvc.node +0 -0
  38. package/package.json +10 -6
  39. package/monkey-patch.js +0 -184
package/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## v0.16.0 (09/02/2024)
2
+
3
+ - Update upstream create to [v0.42.0](https://github.com/orottier/web-audio-api-rs/blob/main/CHANGELOG.md#version-0420-2024-02-05)
4
+ - Improve Error handling
5
+ - Add channelCounnt to media constraints
6
+
7
+ ## v0.15.0 (16/01/2024)
8
+
9
+ - Update upstream create to [v0.41.1](https://github.com/orottier/web-audio-api-rs/blob/main/CHANGELOG.md#version-0411-2024-01-11)
10
+ - Better error handling
11
+ - Implement online AudioContext and AudioScheduledSourceNode events
12
+ - Test against wpt
13
+
1
14
  ## v0.14.0 (06/12/2023)
2
15
 
3
16
  - Update upstream create to [v0.38.0](https://github.com/orottier/web-audio-api-rs/blob/main/CHANGELOG.md#version-0380-2023-12-03)
package/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2021-2022 IRCAM – Centre Pompidou (France, Paris)
1
+ Copyright (c) 2021-present IRCAM – Centre Pompidou (France, Paris)
2
2
 
3
3
  All rights reserved.
4
4
 
package/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/node-web-audio-api.svg)](https://badge.fury.io/js/node-web-audio-api)
4
4
 
5
- Node.js bindings for the Rust implementation of the Web Audio API Specification
5
+ Node.js bindings for the Rust implementation of the [Web Audio API](https://www.w3.org/TR/webaudio/).
6
6
 
7
- The goal of this library is to provide an implementation that is both efficient and _exactly_ matches the browsers' API.
7
+ This library aims to provide an implementation that is both efficient and compliant with the specification.
8
8
 
9
9
  - see [`orottier/web-audio-api-rs`](https://github.com/orottier/web-audio-api-rs/) for the "real" audio guts
10
10
  - use [`napi-rs`](https://github.com/napi-rs/napi-rs/) for the Node.js bindings
@@ -19,23 +19,22 @@ npm install [--save] node-web-audio-api
19
19
 
20
20
  ```js
21
21
  import { AudioContext, OscillatorNode, GainNode } from 'node-web-audio-api';
22
- // or using old fashionned commonjs syntax:
22
+ // or using old fashioned commonjs syntax:
23
23
  // const { AudioContext, OscillatorNode, GainNode } = require('node-web-audio-api');
24
-
25
24
  const audioContext = new AudioContext();
26
25
 
27
26
  setInterval(() => {
28
27
  const now = audioContext.currentTime;
28
+ const frequency = 200 + Math.random() * 2800;
29
29
 
30
- const env = new GainNode(audioContext);
30
+ const env = new GainNode(audioContext, { gain: 0 });
31
31
  env.connect(audioContext.destination);
32
- env.gain.value = 0;
33
- env.gain.setValueAtTime(0, now);
34
- env.gain.linearRampToValueAtTime(1, now + 0.02);
35
- env.gain.exponentialRampToValueAtTime(0.0001, now + 1);
32
+ env.gain
33
+ .setValueAtTime(0, now)
34
+ .linearRampToValueAtTime(0.2, now + 0.02)
35
+ .exponentialRampToValueAtTime(0.0001, now + 1);
36
36
 
37
- const osc = new OscillatorNode(audioContext);
38
- osc.frequency.value = 200 + Math.random() * 2800;
37
+ const osc = new OscillatorNode(audioContext, { frequency });
39
38
  osc.connect(env);
40
39
  osc.start(now);
41
40
  osc.stop(now + 1);
@@ -66,8 +65,9 @@ node examples/granular-scrub.mjs
66
65
 
67
66
  ## Caveats
68
67
 
69
- - The async methods are not trully async for now and are just patched on the JS side. This will evolve once the "trully" async version of the methods are implemented in the upstream library.
70
- - On Raspberry Pi, the `Linux arm gnueabihf` binary provided only works on 32bit OS. We will provide a version for the 64 bit OS in the future.
68
+ - Missing nodes: `ScriptProcessorNode`, `AudioWorkletNode`.
69
+ - Streams: only a minimial audio input stream and the `MediaStreamSourceNode` are provided. All other `MediaStream` features are left on the side for now as they principaly concern a different API specification, which is not a trivial problem.
70
+ - Some async methods (e.g. `decodeAudioData`, `setSinkId`) are not trully async yet. This will evolve with the implemetation of the async version in the upstream crate.
71
71
 
72
72
  ## Supported Platforms
73
73
 
@@ -76,7 +76,7 @@ node examples/granular-scrub.mjs
76
76
  | Windows x64 | ✓ | |
77
77
  | Windows arm64 | ✓ | |
78
78
  | macOS x64 | ✓ | ✓ |
79
- | macOS aarch64 | ✓ | |
79
+ | macOS aarch64 | ✓ ||
80
80
  | Linux x64 gnu | ✓ | |
81
81
  | Linux arm gnueabihf (RPi) | ✓ | ✓ |
82
82
  | Linux arm64 gnu (RPi) | ✓ | ✓ |
@@ -90,14 +90,14 @@ Using the library on Linux with the ALSA backend might lead to unexpected cranky
90
90
  const audioContext = new AudioContext({ latencyHint: 'playback' });
91
91
  ```
92
92
 
93
- You can pass the `WEB_AUDIO_LATENCY=playback` env variable to all examples to create the audio context with the playback latency hint, e.g.:
93
+ For real-time and interactive applications where low latency is crucial, you should instead rely on the JACK backend provided by `cpal`. By default the audio context will use that backend if a running JACK server is found.
94
+
95
+ If you don't have JACK installed, you can still pass the `WEB_AUDIO_LATENCY=playback` env variable to all examples to create the audio context with the playback latency hint, e.g.:
94
96
 
95
97
  ```sh
96
98
  WEB_AUDIO_LATENCY=playback node examples/amplitude-modulation.mjs
97
99
  ```
98
100
 
99
- For real-time and interactive applications where low latency is crucial, you should instead rely on the JACK backend provided by `cpal`. By default the audio context will use that backend if a running JACK server is found.
100
-
101
101
  ### Manual Build
102
102
 
103
103
  If prebuilt binaries are not shippped for your platform, you will need to:
@@ -129,6 +129,24 @@ The npm `postversion` script rely on [`cargo-bump`](https://crates.io/crates/car
129
129
  cargo install cargo-bump
130
130
  ```
131
131
 
132
+ ## Running the web-platform-test suite
133
+
134
+ Follow the steps for 'Manual Build' first. Then checkout the web-platform-tests submodule with:
135
+
136
+ ```
137
+ git submodule init
138
+ git submodule update
139
+ ```
140
+
141
+ Then run:
142
+
143
+ ```
144
+ npm run wpt # build in debug mode and run all wpt test
145
+ npm run wpt:only # run all wpt test without build
146
+ npm run wpt -- --list # list all wpt test files
147
+ npm run wpt -- --filter <string> # apply <string> filter on executed/listed wpt tests
148
+ ```
149
+
132
150
  ## License
133
151
 
134
152
  [BSD-3-Clause](./LICENSE)
package/index.cjs CHANGED
@@ -83,7 +83,7 @@ if (!nativeBinding) {
83
83
  throw new Error(`Failed to load native binding for OS: ${platform}, architecture: ${arch}`);
84
84
  }
85
85
 
86
- const monkeyPatch = require('./monkey-patch.js');
86
+ const monkeyPatch = require('./js/monkey-patch.js');
87
87
  nativeBinding = monkeyPatch(nativeBinding);
88
88
 
89
89
  module.exports = nativeBinding;
package/index.mjs CHANGED
@@ -17,7 +17,7 @@
17
17
  // -------------------------------------------------------------------------- //
18
18
  // -------------------------------------------------------------------------- //
19
19
 
20
- // re-export index.js to support clean esm syntax
20
+ // re-export index.cjs to support esm import syntax
21
21
  // see https://github.com/nodejs/node/issues/40541#issuecomment-951609570
22
22
 
23
23
  import { createRequire } from 'module';
@@ -54,4 +54,5 @@ export const {
54
54
 
55
55
  export default nativeModule;
56
56
 
57
+
57
58
 
@@ -0,0 +1,135 @@
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
+ // eslint-disable-next-line no-unused-vars
21
+ const { throwSanitizedError } = require('./lib/errors.js');
22
+ // eslint-disable-next-line no-unused-vars
23
+ const { AudioParam } = require('./AudioParam.js');
24
+ const EventTargetMixin = require('./EventTarget.mixin.js');
25
+ const AudioNodeMixin = require('./AudioNode.mixin.js');
26
+
27
+
28
+ module.exports = (NativeAnalyserNode) => {
29
+
30
+ const EventTarget = EventTargetMixin(NativeAnalyserNode);
31
+ const AudioNode = AudioNodeMixin(EventTarget);
32
+
33
+ class AnalyserNode extends AudioNode {
34
+ constructor(context, options) {
35
+ super(context, options);
36
+
37
+ }
38
+
39
+ // getters
40
+
41
+ get fftSize() {
42
+ return super.fftSize;
43
+ }
44
+
45
+ get frequencyBinCount() {
46
+ return super.frequencyBinCount;
47
+ }
48
+
49
+ get minDecibels() {
50
+ return super.minDecibels;
51
+ }
52
+
53
+ get maxDecibels() {
54
+ return super.maxDecibels;
55
+ }
56
+
57
+ get smoothingTimeConstant() {
58
+ return super.smoothingTimeConstant;
59
+ }
60
+
61
+ // setters
62
+
63
+ set fftSize(value) {
64
+ try {
65
+ super.fftSize = value;
66
+ } catch (err) {
67
+ throwSanitizedError(err);
68
+ }
69
+ }
70
+
71
+ set minDecibels(value) {
72
+ try {
73
+ super.minDecibels = value;
74
+ } catch (err) {
75
+ throwSanitizedError(err);
76
+ }
77
+ }
78
+
79
+ set maxDecibels(value) {
80
+ try {
81
+ super.maxDecibels = value;
82
+ } catch (err) {
83
+ throwSanitizedError(err);
84
+ }
85
+ }
86
+
87
+ set smoothingTimeConstant(value) {
88
+ try {
89
+ super.smoothingTimeConstant = value;
90
+ } catch (err) {
91
+ throwSanitizedError(err);
92
+ }
93
+ }
94
+
95
+ // methods
96
+
97
+ getFloatFrequencyData(...args) {
98
+ try {
99
+ return super.getFloatFrequencyData(...args);
100
+ } catch (err) {
101
+ throwSanitizedError(err);
102
+ }
103
+ }
104
+
105
+ getByteFrequencyData(...args) {
106
+ try {
107
+ return super.getByteFrequencyData(...args);
108
+ } catch (err) {
109
+ throwSanitizedError(err);
110
+ }
111
+ }
112
+
113
+ getFloatTimeDomainData(...args) {
114
+ try {
115
+ return super.getFloatTimeDomainData(...args);
116
+ } catch (err) {
117
+ throwSanitizedError(err);
118
+ }
119
+ }
120
+
121
+ getByteTimeDomainData(...args) {
122
+ try {
123
+ return super.getByteTimeDomainData(...args);
124
+ } catch (err) {
125
+ throwSanitizedError(err);
126
+ }
127
+ }
128
+
129
+ }
130
+
131
+ return AnalyserNode;
132
+ };
133
+
134
+
135
+
@@ -0,0 +1,105 @@
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
+ // eslint-disable-next-line no-unused-vars
21
+ const { throwSanitizedError } = require('./lib/errors.js');
22
+ // eslint-disable-next-line no-unused-vars
23
+ const { AudioParam } = require('./AudioParam.js');
24
+ const EventTargetMixin = require('./EventTarget.mixin.js');
25
+ const AudioNodeMixin = require('./AudioNode.mixin.js');
26
+ const AudioScheduledSourceNodeMixin = require('./AudioScheduledSourceNode.mixin.js');
27
+
28
+ module.exports = (NativeAudioBufferSourceNode) => {
29
+
30
+ const EventTarget = EventTargetMixin(NativeAudioBufferSourceNode, ['ended']);
31
+ const AudioNode = AudioNodeMixin(EventTarget);
32
+ const AudioScheduledSourceNode = AudioScheduledSourceNodeMixin(AudioNode);
33
+
34
+ class AudioBufferSourceNode extends AudioScheduledSourceNode {
35
+ constructor(context, options) {
36
+ super(context, options);
37
+ // EventTargetMixin has been called so EventTargetMixin[kDispatchEvent] is
38
+ // bound to this, then we can safely finalize event target initialization
39
+ super.__initEventTarget__();
40
+
41
+ this.playbackRate = new AudioParam(this.playbackRate);
42
+ this.detune = new AudioParam(this.detune);
43
+ }
44
+
45
+ // getters
46
+
47
+ get buffer() {
48
+ return super.buffer;
49
+ }
50
+
51
+ get loop() {
52
+ return super.loop;
53
+ }
54
+
55
+ get loopStart() {
56
+ return super.loopStart;
57
+ }
58
+
59
+ get loopEnd() {
60
+ return super.loopEnd;
61
+ }
62
+
63
+ // setters
64
+
65
+ set buffer(value) {
66
+ try {
67
+ super.buffer = value;
68
+ } catch (err) {
69
+ throwSanitizedError(err);
70
+ }
71
+ }
72
+
73
+ set loop(value) {
74
+ try {
75
+ super.loop = value;
76
+ } catch (err) {
77
+ throwSanitizedError(err);
78
+ }
79
+ }
80
+
81
+ set loopStart(value) {
82
+ try {
83
+ super.loopStart = value;
84
+ } catch (err) {
85
+ throwSanitizedError(err);
86
+ }
87
+ }
88
+
89
+ set loopEnd(value) {
90
+ try {
91
+ super.loopEnd = value;
92
+ } catch (err) {
93
+ throwSanitizedError(err);
94
+ }
95
+ }
96
+
97
+ // methods
98
+
99
+ }
100
+
101
+ return AudioBufferSourceNode;
102
+ };
103
+
104
+
105
+
@@ -0,0 +1,60 @@
1
+ let contextId = 0;
2
+
3
+ const kProcessId = Symbol('processId');
4
+ const kKeepAwakeId = Symbol('keepAwakeId');
5
+
6
+ module.exports = function(bindings) {
7
+ const {
8
+ MediaStreamAudioSourceNode,
9
+ } = bindings;
10
+
11
+ const EventTarget = require('./EventTarget.mixin.js')(bindings.AudioContext, ['statechange', 'sinkchange']);
12
+ const BaseAudioContext = require('./BaseAudioContext.mixin.js')(EventTarget, bindings);
13
+
14
+ class AudioContext extends BaseAudioContext {
15
+ // class AudioContext extends NativeAudioContext {
16
+ constructor(options = {}) {
17
+ super(options);
18
+ // EventTargetMixin has been called so EventTargetMixin[kDispatchEvent] is
19
+ // bound to this, then we can safely finalize event target initialization
20
+ super.__initEventTarget__();
21
+
22
+ // prevent garbage collection and process exit
23
+ const id = contextId++;
24
+ // store in process to prevent garbage collection
25
+ const processId = Symbol(`__AudioContext_${id}`);
26
+ process[processId] = this;
27
+ // keep process symbol around to delete later
28
+ this[kProcessId] = processId;
29
+ // keep process awake until context is closed
30
+ const keepAwakeId = setInterval(() => {}, 10 * 1000);
31
+ this[kKeepAwakeId] = keepAwakeId;
32
+
33
+ // clear on close
34
+ this.addEventListener('statechange', () => {
35
+ if (this.state === 'closed') {
36
+ // allow to garbage collect the context and to the close the process
37
+ delete process[this[kProcessId]];
38
+ clearTimeout(this[kKeepAwakeId]);
39
+ }
40
+ });
41
+ }
42
+
43
+ setSinkId(sinkId) {
44
+ try {
45
+ super.setSinkId(sinkId);
46
+ return Promise.resolve(undefined);
47
+ } catch (err) {
48
+ return Promise.reject(err);
49
+ }
50
+ }
51
+
52
+ // online context only AudioNodes
53
+ createMediaStreamSource(mediaStream) {
54
+ const options = { mediaStream };
55
+ return new MediaStreamAudioSourceNode(this, options);
56
+ }
57
+ }
58
+
59
+ return AudioContext;
60
+ };
@@ -0,0 +1,121 @@
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
+ const { throwSanitizedError } = require('./lib/errors.js');
21
+
22
+ const { AudioParam, kNativeAudioParam } = require('./AudioParam.js');
23
+
24
+ module.exports = (superclass) => {
25
+ class AudioNode extends superclass {
26
+ /* eslint-disable constructor-super */
27
+ constructor(...args) {
28
+ try {
29
+ super(...args);
30
+ } catch (err) {
31
+ throwSanitizedError(err);
32
+ }
33
+ }
34
+ /* eslint-enable constructor-super */
35
+
36
+ // getters
37
+
38
+ get context() {
39
+ return super.context;
40
+ }
41
+
42
+ get numberOfInputs() {
43
+ return super.numberOfInputs;
44
+ }
45
+
46
+ get numberOfOutputs() {
47
+ return super.numberOfOutputs;
48
+ }
49
+
50
+ get channelCount() {
51
+ return super.channelCount;
52
+ }
53
+
54
+ get channelCountMode() {
55
+ return super.channelCountMode;
56
+ }
57
+
58
+ get channelInterpretation() {
59
+ return super.channelInterpretation;
60
+ }
61
+
62
+ // setters
63
+
64
+ set channelCount(value) {
65
+ try {
66
+ super.channelCount = value;
67
+ } catch (err) {
68
+ throwSanitizedError(err);
69
+ }
70
+ }
71
+
72
+ set channelCountMode(value) {
73
+ try {
74
+ super.channelCountMode = value;
75
+ } catch (err) {
76
+ throwSanitizedError(err);
77
+ }
78
+ }
79
+
80
+ set channelInterpretation(value) {
81
+ try {
82
+ super.channelInterpretation = value;
83
+ } catch (err) {
84
+ throwSanitizedError(err);
85
+ }
86
+ }
87
+
88
+ // methods - connect / disconnect
89
+
90
+ connect(...args) {
91
+ // unwrap raw audio params from facade
92
+ if (args[0] instanceof AudioParam) {
93
+ args[0] = args[0][kNativeAudioParam];
94
+ }
95
+
96
+ try {
97
+ return super.connect(...args);
98
+ } catch (err) {
99
+ throwSanitizedError(err);
100
+ }
101
+ }
102
+
103
+ disconnect(...args) {
104
+ // unwrap raw audio params from facade
105
+ if (args[0] instanceof AudioParam) {
106
+ args[0] = args[0][kNativeAudioParam];
107
+ }
108
+
109
+ try {
110
+ return super.disconnect(...args);
111
+ } catch (err) {
112
+ throwSanitizedError(err);
113
+ }
114
+ }
115
+
116
+ }
117
+
118
+ return AudioNode;
119
+ };
120
+
121
+