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.
- package/CHANGELOG.md +7 -0
- package/TODOS.md +140 -12
- package/index.mjs +10 -5
- package/js/AnalyserNode.js +262 -48
- package/js/AudioBuffer.js +244 -0
- package/js/AudioBufferSourceNode.js +265 -41
- package/js/AudioContext.js +271 -28
- package/js/AudioDestinationNode.js +42 -100
- package/js/AudioListener.js +219 -0
- package/js/AudioNode.js +323 -0
- package/js/AudioParam.js +252 -39
- package/js/AudioScheduledSourceNode.js +105 -0
- package/js/BaseAudioContext.js +419 -0
- package/js/BiquadFilterNode.js +221 -29
- package/js/ChannelMergerNode.js +96 -22
- package/js/ChannelSplitterNode.js +96 -22
- package/js/ConstantSourceNode.js +92 -26
- package/js/ConvolverNode.js +161 -29
- package/js/DelayNode.js +115 -21
- package/js/DynamicsCompressorNode.js +198 -27
- package/js/GainNode.js +107 -21
- package/js/IIRFilterNode.js +139 -23
- package/js/MediaStreamAudioSourceNode.js +83 -24
- package/js/OfflineAudioContext.js +182 -34
- package/js/OscillatorNode.js +195 -32
- package/js/PannerNode.js +461 -56
- package/js/PeriodicWave.js +67 -3
- package/js/StereoPannerNode.js +107 -21
- package/js/WaveShaperNode.js +147 -29
- package/js/lib/cast.js +19 -0
- package/js/lib/errors.js +10 -55
- package/js/lib/events.js +20 -0
- package/js/lib/symbols.js +5 -0
- package/js/lib/utils.js +12 -12
- package/js/monkey-patch.js +32 -30
- package/node-web-audio-api.darwin-arm64.node +0 -0
- package/node-web-audio-api.darwin-x64.node +0 -0
- package/node-web-audio-api.linux-arm-gnueabihf.node +0 -0
- package/node-web-audio-api.linux-arm64-gnu.node +0 -0
- package/node-web-audio-api.linux-x64-gnu.node +0 -0
- package/node-web-audio-api.win32-arm64-msvc.node +0 -0
- package/node-web-audio-api.win32-x64-msvc.node +0 -0
- package/package.json +7 -4
- package/run-wpt.md +27 -0
- package/run-wpt.sh +5 -0
- package/js/AudioNode.mixin.js +0 -132
- package/js/AudioScheduledSourceNode.mixin.js +0 -67
- package/js/BaseAudioContext.mixin.js +0 -154
- package/js/EventTarget.mixin.js +0 -60
package/js/PeriodicWave.js
CHANGED
|
@@ -1,16 +1,80 @@
|
|
|
1
|
+
const conversions = require('webidl-conversions');
|
|
2
|
+
|
|
1
3
|
const { throwSanitizedError } = require('./lib/errors.js');
|
|
4
|
+
const { toSanitizedSequence } = require('./lib/cast.js');
|
|
5
|
+
const { kNapiObj } = require('./lib/symbols.js');
|
|
6
|
+
const { kHiddenProperty } = require('./lib/utils.js');
|
|
2
7
|
|
|
3
|
-
module.exports = (
|
|
4
|
-
class PeriodicWave
|
|
8
|
+
module.exports = (jsExport, nativeBinding) => {
|
|
9
|
+
class PeriodicWave {
|
|
5
10
|
constructor(context, options) {
|
|
11
|
+
if (arguments.length < 1) {
|
|
12
|
+
throw new TypeError(`Failed to construct 'PeriodicWave': 1 argument required, but only ${arguments.length} present`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!(context instanceof jsExport.BaseAudioContext)) {
|
|
16
|
+
throw new TypeError(`Failed to construct 'PeriodicWave': argument 1 is not of type BaseAudioContext`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const parsedOptions = {};
|
|
20
|
+
|
|
21
|
+
if (options && 'real' in options) {
|
|
22
|
+
try {
|
|
23
|
+
parsedOptions.real = toSanitizedSequence(options.real, Float32Array);
|
|
24
|
+
} catch (err) {
|
|
25
|
+
throw new TypeError(`Failed to construct 'PeriodicWave': Failed to read the 'real' property from PeriodicWaveOptions: The provided value ${err.message}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (options && 'imag' in options) {
|
|
30
|
+
try {
|
|
31
|
+
parsedOptions.imag = toSanitizedSequence(options.imag, Float32Array);
|
|
32
|
+
} catch (err) {
|
|
33
|
+
throw new TypeError(`Failed to construct 'PeriodicWave': Failed to read the 'imag' property from PeriodicWaveOptions: The provided value ${err.message}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// disableNormalization = false
|
|
38
|
+
if (options && 'disableNormalization' in options) {
|
|
39
|
+
parsedOptions.disableNormalization = conversions['boolean'](options.disableNormalization, {
|
|
40
|
+
context: `Failed to construct 'PeriodicWave': Failed to read the 'imag' property from PeriodicWaveOptions: The provided value`,
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
parsedOptions.disableNormalization;
|
|
44
|
+
}
|
|
45
|
+
|
|
6
46
|
try {
|
|
7
|
-
|
|
47
|
+
const napiObj = new nativeBinding.PeriodicWave(context[kNapiObj], parsedOptions);
|
|
48
|
+
Object.defineProperty(this, kNapiObj, {
|
|
49
|
+
value: napiObj,
|
|
50
|
+
...kHiddenProperty,
|
|
51
|
+
});
|
|
8
52
|
} catch (err) {
|
|
9
53
|
throwSanitizedError(err);
|
|
10
54
|
}
|
|
11
55
|
}
|
|
12
56
|
}
|
|
13
57
|
|
|
58
|
+
Object.defineProperties(PeriodicWave, {
|
|
59
|
+
length: {
|
|
60
|
+
__proto__: null,
|
|
61
|
+
writable: false,
|
|
62
|
+
enumerable: false,
|
|
63
|
+
configurable: true,
|
|
64
|
+
value: 1,
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
Object.defineProperties(PeriodicWave.prototype, {
|
|
69
|
+
[Symbol.toStringTag]: {
|
|
70
|
+
__proto__: null,
|
|
71
|
+
writable: false,
|
|
72
|
+
enumerable: false,
|
|
73
|
+
configurable: true,
|
|
74
|
+
value: 'PeriodicWave',
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
14
78
|
return PeriodicWave;
|
|
15
79
|
};
|
|
16
80
|
|
package/js/StereoPannerNode.js
CHANGED
|
@@ -17,40 +17,126 @@
|
|
|
17
17
|
// -------------------------------------------------------------------------- //
|
|
18
18
|
// -------------------------------------------------------------------------- //
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
20
|
+
/* eslint-disable no-unused-vars */
|
|
21
|
+
const conversions = require('webidl-conversions');
|
|
22
|
+
const {
|
|
23
|
+
toSanitizedSequence,
|
|
24
|
+
} = require('./lib/cast.js');
|
|
25
|
+
const {
|
|
26
|
+
isFunction,
|
|
27
|
+
kEnumerableProperty,
|
|
28
|
+
} = require('./lib/utils.js');
|
|
29
|
+
const {
|
|
30
|
+
throwSanitizedError,
|
|
31
|
+
} = require('./lib/errors.js');
|
|
32
|
+
const {
|
|
33
|
+
kNapiObj,
|
|
34
|
+
kAudioBuffer,
|
|
35
|
+
} = require('./lib/symbols.js');
|
|
36
|
+
const {
|
|
37
|
+
bridgeEventTarget,
|
|
38
|
+
} = require('./lib/events.js');
|
|
39
|
+
/* eslint-enable no-unused-vars */
|
|
26
40
|
|
|
41
|
+
const AudioNode = require('./AudioNode.js');
|
|
27
42
|
|
|
28
|
-
module.exports = (
|
|
43
|
+
module.exports = (jsExport, nativeBinding) => {
|
|
44
|
+
class StereoPannerNode extends AudioNode {
|
|
29
45
|
|
|
30
|
-
|
|
31
|
-
const AudioNode = AudioNodeMixin(EventTarget);
|
|
46
|
+
#pan = null;
|
|
32
47
|
|
|
33
|
-
class StereoPannerNode extends AudioNode {
|
|
34
48
|
constructor(context, options) {
|
|
35
|
-
|
|
36
|
-
|
|
49
|
+
|
|
50
|
+
if (arguments.length < 1) {
|
|
51
|
+
throw new TypeError(`Failed to construct 'StereoPannerNode': 1 argument required, but only ${arguments.length} present`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (!(context instanceof jsExport.BaseAudioContext)) {
|
|
55
|
+
throw new TypeError(`Failed to construct 'StereoPannerNode': argument 1 is not of type BaseAudioContext`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// parsed version of the option to be passed to NAPI
|
|
59
|
+
const parsedOptions = {};
|
|
60
|
+
|
|
61
|
+
if (options && typeof options !== 'object') {
|
|
62
|
+
throw new TypeError('Failed to construct \'StereoPannerNode\': argument 2 is not of type \'StereoPannerOptions\'');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (options && options.pan !== undefined) {
|
|
66
|
+
parsedOptions.pan = conversions['float'](options.pan, {
|
|
67
|
+
context: `Failed to construct 'StereoPannerNode': Failed to read the 'pan' property from StereoPannerOptions: The provided value (${options.pan}})`,
|
|
68
|
+
});
|
|
69
|
+
} else {
|
|
70
|
+
parsedOptions.pan = 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (options && options.channelCount !== undefined) {
|
|
74
|
+
parsedOptions.channelCount = conversions['unsigned long'](options.channelCount, {
|
|
75
|
+
enforceRange: true,
|
|
76
|
+
context: `Failed to construct 'StereoPannerNode': Failed to read the 'channelCount' property from StereoPannerOptions: The provided value '${options.channelCount}'`,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (options && options.channelCountMode !== undefined) {
|
|
81
|
+
parsedOptions.channelCountMode = conversions['DOMString'](options.channelCountMode, {
|
|
82
|
+
context: `Failed to construct 'StereoPannerNode': Failed to read the 'channelCount' property from StereoPannerOptions: The provided value '${options.channelCountMode}'`,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (options && options.channelInterpretation !== undefined) {
|
|
87
|
+
parsedOptions.channelInterpretation = conversions['DOMString'](options.channelInterpretation, {
|
|
88
|
+
context: `Failed to construct 'StereoPannerNode': Failed to read the 'channelInterpretation' property from StereoPannerOptions: The provided value '${options.channelInterpretation}'`,
|
|
89
|
+
});
|
|
37
90
|
}
|
|
38
91
|
|
|
39
|
-
|
|
92
|
+
let napiObj;
|
|
40
93
|
|
|
41
|
-
|
|
94
|
+
try {
|
|
95
|
+
napiObj = new nativeBinding.StereoPannerNode(context[kNapiObj], parsedOptions);
|
|
96
|
+
} catch (err) {
|
|
97
|
+
throwSanitizedError(err);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
super(context, {
|
|
101
|
+
[kNapiObj]: napiObj,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
this.#pan = new jsExport.AudioParam({
|
|
105
|
+
[kNapiObj]: this[kNapiObj].pan,
|
|
106
|
+
});
|
|
42
107
|
}
|
|
43
108
|
|
|
44
|
-
|
|
109
|
+
get pan() {
|
|
110
|
+
if (!(this instanceof StereoPannerNode)) {
|
|
111
|
+
throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'StereoPannerNode\'');
|
|
112
|
+
}
|
|
45
113
|
|
|
46
|
-
|
|
114
|
+
return this.#pan;
|
|
115
|
+
}
|
|
47
116
|
|
|
48
|
-
// methods
|
|
49
|
-
|
|
50
117
|
}
|
|
51
118
|
|
|
52
|
-
|
|
53
|
-
|
|
119
|
+
Object.defineProperties(StereoPannerNode, {
|
|
120
|
+
length: {
|
|
121
|
+
__proto__: null,
|
|
122
|
+
writable: false,
|
|
123
|
+
enumerable: false,
|
|
124
|
+
configurable: true,
|
|
125
|
+
value: 1,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
54
128
|
|
|
129
|
+
Object.defineProperties(StereoPannerNode.prototype, {
|
|
130
|
+
[Symbol.toStringTag]: {
|
|
131
|
+
__proto__: null,
|
|
132
|
+
writable: false,
|
|
133
|
+
enumerable: false,
|
|
134
|
+
configurable: true,
|
|
135
|
+
value: 'StereoPannerNode',
|
|
136
|
+
},
|
|
137
|
+
pan: kEnumerableProperty,
|
|
55
138
|
|
|
56
|
-
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
return StereoPannerNode;
|
|
142
|
+
};
|
package/js/WaveShaperNode.js
CHANGED
|
@@ -17,63 +17,181 @@
|
|
|
17
17
|
// -------------------------------------------------------------------------- //
|
|
18
18
|
// -------------------------------------------------------------------------- //
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
20
|
+
/* eslint-disable no-unused-vars */
|
|
21
|
+
const conversions = require('webidl-conversions');
|
|
22
|
+
const {
|
|
23
|
+
toSanitizedSequence,
|
|
24
|
+
} = require('./lib/cast.js');
|
|
25
|
+
const {
|
|
26
|
+
isFunction,
|
|
27
|
+
kEnumerableProperty,
|
|
28
|
+
} = require('./lib/utils.js');
|
|
29
|
+
const {
|
|
30
|
+
throwSanitizedError,
|
|
31
|
+
} = require('./lib/errors.js');
|
|
32
|
+
const {
|
|
33
|
+
kNapiObj,
|
|
34
|
+
kAudioBuffer,
|
|
35
|
+
} = require('./lib/symbols.js');
|
|
36
|
+
const {
|
|
37
|
+
bridgeEventTarget,
|
|
38
|
+
} = require('./lib/events.js');
|
|
39
|
+
/* eslint-enable no-unused-vars */
|
|
40
|
+
|
|
41
|
+
const AudioNode = require('./AudioNode.js');
|
|
42
|
+
|
|
43
|
+
module.exports = (jsExport, nativeBinding) => {
|
|
44
|
+
class WaveShaperNode extends AudioNode {
|
|
26
45
|
|
|
46
|
+
constructor(context, options) {
|
|
27
47
|
|
|
28
|
-
|
|
48
|
+
if (arguments.length < 1) {
|
|
49
|
+
throw new TypeError(`Failed to construct 'WaveShaperNode': 1 argument required, but only ${arguments.length} present`);
|
|
50
|
+
}
|
|
29
51
|
|
|
30
|
-
|
|
31
|
-
|
|
52
|
+
if (!(context instanceof jsExport.BaseAudioContext)) {
|
|
53
|
+
throw new TypeError(`Failed to construct 'WaveShaperNode': argument 1 is not of type BaseAudioContext`);
|
|
54
|
+
}
|
|
32
55
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
56
|
+
// parsed version of the option to be passed to NAPI
|
|
57
|
+
const parsedOptions = {};
|
|
58
|
+
|
|
59
|
+
if (options && typeof options !== 'object') {
|
|
60
|
+
throw new TypeError('Failed to construct \'WaveShaperNode\': argument 2 is not of type \'WaveShaperOptions\'');
|
|
37
61
|
}
|
|
38
62
|
|
|
39
|
-
|
|
63
|
+
if (options && options.curve !== undefined) {
|
|
64
|
+
try {
|
|
65
|
+
parsedOptions.curve = toSanitizedSequence(options.curve, Float32Array);
|
|
66
|
+
} catch (err) {
|
|
67
|
+
throw new TypeError(`Failed to construct 'WaveShaperNode': Failed to read the 'curve' property from WaveShaperOptions: The provided value ${err.message}`);
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
parsedOptions.curve = null;
|
|
71
|
+
}
|
|
40
72
|
|
|
41
|
-
|
|
73
|
+
if (options && options.oversample !== undefined) {
|
|
74
|
+
if (!['none', '2x', '4x'].includes(options.oversample)) {
|
|
75
|
+
throw new TypeError(`Failed to construct 'WaveShaperNode': Failed to read the 'oversample' property from WaveShaperOptions: The provided value '${options.oversample}' is not a valid enum value of type OverSampleType`);
|
|
76
|
+
}
|
|
42
77
|
|
|
43
|
-
|
|
78
|
+
parsedOptions.oversample = conversions['DOMString'](options.oversample, {
|
|
79
|
+
context: `Failed to construct 'WaveShaperNode': Failed to read the 'oversample' property from WaveShaperOptions: The provided value '${options.oversample}'`,
|
|
80
|
+
});
|
|
81
|
+
} else {
|
|
82
|
+
parsedOptions.oversample = 'none';
|
|
83
|
+
}
|
|
44
84
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
85
|
+
if (options && options.channelCount !== undefined) {
|
|
86
|
+
parsedOptions.channelCount = conversions['unsigned long'](options.channelCount, {
|
|
87
|
+
enforceRange: true,
|
|
88
|
+
context: `Failed to construct 'WaveShaperNode': Failed to read the 'channelCount' property from WaveShaperOptions: The provided value '${options.channelCount}'`,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (options && options.channelCountMode !== undefined) {
|
|
93
|
+
parsedOptions.channelCountMode = conversions['DOMString'](options.channelCountMode, {
|
|
94
|
+
context: `Failed to construct 'WaveShaperNode': Failed to read the 'channelCount' property from WaveShaperOptions: The provided value '${options.channelCountMode}'`,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (options && options.channelInterpretation !== undefined) {
|
|
99
|
+
parsedOptions.channelInterpretation = conversions['DOMString'](options.channelInterpretation, {
|
|
100
|
+
context: `Failed to construct 'WaveShaperNode': Failed to read the 'channelInterpretation' property from WaveShaperOptions: The provided value '${options.channelInterpretation}'`,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let napiObj;
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
napiObj = new nativeBinding.WaveShaperNode(context[kNapiObj], parsedOptions);
|
|
108
|
+
} catch (err) {
|
|
109
|
+
throwSanitizedError(err);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
super(context, {
|
|
113
|
+
[kNapiObj]: napiObj,
|
|
114
|
+
});
|
|
48
115
|
|
|
49
|
-
get oversample() {
|
|
50
|
-
return super.oversample;
|
|
51
116
|
}
|
|
52
117
|
|
|
53
|
-
|
|
118
|
+
get curve() {
|
|
119
|
+
if (!(this instanceof WaveShaperNode)) {
|
|
120
|
+
throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'WaveShaperNode\'');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return this[kNapiObj].curve;
|
|
124
|
+
}
|
|
54
125
|
|
|
55
126
|
set curve(value) {
|
|
127
|
+
if (!(this instanceof WaveShaperNode)) {
|
|
128
|
+
throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'WaveShaperNode\'');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (value === null) {
|
|
132
|
+
console.warn('Setting the \'curve\' property on \'WaveShaperNode\' to \'null\' is not supported yet');
|
|
133
|
+
return;
|
|
134
|
+
} else if (!(value instanceof Float32Array)) {
|
|
135
|
+
throw new TypeError('Failed to set the \'curve\' property on \'WaveShaperNode\': Value is not a valid \'Float32Array\' value');
|
|
136
|
+
}
|
|
137
|
+
|
|
56
138
|
try {
|
|
57
|
-
|
|
139
|
+
this[kNapiObj].curve = value;
|
|
58
140
|
} catch (err) {
|
|
59
141
|
throwSanitizedError(err);
|
|
60
142
|
}
|
|
61
143
|
}
|
|
62
144
|
|
|
145
|
+
get oversample() {
|
|
146
|
+
if (!(this instanceof WaveShaperNode)) {
|
|
147
|
+
throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'WaveShaperNode\'');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return this[kNapiObj].oversample;
|
|
151
|
+
}
|
|
152
|
+
|
|
63
153
|
set oversample(value) {
|
|
154
|
+
if (!(this instanceof WaveShaperNode)) {
|
|
155
|
+
throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'WaveShaperNode\'');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!['none', '2x', '4x'].includes(value)) {
|
|
159
|
+
console.warn(`Failed to set the 'oversample' property on 'WaveShaperNode': Value '${value}' is not a valid 'OverSampleType' enum value`);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
64
163
|
try {
|
|
65
|
-
|
|
164
|
+
this[kNapiObj].oversample = value;
|
|
66
165
|
} catch (err) {
|
|
67
166
|
throwSanitizedError(err);
|
|
68
167
|
}
|
|
69
168
|
}
|
|
70
169
|
|
|
71
|
-
// methods
|
|
72
|
-
|
|
73
170
|
}
|
|
74
171
|
|
|
172
|
+
Object.defineProperties(WaveShaperNode, {
|
|
173
|
+
length: {
|
|
174
|
+
__proto__: null,
|
|
175
|
+
writable: false,
|
|
176
|
+
enumerable: false,
|
|
177
|
+
configurable: true,
|
|
178
|
+
value: 1,
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
Object.defineProperties(WaveShaperNode.prototype, {
|
|
183
|
+
[Symbol.toStringTag]: {
|
|
184
|
+
__proto__: null,
|
|
185
|
+
writable: false,
|
|
186
|
+
enumerable: false,
|
|
187
|
+
configurable: true,
|
|
188
|
+
value: 'WaveShaperNode',
|
|
189
|
+
},
|
|
190
|
+
|
|
191
|
+
curve: kEnumerableProperty,
|
|
192
|
+
oversample: kEnumerableProperty,
|
|
193
|
+
|
|
194
|
+
});
|
|
195
|
+
|
|
75
196
|
return WaveShaperNode;
|
|
76
197
|
};
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
package/js/lib/cast.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
exports.toSanitizedSequence = function toSanitizedSequence(data, targetCtor) {
|
|
2
|
+
if (
|
|
3
|
+
(data.buffer && data.buffer instanceof ArrayBuffer)
|
|
4
|
+
|| Array.isArray(data)
|
|
5
|
+
) {
|
|
6
|
+
data = new targetCtor(data);
|
|
7
|
+
} else {
|
|
8
|
+
throw new TypeError(`cannot be converted to sequence of ${targetCtor}`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// check it only contains finite values
|
|
12
|
+
for (let i = 0; i < data.length; i++) {
|
|
13
|
+
if (!Number.isFinite(data[i])) {
|
|
14
|
+
throw new TypeError(`should contain only finite values`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return data;
|
|
19
|
+
}
|
package/js/lib/errors.js
CHANGED
|
@@ -4,58 +4,6 @@ const path = require('path');
|
|
|
4
4
|
const internalPath = path.join('node-web-audio-api', 'js');
|
|
5
5
|
const internalRe = new RegExp(internalPath);
|
|
6
6
|
|
|
7
|
-
// from wpt/resources/tesharness.js (line 2226)
|
|
8
|
-
const nameCodeMap = {
|
|
9
|
-
IndexSizeError: 1,
|
|
10
|
-
HierarchyRequestError: 3,
|
|
11
|
-
WrongDocumentError: 4,
|
|
12
|
-
InvalidCharacterError: 5,
|
|
13
|
-
NoModificationAllowedError: 7,
|
|
14
|
-
NotFoundError: 8,
|
|
15
|
-
NotSupportedError: 9,
|
|
16
|
-
InUseAttributeError: 10,
|
|
17
|
-
InvalidStateError: 11,
|
|
18
|
-
SyntaxError: 12,
|
|
19
|
-
InvalidModificationError: 13,
|
|
20
|
-
NamespaceError: 14,
|
|
21
|
-
InvalidAccessError: 15,
|
|
22
|
-
TypeMismatchError: 17,
|
|
23
|
-
SecurityError: 18,
|
|
24
|
-
NetworkError: 19,
|
|
25
|
-
AbortError: 20,
|
|
26
|
-
URLMismatchError: 21,
|
|
27
|
-
QuotaExceededError: 22,
|
|
28
|
-
TimeoutError: 23,
|
|
29
|
-
InvalidNodeTypeError: 24,
|
|
30
|
-
DataCloneError: 25,
|
|
31
|
-
|
|
32
|
-
EncodingError: 0,
|
|
33
|
-
NotReadableError: 0,
|
|
34
|
-
UnknownError: 0,
|
|
35
|
-
ConstraintError: 0,
|
|
36
|
-
DataError: 0,
|
|
37
|
-
TransactionInactiveError: 0,
|
|
38
|
-
ReadOnlyError: 0,
|
|
39
|
-
VersionError: 0,
|
|
40
|
-
OperationError: 0,
|
|
41
|
-
NotAllowedError: 0,
|
|
42
|
-
OptOutError: 0
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
exports.nameCodeMap = nameCodeMap;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class DOMException extends Error {
|
|
49
|
-
constructor(message, name) {
|
|
50
|
-
super(message);
|
|
51
|
-
|
|
52
|
-
this.name = name;
|
|
53
|
-
this.code = nameCodeMap[this.name];
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
exports.DOMException = DOMException;
|
|
58
|
-
|
|
59
7
|
function overrideStack(originalError, newError) {
|
|
60
8
|
// override previous error message
|
|
61
9
|
const stack = originalError.stack.replace(originalError.message, newError.message);
|
|
@@ -87,6 +35,7 @@ exports.throwSanitizedError = function throwSanitizedError(err) {
|
|
|
87
35
|
if (originalMessage.startsWith('TypeError')) {
|
|
88
36
|
const msg = originalMessage.replace(/^TypeError - /, '');
|
|
89
37
|
const error = new TypeError(msg);
|
|
38
|
+
overrideStack(err, error);
|
|
90
39
|
|
|
91
40
|
throw error;
|
|
92
41
|
} else if (originalMessage.startsWith('RangeError')) {
|
|
@@ -110,20 +59,26 @@ exports.throwSanitizedError = function throwSanitizedError(err) {
|
|
|
110
59
|
overrideStack(err, error);
|
|
111
60
|
|
|
112
61
|
throw error;
|
|
113
|
-
} if (originalMessage.startsWith('IndexSizeError')) {
|
|
62
|
+
} else if (originalMessage.startsWith('IndexSizeError')) {
|
|
114
63
|
const msg = originalMessage.replace(/^IndexSizeError - /, '');
|
|
115
64
|
const error = new DOMException(msg, 'IndexSizeError');
|
|
116
65
|
overrideStack(err, error);
|
|
117
66
|
|
|
118
67
|
throw error;
|
|
119
|
-
} if (originalMessage.startsWith('InvalidAccessError')) {
|
|
68
|
+
} else if (originalMessage.startsWith('InvalidAccessError')) {
|
|
120
69
|
const msg = originalMessage.replace(/^InvalidAccessError - /, '');
|
|
121
70
|
const error = new DOMException(msg, 'InvalidAccessError');
|
|
122
71
|
overrideStack(err, error);
|
|
123
72
|
|
|
73
|
+
throw error;
|
|
74
|
+
} else if (originalMessage.startsWith('NotFoundError')) {
|
|
75
|
+
const msg = originalMessage.replace(/^NotFoundError - /, '');
|
|
76
|
+
const error = new DOMException(msg, 'NotFoundError');
|
|
77
|
+
overrideStack(err, error);
|
|
78
|
+
|
|
124
79
|
throw error;
|
|
125
80
|
}
|
|
126
81
|
|
|
127
|
-
console.warn('[lib/errors.js]
|
|
82
|
+
console.warn('[lib/errors.js] Unexpected Rust error', err);
|
|
128
83
|
throw err;
|
|
129
84
|
}
|
package/js/lib/events.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const { kNapiObj, kDispatchEvent } = require('./symbols.js');
|
|
2
|
+
const { isFunction } = require('./utils.js');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Listen for events from Rust, and bridge them to Node EventTarget paradigm
|
|
6
|
+
*/
|
|
7
|
+
module.exports.bridgeEventTarget = function bridgeEventTarget(jsObj) {
|
|
8
|
+
// Finalize event registration on Rust side
|
|
9
|
+
jsObj[kNapiObj][kDispatchEvent] = (err, eventType) => {
|
|
10
|
+
const event = new Event(eventType);
|
|
11
|
+
// call attribute first if exists
|
|
12
|
+
if (isFunction(jsObj[`on${event.type}`])) {
|
|
13
|
+
jsObj[`on${event.type}`](event);
|
|
14
|
+
}
|
|
15
|
+
// then distach to add event listeners
|
|
16
|
+
jsObj.dispatchEvent(event);
|
|
17
|
+
}
|
|
18
|
+
// ask Rust to register `kDispatchEvent` as listener
|
|
19
|
+
jsObj[kNapiObj].__initEventTarget__();
|
|
20
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
module.exports.kNapiObj = Symbol('node-web-audio-api:napi-obj');
|
|
2
|
+
module.exports.kAudioBuffer = Symbol('node-web-audio-api:audio-buffer');
|
|
3
|
+
// this needs to be shared with Rust ide
|
|
4
|
+
module.exports.kDispatchEvent = Symbol.for('node-web-audio-api:napi-dispatch-event');
|
|
5
|
+
|
package/js/lib/utils.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
exports.isPlainObject = function isPlainObject(obj) {
|
|
2
|
-
return Object.prototype.toString.call(obj) === '[object Object]';
|
|
3
|
-
};
|
|
4
|
-
|
|
5
|
-
exports.isPositiveInt = function isPositiveInt(n) {
|
|
6
|
-
return Number.isSafeInteger(n) && 0 < n;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
exports.isPositiveNumber = function isPositiveNumber(n) {
|
|
10
|
-
return Number(n) === n && 0 < n;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
1
|
exports.isFunction = function isFunction(val) {
|
|
14
2
|
return Object.prototype.toString.call(val) == '[object Function]' ||
|
|
15
3
|
Object.prototype.toString.call(val) == '[object AsyncFunction]';
|
|
16
4
|
};
|
|
5
|
+
|
|
6
|
+
const kEnumerableProperty = { __proto__: null };
|
|
7
|
+
kEnumerableProperty.enumerable = true;
|
|
8
|
+
Object.freeze(kEnumerableProperty);
|
|
9
|
+
|
|
10
|
+
exports.kEnumerableProperty = kEnumerableProperty;
|
|
11
|
+
|
|
12
|
+
const kHiddenProperty = { __proto__: null };
|
|
13
|
+
kHiddenProperty.enumerable = false;
|
|
14
|
+
Object.freeze(kHiddenProperty);
|
|
15
|
+
|
|
16
|
+
exports.kHiddenProperty = kHiddenProperty;
|