node-web-audio-api 0.18.0 → 0.20.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 (51) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/TODOS.md +134 -12
  3. package/index.mjs +17 -6
  4. package/js/AnalyserNode.js +259 -48
  5. package/js/AudioBuffer.js +243 -0
  6. package/js/AudioBufferSourceNode.js +259 -41
  7. package/js/AudioContext.js +294 -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 +120 -0
  13. package/js/BaseAudioContext.js +434 -0
  14. package/js/BiquadFilterNode.js +218 -29
  15. package/js/ChannelMergerNode.js +93 -22
  16. package/js/ChannelSplitterNode.js +93 -22
  17. package/js/ConstantSourceNode.js +86 -26
  18. package/js/ConvolverNode.js +158 -29
  19. package/js/DelayNode.js +112 -21
  20. package/js/DynamicsCompressorNode.js +195 -27
  21. package/js/Events.js +84 -0
  22. package/js/GainNode.js +104 -21
  23. package/js/IIRFilterNode.js +136 -23
  24. package/js/MediaStreamAudioSourceNode.js +80 -24
  25. package/js/OfflineAudioContext.js +198 -35
  26. package/js/OscillatorNode.js +189 -32
  27. package/js/PannerNode.js +458 -56
  28. package/js/PeriodicWave.js +67 -3
  29. package/js/ScriptProcessorNode.js +179 -0
  30. package/js/StereoPannerNode.js +104 -21
  31. package/js/WaveShaperNode.js +144 -29
  32. package/js/lib/cast.js +19 -0
  33. package/js/lib/errors.js +10 -55
  34. package/js/lib/events.js +10 -0
  35. package/js/lib/symbols.js +20 -0
  36. package/js/lib/utils.js +12 -12
  37. package/js/monkey-patch.js +40 -31
  38. package/node-web-audio-api.darwin-arm64.node +0 -0
  39. package/node-web-audio-api.darwin-x64.node +0 -0
  40. package/node-web-audio-api.linux-arm-gnueabihf.node +0 -0
  41. package/node-web-audio-api.linux-arm64-gnu.node +0 -0
  42. package/node-web-audio-api.linux-x64-gnu.node +0 -0
  43. package/node-web-audio-api.win32-arm64-msvc.node +0 -0
  44. package/node-web-audio-api.win32-x64-msvc.node +0 -0
  45. package/package.json +7 -4
  46. package/run-wpt.md +27 -0
  47. package/run-wpt.sh +5 -0
  48. package/js/AudioNode.mixin.js +0 -132
  49. package/js/AudioScheduledSourceNode.mixin.js +0 -67
  50. package/js/BaseAudioContext.mixin.js +0 -154
  51. package/js/EventTarget.mixin.js +0 -60
@@ -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 = (NativePeriodicWave) => {
4
- class PeriodicWave extends NativePeriodicWave {
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
- super(context, options);
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
 
@@ -0,0 +1,179 @@
1
+ /* eslint-disable no-unused-vars */
2
+ const conversions = require('webidl-conversions');
3
+ const {
4
+ toSanitizedSequence,
5
+ } = require('./lib/cast.js');
6
+ const {
7
+ isFunction,
8
+ kEnumerableProperty,
9
+ } = require('./lib/utils.js');
10
+ const {
11
+ throwSanitizedError,
12
+ } = require('./lib/errors.js');
13
+ const {
14
+ kNapiObj,
15
+ kAudioBuffer,
16
+ kOnAudioProcess,
17
+ } = require('./lib/symbols.js');
18
+ const {
19
+ propagateEvent,
20
+ } = require('./lib/events.js');
21
+ /* eslint-enable no-unused-vars */
22
+
23
+ const AudioNode = require('./AudioNode.js');
24
+
25
+ module.exports = (jsExport, nativeBinding) => {
26
+ class ScriptProcessorNode extends AudioNode {
27
+
28
+ #onaudioprocess = null;
29
+
30
+ constructor(context, options) {
31
+
32
+ if (arguments.length < 1) {
33
+ throw new TypeError(`Failed to construct 'ScriptProcessorNode': 1 argument required, but only ${arguments.length} present`);
34
+ }
35
+
36
+ if (!(context instanceof jsExport.BaseAudioContext)) {
37
+ throw new TypeError(`Failed to construct 'ScriptProcessorNode': argument 1 is not of type BaseAudioContext`);
38
+ }
39
+
40
+ // parsed version of the option to be passed to NAPI
41
+ const parsedOptions = {};
42
+
43
+ if (options && typeof options !== 'object') {
44
+ throw new TypeError('Failed to construct \'ScriptProcessorNode\': argument 2 is not of type \'ScriptProcessorNodeOptions\'');
45
+ }
46
+
47
+ // IDL defines bufferSize default value as 0
48
+ // cf. https://webaudio.github.io/web-audio-api/#dom-baseaudiocontext-createscriptprocessor
49
+ // > If it’s not passed in, or if the value is 0, then the implementation
50
+ // > will choose the best buffer size for the given environment, which will
51
+ // > be constant power of 2 throughout the lifetime of the node.
52
+ if (options && options.bufferSize !== undefined && options.bufferSize !== 0) {
53
+ parsedOptions.bufferSize = conversions['unsigned long'](options.bufferSize, {
54
+ enforceRange: true,
55
+ context: `Failed to construct 'ScriptProcessorNode': Failed to read the 'bufferSize' property from ScriptProcessorNodeOptions: The provided value '${options.bufferSize}'`,
56
+ });
57
+ } else {
58
+ parsedOptions.bufferSize = 256;
59
+ }
60
+
61
+ if (options && options.numberOfInputChannels !== undefined) {
62
+ parsedOptions.numberOfInputChannels = conversions['unsigned long'](options.numberOfInputChannels, {
63
+ enforceRange: true,
64
+ context: `Failed to construct 'ScriptProcessorNode': Failed to read the 'numberOfInputChannels' property from ScriptProcessorNodeOptions: The provided value '${options.numberOfInputChannels}'`,
65
+ });
66
+ } else {
67
+ parsedOptions.numberOfInputChannels = 2;
68
+ }
69
+
70
+ if (options && options.numberOfOutputChannels !== undefined) {
71
+ parsedOptions.numberOfOutputChannels = conversions['unsigned long'](options.numberOfOutputChannels, {
72
+ enforceRange: true,
73
+ context: `Failed to construct 'ScriptProcessorNode': Failed to read the 'numberOfOutputChannels' property from ScriptProcessorNodeOptions: The provided value '${options.numberOfOutputChannels}'`,
74
+ });
75
+ } else {
76
+ parsedOptions.numberOfOutputChannels = 2;
77
+ }
78
+
79
+ if (options && options.channelCount !== undefined) {
80
+ parsedOptions.channelCount = conversions['unsigned long'](options.channelCount, {
81
+ enforceRange: true,
82
+ context: `Failed to construct 'ScriptProcessorNode': Failed to read the 'channelCount' property from ScriptProcessorNodeOptions: The provided value '${options.channelCount}'`,
83
+ });
84
+ }
85
+
86
+ if (options && options.channelCountMode !== undefined) {
87
+ parsedOptions.channelCountMode = conversions['DOMString'](options.channelCountMode, {
88
+ context: `Failed to construct 'ScriptProcessorNode': Failed to read the 'channelCount' property from ScriptProcessorNodeOptions: The provided value '${options.channelCountMode}'`,
89
+ });
90
+ }
91
+
92
+ if (options && options.channelInterpretation !== undefined) {
93
+ parsedOptions.channelInterpretation = conversions['DOMString'](options.channelInterpretation, {
94
+ context: `Failed to construct 'ScriptProcessorNode': Failed to read the 'channelInterpretation' property from ScriptProcessorNodeOptions: The provided value '${options.channelInterpretation}'`,
95
+ });
96
+ }
97
+
98
+ let napiObj;
99
+
100
+ try {
101
+ napiObj = new nativeBinding.ScriptProcessorNode(context[kNapiObj], parsedOptions);
102
+ } catch (err) {
103
+ throwSanitizedError(err);
104
+ }
105
+
106
+ super(context, {
107
+ [kNapiObj]: napiObj,
108
+ });
109
+
110
+ this[kNapiObj][kOnAudioProcess] = (err, rawEvent) => {
111
+ if (typeof rawEvent !== 'object' && !('type' in rawEvent)) {
112
+ throw new TypeError('Invalid [kOnStateChange] Invocation: rawEvent should have a type property');
113
+ }
114
+
115
+ const audioProcessingEventInit = {
116
+ playbackTime: rawEvent.playbackTime,
117
+ inputBuffer: new jsExport.AudioBuffer({ [kNapiObj]: rawEvent.inputBuffer }),
118
+ outputBuffer: new jsExport.AudioBuffer({ [kNapiObj]: rawEvent.outputBuffer }),
119
+ };
120
+
121
+ const event = new jsExport.AudioProcessingEvent('audioprocess', audioProcessingEventInit);
122
+ propagateEvent(this, event);
123
+ };
124
+
125
+ this[kNapiObj].listen_to_events();
126
+ }
127
+
128
+ get bufferSize() {
129
+ if (!(this instanceof ScriptProcessorNode)) {
130
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'ScriptProcessorNode\'');
131
+ }
132
+
133
+ return this[kNapiObj].bufferSize;
134
+ }
135
+
136
+ get onaudioprocess() {
137
+ if (!(this instanceof ScriptProcessorNode)) {
138
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'ScriptProcessorNode\'');
139
+ }
140
+
141
+ return this.#onaudioprocess;
142
+ }
143
+
144
+ set onaudioprocess(value) {
145
+ if (!(this instanceof ScriptProcessorNode)) {
146
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'ScriptProcessorNode\'');
147
+ }
148
+
149
+ if (isFunction(value) || value === null) {
150
+ this.#onaudioprocess = value;
151
+ }
152
+ }
153
+ }
154
+
155
+ Object.defineProperties(ScriptProcessorNode, {
156
+ length: {
157
+ __proto__: null,
158
+ writable: false,
159
+ enumerable: false,
160
+ configurable: true,
161
+ value: 0,
162
+ },
163
+ });
164
+
165
+ Object.defineProperties(ScriptProcessorNode.prototype, {
166
+ [Symbol.toStringTag]: {
167
+ __proto__: null,
168
+ writable: false,
169
+ enumerable: false,
170
+ configurable: true,
171
+ value: 'ScriptProcessorNode',
172
+ },
173
+ bufferSize: kEnumerableProperty,
174
+ onaudioprocess: kEnumerableProperty,
175
+
176
+ });
177
+
178
+ return ScriptProcessorNode;
179
+ };
@@ -17,40 +17,123 @@
17
17
  // -------------------------------------------------------------------------- //
18
18
  // -------------------------------------------------------------------------- //
19
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');
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
+ /* eslint-enable no-unused-vars */
26
37
 
38
+ const AudioNode = require('./AudioNode.js');
27
39
 
28
- module.exports = (NativeStereoPannerNode) => {
40
+ module.exports = (jsExport, nativeBinding) => {
41
+ class StereoPannerNode extends AudioNode {
29
42
 
30
- const EventTarget = EventTargetMixin(NativeStereoPannerNode);
31
- const AudioNode = AudioNodeMixin(EventTarget);
43
+ #pan = null;
32
44
 
33
- class StereoPannerNode extends AudioNode {
34
45
  constructor(context, options) {
35
- if (options !== undefined && typeof options !== 'object') {
36
- throw new TypeError("Failed to construct 'StereoPannerNode': argument 2 is not of type 'StereoPannerOptions'")
46
+
47
+ if (arguments.length < 1) {
48
+ throw new TypeError(`Failed to construct 'StereoPannerNode': 1 argument required, but only ${arguments.length} present`);
49
+ }
50
+
51
+ if (!(context instanceof jsExport.BaseAudioContext)) {
52
+ throw new TypeError(`Failed to construct 'StereoPannerNode': argument 1 is not of type BaseAudioContext`);
53
+ }
54
+
55
+ // parsed version of the option to be passed to NAPI
56
+ const parsedOptions = {};
57
+
58
+ if (options && typeof options !== 'object') {
59
+ throw new TypeError('Failed to construct \'StereoPannerNode\': argument 2 is not of type \'StereoPannerOptions\'');
60
+ }
61
+
62
+ if (options && options.pan !== undefined) {
63
+ parsedOptions.pan = conversions['float'](options.pan, {
64
+ context: `Failed to construct 'StereoPannerNode': Failed to read the 'pan' property from StereoPannerOptions: The provided value (${options.pan}})`,
65
+ });
66
+ } else {
67
+ parsedOptions.pan = 0;
68
+ }
69
+
70
+ if (options && options.channelCount !== undefined) {
71
+ parsedOptions.channelCount = conversions['unsigned long'](options.channelCount, {
72
+ enforceRange: true,
73
+ context: `Failed to construct 'StereoPannerNode': Failed to read the 'channelCount' property from StereoPannerOptions: The provided value '${options.channelCount}'`,
74
+ });
75
+ }
76
+
77
+ if (options && options.channelCountMode !== undefined) {
78
+ parsedOptions.channelCountMode = conversions['DOMString'](options.channelCountMode, {
79
+ context: `Failed to construct 'StereoPannerNode': Failed to read the 'channelCount' property from StereoPannerOptions: The provided value '${options.channelCountMode}'`,
80
+ });
81
+ }
82
+
83
+ if (options && options.channelInterpretation !== undefined) {
84
+ parsedOptions.channelInterpretation = conversions['DOMString'](options.channelInterpretation, {
85
+ context: `Failed to construct 'StereoPannerNode': Failed to read the 'channelInterpretation' property from StereoPannerOptions: The provided value '${options.channelInterpretation}'`,
86
+ });
37
87
  }
38
88
 
39
- super(context, options);
89
+ let napiObj;
40
90
 
41
- this.pan = new AudioParam(this.pan);
91
+ try {
92
+ napiObj = new nativeBinding.StereoPannerNode(context[kNapiObj], parsedOptions);
93
+ } catch (err) {
94
+ throwSanitizedError(err);
95
+ }
96
+
97
+ super(context, {
98
+ [kNapiObj]: napiObj,
99
+ });
100
+
101
+ this.#pan = new jsExport.AudioParam({
102
+ [kNapiObj]: this[kNapiObj].pan,
103
+ });
42
104
  }
43
105
 
44
- // getters
106
+ get pan() {
107
+ if (!(this instanceof StereoPannerNode)) {
108
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'StereoPannerNode\'');
109
+ }
45
110
 
46
- // setters
111
+ return this.#pan;
112
+ }
47
113
 
48
- // methods
49
-
50
114
  }
51
115
 
52
- return StereoPannerNode;
53
- };
116
+ Object.defineProperties(StereoPannerNode, {
117
+ length: {
118
+ __proto__: null,
119
+ writable: false,
120
+ enumerable: false,
121
+ configurable: true,
122
+ value: 1,
123
+ },
124
+ });
54
125
 
126
+ Object.defineProperties(StereoPannerNode.prototype, {
127
+ [Symbol.toStringTag]: {
128
+ __proto__: null,
129
+ writable: false,
130
+ enumerable: false,
131
+ configurable: true,
132
+ value: 'StereoPannerNode',
133
+ },
134
+ pan: kEnumerableProperty,
55
135
 
56
-
136
+ });
137
+
138
+ return StereoPannerNode;
139
+ };
@@ -17,63 +17,178 @@
17
17
  // -------------------------------------------------------------------------- //
18
18
  // -------------------------------------------------------------------------- //
19
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');
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
+ /* eslint-enable no-unused-vars */
37
+
38
+ const AudioNode = require('./AudioNode.js');
39
+
40
+ module.exports = (jsExport, nativeBinding) => {
41
+ class WaveShaperNode extends AudioNode {
26
42
 
43
+ constructor(context, options) {
27
44
 
28
- module.exports = (NativeWaveShaperNode) => {
45
+ if (arguments.length < 1) {
46
+ throw new TypeError(`Failed to construct 'WaveShaperNode': 1 argument required, but only ${arguments.length} present`);
47
+ }
29
48
 
30
- const EventTarget = EventTargetMixin(NativeWaveShaperNode);
31
- const AudioNode = AudioNodeMixin(EventTarget);
49
+ if (!(context instanceof jsExport.BaseAudioContext)) {
50
+ throw new TypeError(`Failed to construct 'WaveShaperNode': argument 1 is not of type BaseAudioContext`);
51
+ }
32
52
 
33
- class WaveShaperNode extends AudioNode {
34
- constructor(context, options) {
35
- if (options !== undefined && typeof options !== 'object') {
36
- throw new TypeError("Failed to construct 'WaveShaperNode': argument 2 is not of type 'WaveShaperOptions'")
53
+ // parsed version of the option to be passed to NAPI
54
+ const parsedOptions = {};
55
+
56
+ if (options && typeof options !== 'object') {
57
+ throw new TypeError('Failed to construct \'WaveShaperNode\': argument 2 is not of type \'WaveShaperOptions\'');
37
58
  }
38
59
 
39
- super(context, options);
60
+ if (options && options.curve !== undefined) {
61
+ try {
62
+ parsedOptions.curve = toSanitizedSequence(options.curve, Float32Array);
63
+ } catch (err) {
64
+ throw new TypeError(`Failed to construct 'WaveShaperNode': Failed to read the 'curve' property from WaveShaperOptions: The provided value ${err.message}`);
65
+ }
66
+ } else {
67
+ parsedOptions.curve = null;
68
+ }
40
69
 
41
- }
70
+ if (options && options.oversample !== undefined) {
71
+ if (!['none', '2x', '4x'].includes(options.oversample)) {
72
+ 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`);
73
+ }
42
74
 
43
- // getters
75
+ parsedOptions.oversample = conversions['DOMString'](options.oversample, {
76
+ context: `Failed to construct 'WaveShaperNode': Failed to read the 'oversample' property from WaveShaperOptions: The provided value '${options.oversample}'`,
77
+ });
78
+ } else {
79
+ parsedOptions.oversample = 'none';
80
+ }
44
81
 
45
- get curve() {
46
- return super.curve;
47
- }
82
+ if (options && options.channelCount !== undefined) {
83
+ parsedOptions.channelCount = conversions['unsigned long'](options.channelCount, {
84
+ enforceRange: true,
85
+ context: `Failed to construct 'WaveShaperNode': Failed to read the 'channelCount' property from WaveShaperOptions: The provided value '${options.channelCount}'`,
86
+ });
87
+ }
88
+
89
+ if (options && options.channelCountMode !== undefined) {
90
+ parsedOptions.channelCountMode = conversions['DOMString'](options.channelCountMode, {
91
+ context: `Failed to construct 'WaveShaperNode': Failed to read the 'channelCount' property from WaveShaperOptions: The provided value '${options.channelCountMode}'`,
92
+ });
93
+ }
94
+
95
+ if (options && options.channelInterpretation !== undefined) {
96
+ parsedOptions.channelInterpretation = conversions['DOMString'](options.channelInterpretation, {
97
+ context: `Failed to construct 'WaveShaperNode': Failed to read the 'channelInterpretation' property from WaveShaperOptions: The provided value '${options.channelInterpretation}'`,
98
+ });
99
+ }
100
+
101
+ let napiObj;
102
+
103
+ try {
104
+ napiObj = new nativeBinding.WaveShaperNode(context[kNapiObj], parsedOptions);
105
+ } catch (err) {
106
+ throwSanitizedError(err);
107
+ }
108
+
109
+ super(context, {
110
+ [kNapiObj]: napiObj,
111
+ });
48
112
 
49
- get oversample() {
50
- return super.oversample;
51
113
  }
52
114
 
53
- // setters
115
+ get curve() {
116
+ if (!(this instanceof WaveShaperNode)) {
117
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'WaveShaperNode\'');
118
+ }
119
+
120
+ return this[kNapiObj].curve;
121
+ }
54
122
 
55
123
  set curve(value) {
124
+ if (!(this instanceof WaveShaperNode)) {
125
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'WaveShaperNode\'');
126
+ }
127
+
128
+ if (value === null) {
129
+ console.warn('Setting the \'curve\' property on \'WaveShaperNode\' to \'null\' is not supported yet');
130
+ return;
131
+ } else if (!(value instanceof Float32Array)) {
132
+ throw new TypeError('Failed to set the \'curve\' property on \'WaveShaperNode\': Value is not a valid \'Float32Array\' value');
133
+ }
134
+
56
135
  try {
57
- super.curve = value;
136
+ this[kNapiObj].curve = value;
58
137
  } catch (err) {
59
138
  throwSanitizedError(err);
60
139
  }
61
140
  }
62
141
 
142
+ get oversample() {
143
+ if (!(this instanceof WaveShaperNode)) {
144
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'WaveShaperNode\'');
145
+ }
146
+
147
+ return this[kNapiObj].oversample;
148
+ }
149
+
63
150
  set oversample(value) {
151
+ if (!(this instanceof WaveShaperNode)) {
152
+ throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'WaveShaperNode\'');
153
+ }
154
+
155
+ if (!['none', '2x', '4x'].includes(value)) {
156
+ console.warn(`Failed to set the 'oversample' property on 'WaveShaperNode': Value '${value}' is not a valid 'OverSampleType' enum value`);
157
+ return;
158
+ }
159
+
64
160
  try {
65
- super.oversample = value;
161
+ this[kNapiObj].oversample = value;
66
162
  } catch (err) {
67
163
  throwSanitizedError(err);
68
164
  }
69
165
  }
70
166
 
71
- // methods
72
-
73
167
  }
74
168
 
169
+ Object.defineProperties(WaveShaperNode, {
170
+ length: {
171
+ __proto__: null,
172
+ writable: false,
173
+ enumerable: false,
174
+ configurable: true,
175
+ value: 1,
176
+ },
177
+ });
178
+
179
+ Object.defineProperties(WaveShaperNode.prototype, {
180
+ [Symbol.toStringTag]: {
181
+ __proto__: null,
182
+ writable: false,
183
+ enumerable: false,
184
+ configurable: true,
185
+ value: 'WaveShaperNode',
186
+ },
187
+
188
+ curve: kEnumerableProperty,
189
+ oversample: kEnumerableProperty,
190
+
191
+ });
192
+
75
193
  return WaveShaperNode;
76
194
  };
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
+ }