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
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
const conversions = require("webidl-conversions");
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
throwSanitizedError,
|
|
5
|
+
} = require('./lib/errors.js');
|
|
6
|
+
const {
|
|
7
|
+
kEnumerableProperty,
|
|
8
|
+
kHiddenProperty,
|
|
9
|
+
} = require('./lib/utils.js');
|
|
10
|
+
const {
|
|
11
|
+
kNapiObj,
|
|
12
|
+
kAudioBuffer,
|
|
13
|
+
} = require('./lib/symbols.js');
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
module.exports = (_jsExport, nativeBinding) => {
|
|
17
|
+
class AudioBuffer {
|
|
18
|
+
constructor(options) {
|
|
19
|
+
if (arguments.length < 1) {
|
|
20
|
+
throw new TypeError(`Failed to construct 'AudioBuffer': 1 argument required, but only ${arguments.length} present`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (typeof options !== 'object') {
|
|
24
|
+
throw new TypeError("Failed to construct 'AudioBuffer': argument 1 is not of type 'AudioBufferOptions'");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (kNapiObj in options) {
|
|
28
|
+
// internal constructor for `startRendering` and `decodeAudioData` cases
|
|
29
|
+
Object.defineProperty(this, kNapiObj, {
|
|
30
|
+
value: options[kNapiObj],
|
|
31
|
+
...kHiddenProperty,
|
|
32
|
+
});
|
|
33
|
+
} else {
|
|
34
|
+
// Regular public constructor
|
|
35
|
+
// dictionary AudioBufferOptions {
|
|
36
|
+
// unsigned long numberOfChannels = 1;
|
|
37
|
+
// required unsigned long length;
|
|
38
|
+
// required float sampleRate;
|
|
39
|
+
// };
|
|
40
|
+
const parsedOptions = {};
|
|
41
|
+
|
|
42
|
+
if (options.numberOfChannels !== undefined) {
|
|
43
|
+
parsedOptions.numberOfChannels = conversions['unsigned long'](options.numberOfChannels, {
|
|
44
|
+
enforceRange: true,
|
|
45
|
+
context: `Failed to construct 'AudioBuffer': Failed to read the 'numberOfChannels' property from AudioBufferOptions: numberOfCHannels`,
|
|
46
|
+
});
|
|
47
|
+
} else {
|
|
48
|
+
parsedOptions.numberOfChannels = 1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (options.length === undefined) {
|
|
52
|
+
throw new TypeError(`Failed to construct 'AudioBuffer': Failed to read the 'numberOfChannels' property from AudioBufferOptions: required member is undefined`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
parsedOptions.length = conversions['unsigned long'](options.length, {
|
|
56
|
+
enforceRange: true,
|
|
57
|
+
context: `Failed to construct 'AudioBuffer': Failed to read the 'length' property from AudioBufferOptions: length`,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (options.sampleRate === undefined) {
|
|
61
|
+
throw new TypeError(`Failed to construct 'AudioBuffer': Failed to read the 'numberOfChannels' property from AudioBufferOptions: required member is undefined`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
parsedOptions.sampleRate = conversions['float'](options.sampleRate, {
|
|
65
|
+
context: `Failed to construct 'AudioBuffer': Failed to read the 'sampleRate' property from AudioBufferOptions: sampleRate`,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
let napiObj;
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
napiObj = new nativeBinding.AudioBuffer(parsedOptions);
|
|
72
|
+
} catch (err) {
|
|
73
|
+
throwSanitizedError(err);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
Object.defineProperty(this, kNapiObj, {
|
|
77
|
+
value: napiObj,
|
|
78
|
+
...kHiddenProperty,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get sampleRate() {
|
|
84
|
+
if (!(this instanceof AudioBuffer)) {
|
|
85
|
+
throw new TypeError("Invalid Invocation: Value of 'this' must be of type 'AudioBuffer'");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return this[kNapiObj].sampleRate;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get duration() {
|
|
92
|
+
if (!(this instanceof AudioBuffer)) {
|
|
93
|
+
throw new TypeError("Invalid Invocation: Value of 'this' must be of type 'AudioBuffer'");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return this[kNapiObj].duration;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get length() {
|
|
100
|
+
if (!(this instanceof AudioBuffer)) {
|
|
101
|
+
throw new TypeError("Invalid Invocation: Value of 'this' must be of type 'AudioBuffer'");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return this[kNapiObj].length;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
get numberOfChannels() {
|
|
108
|
+
if (!(this instanceof AudioBuffer)) {
|
|
109
|
+
throw new TypeError("Invalid Invocation: Value of 'this' must be of type 'AudioBuffer'");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return this[kNapiObj].numberOfChannels;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
copyFromChannel(destination, channelNumber, bufferOffset = 0) {
|
|
116
|
+
if (!(this instanceof AudioBuffer)) {
|
|
117
|
+
throw new TypeError("Invalid Invocation: Value of 'this' must be of type 'AudioBuffer'");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (arguments.length < 2) {
|
|
121
|
+
throw new TypeError(`Failed to execute 'copyFromChannel' on 'AudioBuffer': 2 argument required, but only ${arguments.length} present`);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!(destination instanceof Float32Array)) {
|
|
125
|
+
throw new TypeError(`Failed to execute 'copyFromChannel' on 'AudioBuffer': parameter 1 is not of type 'Float32Array'`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Rust implementation uses a usize which will clamp -1 to 0, and spec requires
|
|
129
|
+
// an IndexSizeError rather than a TypeError, so this check must be done here.
|
|
130
|
+
// cf. note on AnalyzerNode::fftSize
|
|
131
|
+
if (channelNumber < 0) {
|
|
132
|
+
throw new DOMException(`Failed to execute 'copyFromChannel' on 'AudioBuffer': channelNumber must equal or greater than 0`, 'IndexSizeError');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
channelNumber = conversions['unsigned long'](channelNumber, {
|
|
136
|
+
context: `Failed to execute 'copyFromChannel' on 'AudioBuffer': channelNumber`,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
bufferOffset = conversions['unsigned long'](bufferOffset, {
|
|
140
|
+
context: `Failed to execute 'copyFromChannel' on 'AudioBuffer': bufferOffset`,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
this[kNapiObj].copyFromChannel(destination, channelNumber, bufferOffset);
|
|
145
|
+
} catch (err) {
|
|
146
|
+
throwSanitizedError(err);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
copyToChannel(source, channelNumber, bufferOffset = 0) {
|
|
151
|
+
if (!(this instanceof AudioBuffer)) {
|
|
152
|
+
throw new TypeError("Invalid Invocation: Value of 'this' must be of type 'AudioBuffer'");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (arguments.length < 2) {
|
|
156
|
+
throw new TypeError(`Failed to execute 'copyToChannel' on 'AudioBuffer': 2 argument required, but only ${arguments.length} present`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (!(source instanceof Float32Array)) {
|
|
160
|
+
throw new TypeError(`Failed to execute 'copyToChannel' on 'AudioBuffer': source is not of type 'Float32Array'`);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Rust implementation uses a usize which will clamp -1 to 0, and spec requires
|
|
164
|
+
// an IndexSizeError rather than a TypeError, so this check must be done here.
|
|
165
|
+
// cf. note on AnalyzerNode::fftSize
|
|
166
|
+
if (channelNumber < 0) {
|
|
167
|
+
throw new DOMException(`Failed to execute 'copyToChannel' on 'AudioBuffer': channelNumber must equal or greater than 0`, 'IndexSizeError');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
channelNumber = conversions['unsigned long'](channelNumber, {
|
|
171
|
+
context: `Failed to execute 'copyToChannel' on 'AudioBuffer': channelNumber`,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
bufferOffset = conversions['unsigned long'](bufferOffset, {
|
|
175
|
+
context: `Failed to execute 'copyToChannel' on 'AudioBuffer': bufferOffset`,
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
this[kNapiObj].copyToChannel(source, channelNumber, bufferOffset);
|
|
180
|
+
} catch (err) {
|
|
181
|
+
throwSanitizedError(err);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
getChannelData(channel) {
|
|
186
|
+
if (!(this instanceof AudioBuffer)) {
|
|
187
|
+
throw new TypeError("Invalid Invocation: Value of 'this' must be of type 'AudioBuffer'");
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (arguments.length < 1) {
|
|
191
|
+
throw new TypeError(`Failed to execute 'getChannelData' on 'AudioBuffer': 1 argument required, but only ${arguments.length} present`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Rust implementation uses a usize which will clamp -1 to 0, and spec requires
|
|
195
|
+
// an IndexSizeError rather than a TypeError, so this check must be done here.
|
|
196
|
+
// cf. note on AnalyzerNode::fftSize
|
|
197
|
+
if (channel < 0) {
|
|
198
|
+
throw new DOMException(`Failed to execute 'getChannelData' on 'AudioBuffer': channel must equal or greater than 0`, 'IndexSizeError');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
channel = conversions['unsigned long'](channel, {
|
|
202
|
+
context: `Failed to execute 'getChannelData' on 'AudioBuffer': channel`,
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
return this[kNapiObj].getChannelData(channel);
|
|
207
|
+
} catch (err) {
|
|
208
|
+
throwSanitizedError(err);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
Object.defineProperties(AudioBuffer, {
|
|
214
|
+
length: {
|
|
215
|
+
__proto__: null,
|
|
216
|
+
writable: false,
|
|
217
|
+
enumerable: false,
|
|
218
|
+
configurable: true,
|
|
219
|
+
value: 1,
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
Object.defineProperties(AudioBuffer.prototype, {
|
|
224
|
+
[Symbol.toStringTag]: {
|
|
225
|
+
__proto__: null,
|
|
226
|
+
writable: false,
|
|
227
|
+
enumerable: false,
|
|
228
|
+
configurable: true,
|
|
229
|
+
value: 'AudioBuffer',
|
|
230
|
+
},
|
|
231
|
+
|
|
232
|
+
sampleRate: kEnumerableProperty,
|
|
233
|
+
duration: kEnumerableProperty,
|
|
234
|
+
length: kEnumerableProperty,
|
|
235
|
+
numberOfChannels: kEnumerableProperty,
|
|
236
|
+
copyFromChannel: kEnumerableProperty,
|
|
237
|
+
copyToChannel: kEnumerableProperty,
|
|
238
|
+
getChannelData: kEnumerableProperty,
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
return AudioBuffer;
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
|
|
@@ -17,93 +17,317 @@
|
|
|
17
17
|
// -------------------------------------------------------------------------- //
|
|
18
18
|
// -------------------------------------------------------------------------- //
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
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 */
|
|
27
40
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const EventTarget = EventTargetMixin(NativeAudioBufferSourceNode, ['ended']);
|
|
31
|
-
const AudioNode = AudioNodeMixin(EventTarget);
|
|
32
|
-
const AudioScheduledSourceNode = AudioScheduledSourceNodeMixin(AudioNode);
|
|
41
|
+
const AudioScheduledSourceNode = require('./AudioScheduledSourceNode.js');
|
|
33
42
|
|
|
43
|
+
module.exports = (jsExport, nativeBinding) => {
|
|
34
44
|
class AudioBufferSourceNode extends AudioScheduledSourceNode {
|
|
45
|
+
|
|
46
|
+
#playbackRate = null;
|
|
47
|
+
#detune = null;
|
|
48
|
+
|
|
35
49
|
constructor(context, options) {
|
|
36
|
-
|
|
37
|
-
|
|
50
|
+
|
|
51
|
+
if (arguments.length < 1) {
|
|
52
|
+
throw new TypeError(`Failed to construct 'AudioBufferSourceNode': 1 argument required, but only ${arguments.length} present`);
|
|
38
53
|
}
|
|
39
54
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
super.__initEventTarget__();
|
|
55
|
+
if (!(context instanceof jsExport.BaseAudioContext)) {
|
|
56
|
+
throw new TypeError(`Failed to construct 'AudioBufferSourceNode': argument 1 is not of type BaseAudioContext`);
|
|
57
|
+
}
|
|
44
58
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
59
|
+
// parsed version of the option to be passed to NAPI
|
|
60
|
+
const parsedOptions = {};
|
|
48
61
|
|
|
49
|
-
|
|
62
|
+
if (options && typeof options !== 'object') {
|
|
63
|
+
throw new TypeError('Failed to construct \'AudioBufferSourceNode\': argument 2 is not of type \'AudioBufferSourceOptions\'');
|
|
64
|
+
}
|
|
50
65
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
66
|
+
if (options && options.buffer !== undefined) {
|
|
67
|
+
if (options.buffer !== null) {
|
|
68
|
+
if (!(options.buffer instanceof jsExport.AudioBuffer)) {
|
|
69
|
+
throw new TypeError('Failed to construct \'AudioBufferSourceNode\': Failed to read the \'buffer\' property from AudioBufferSourceOptions: The provided value cannot be converted to \'AudioBuffer\'');
|
|
70
|
+
}
|
|
54
71
|
|
|
55
|
-
|
|
56
|
-
|
|
72
|
+
// unwrap napi audio buffer
|
|
73
|
+
parsedOptions.buffer = options.buffer[kNapiObj];
|
|
74
|
+
} else {
|
|
75
|
+
parsedOptions.buffer = null;
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
parsedOptions.buffer = null;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (options && options.detune !== undefined) {
|
|
82
|
+
parsedOptions.detune = conversions['float'](options.detune, {
|
|
83
|
+
context: `Failed to construct 'AudioBufferSourceNode': Failed to read the 'detune' property from AudioBufferSourceOptions: The provided value (${options.detune}})`,
|
|
84
|
+
});
|
|
85
|
+
} else {
|
|
86
|
+
parsedOptions.detune = 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (options && options.loop !== undefined) {
|
|
90
|
+
parsedOptions.loop = conversions['boolean'](options.loop, {
|
|
91
|
+
context: `Failed to construct 'AudioBufferSourceNode': Failed to read the 'loop' property from AudioBufferSourceOptions: The provided value (${options.loop}})`,
|
|
92
|
+
});
|
|
93
|
+
} else {
|
|
94
|
+
parsedOptions.loop = false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (options && options.loopEnd !== undefined) {
|
|
98
|
+
parsedOptions.loopEnd = conversions['double'](options.loopEnd, {
|
|
99
|
+
context: `Failed to construct 'AudioBufferSourceNode': Failed to read the 'loopEnd' property from AudioBufferSourceOptions: The provided value (${options.loopEnd}})`,
|
|
100
|
+
});
|
|
101
|
+
} else {
|
|
102
|
+
parsedOptions.loopEnd = 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (options && options.loopStart !== undefined) {
|
|
106
|
+
parsedOptions.loopStart = conversions['double'](options.loopStart, {
|
|
107
|
+
context: `Failed to construct 'AudioBufferSourceNode': Failed to read the 'loopStart' property from AudioBufferSourceOptions: The provided value (${options.loopStart}})`,
|
|
108
|
+
});
|
|
109
|
+
} else {
|
|
110
|
+
parsedOptions.loopStart = 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (options && options.playbackRate !== undefined) {
|
|
114
|
+
parsedOptions.playbackRate = conversions['float'](options.playbackRate, {
|
|
115
|
+
context: `Failed to construct 'AudioBufferSourceNode': Failed to read the 'playbackRate' property from AudioBufferSourceOptions: The provided value (${options.playbackRate}})`,
|
|
116
|
+
});
|
|
117
|
+
} else {
|
|
118
|
+
parsedOptions.playbackRate = 1;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let napiObj;
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
napiObj = new nativeBinding.AudioBufferSourceNode(context[kNapiObj], parsedOptions);
|
|
125
|
+
} catch (err) {
|
|
126
|
+
throwSanitizedError(err);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
super(context, {
|
|
130
|
+
[kNapiObj]: napiObj,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// keep the wrapped AudioBuffer around
|
|
134
|
+
Object.defineProperty(this, kAudioBuffer, {
|
|
135
|
+
__proto__: null,
|
|
136
|
+
enumerable: false,
|
|
137
|
+
writable: true,
|
|
138
|
+
value: null,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
if (options && options.buffer !== undefined) {
|
|
142
|
+
this[kAudioBuffer] = options.buffer;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Bridge Rust native event to Node EventTarget
|
|
146
|
+
bridgeEventTarget(this);
|
|
147
|
+
|
|
148
|
+
this.#playbackRate = new jsExport.AudioParam({
|
|
149
|
+
[kNapiObj]: this[kNapiObj].playbackRate,
|
|
150
|
+
});
|
|
151
|
+
this.#detune = new jsExport.AudioParam({
|
|
152
|
+
[kNapiObj]: this[kNapiObj].detune,
|
|
153
|
+
});
|
|
57
154
|
}
|
|
58
155
|
|
|
59
|
-
get
|
|
60
|
-
|
|
156
|
+
get playbackRate() {
|
|
157
|
+
if (!(this instanceof AudioBufferSourceNode)) {
|
|
158
|
+
throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioBufferSourceNode\'');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return this.#playbackRate;
|
|
61
162
|
}
|
|
62
163
|
|
|
63
|
-
get
|
|
64
|
-
|
|
164
|
+
get detune() {
|
|
165
|
+
if (!(this instanceof AudioBufferSourceNode)) {
|
|
166
|
+
throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioBufferSourceNode\'');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return this.#detune;
|
|
65
170
|
}
|
|
66
171
|
|
|
67
|
-
|
|
172
|
+
get buffer() {
|
|
173
|
+
if (!(this instanceof AudioBufferSourceNode)) {
|
|
174
|
+
throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioBufferSourceNode\'');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return this[kAudioBuffer];
|
|
178
|
+
}
|
|
68
179
|
|
|
69
180
|
set buffer(value) {
|
|
181
|
+
if (!(this instanceof AudioBufferSourceNode)) {
|
|
182
|
+
throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioBufferSourceNode\'');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (value === null) {
|
|
186
|
+
console.warn('Setting the \'buffer\' property on \'AudioBufferSourceNode\' to \'null\' is not supported yet');
|
|
187
|
+
return;
|
|
188
|
+
} else if (!(kNapiObj in value)) {
|
|
189
|
+
throw new TypeError('Failed to set the \'buffer\' property on \'AudioBufferSourceNode\': Failed to convert value to \'AudioBuffer\'');
|
|
190
|
+
}
|
|
191
|
+
|
|
70
192
|
try {
|
|
71
|
-
|
|
193
|
+
this[kNapiObj].buffer = value[kNapiObj];
|
|
72
194
|
} catch (err) {
|
|
73
195
|
throwSanitizedError(err);
|
|
74
196
|
}
|
|
197
|
+
|
|
198
|
+
this[kAudioBuffer] = value;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
get loop() {
|
|
202
|
+
if (!(this instanceof AudioBufferSourceNode)) {
|
|
203
|
+
throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioBufferSourceNode\'');
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return this[kNapiObj].loop;
|
|
75
207
|
}
|
|
76
208
|
|
|
77
209
|
set loop(value) {
|
|
210
|
+
if (!(this instanceof AudioBufferSourceNode)) {
|
|
211
|
+
throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioBufferSourceNode\'');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
value = conversions['boolean'](value, {
|
|
215
|
+
context: `Failed to set the 'loop' property on 'AudioBufferSourceNode': Value`,
|
|
216
|
+
});
|
|
217
|
+
|
|
78
218
|
try {
|
|
79
|
-
|
|
219
|
+
this[kNapiObj].loop = value;
|
|
80
220
|
} catch (err) {
|
|
81
221
|
throwSanitizedError(err);
|
|
82
222
|
}
|
|
83
223
|
}
|
|
84
224
|
|
|
225
|
+
get loopStart() {
|
|
226
|
+
if (!(this instanceof AudioBufferSourceNode)) {
|
|
227
|
+
throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioBufferSourceNode\'');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
return this[kNapiObj].loopStart;
|
|
231
|
+
}
|
|
232
|
+
|
|
85
233
|
set loopStart(value) {
|
|
234
|
+
if (!(this instanceof AudioBufferSourceNode)) {
|
|
235
|
+
throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioBufferSourceNode\'');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
value = conversions['double'](value, {
|
|
239
|
+
context: `Failed to set the 'loopStart' property on 'AudioBufferSourceNode': Value`,
|
|
240
|
+
});
|
|
241
|
+
|
|
86
242
|
try {
|
|
87
|
-
|
|
243
|
+
this[kNapiObj].loopStart = value;
|
|
88
244
|
} catch (err) {
|
|
89
245
|
throwSanitizedError(err);
|
|
90
246
|
}
|
|
91
247
|
}
|
|
92
248
|
|
|
249
|
+
get loopEnd() {
|
|
250
|
+
if (!(this instanceof AudioBufferSourceNode)) {
|
|
251
|
+
throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioBufferSourceNode\'');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return this[kNapiObj].loopEnd;
|
|
255
|
+
}
|
|
256
|
+
|
|
93
257
|
set loopEnd(value) {
|
|
258
|
+
if (!(this instanceof AudioBufferSourceNode)) {
|
|
259
|
+
throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioBufferSourceNode\'');
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
value = conversions['double'](value, {
|
|
263
|
+
context: `Failed to set the 'loopEnd' property on 'AudioBufferSourceNode': Value`,
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
this[kNapiObj].loopEnd = value;
|
|
268
|
+
} catch (err) {
|
|
269
|
+
throwSanitizedError(err);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
start(when = 0, offset = null, duration = null) {
|
|
274
|
+
if (!(this instanceof AudioBufferSourceNode)) {
|
|
275
|
+
throw new TypeError('Invalid Invocation: Value of \'this\' must be of type \'AudioBufferSourceNode\'');
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (when !== 0) {
|
|
279
|
+
when = conversions['double'](when, {
|
|
280
|
+
context: `Failed to execute 'start' on 'AudioBufferSourceNode': Parameter 1`,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (offset !== null) {
|
|
285
|
+
offset = conversions['double'](offset, {
|
|
286
|
+
context: `Failed to execute 'start' on 'AudioBufferSourceNode': Parameter 2`,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (duration !== null) {
|
|
291
|
+
duration = conversions['double'](duration, {
|
|
292
|
+
context: `Failed to execute 'start' on 'AudioBufferSourceNode': Parameter 3`,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
94
296
|
try {
|
|
95
|
-
|
|
297
|
+
return this[kNapiObj].start(when, offset, duration);
|
|
96
298
|
} catch (err) {
|
|
97
299
|
throwSanitizedError(err);
|
|
98
300
|
}
|
|
99
301
|
}
|
|
100
302
|
|
|
101
|
-
// methods
|
|
102
|
-
|
|
103
303
|
}
|
|
104
304
|
|
|
105
|
-
|
|
106
|
-
|
|
305
|
+
Object.defineProperties(AudioBufferSourceNode, {
|
|
306
|
+
length: {
|
|
307
|
+
__proto__: null,
|
|
308
|
+
writable: false,
|
|
309
|
+
enumerable: false,
|
|
310
|
+
configurable: true,
|
|
311
|
+
value: 1,
|
|
312
|
+
},
|
|
313
|
+
});
|
|
107
314
|
|
|
315
|
+
Object.defineProperties(AudioBufferSourceNode.prototype, {
|
|
316
|
+
[Symbol.toStringTag]: {
|
|
317
|
+
__proto__: null,
|
|
318
|
+
writable: false,
|
|
319
|
+
enumerable: false,
|
|
320
|
+
configurable: true,
|
|
321
|
+
value: 'AudioBufferSourceNode',
|
|
322
|
+
},
|
|
323
|
+
playbackRate: kEnumerableProperty,
|
|
324
|
+
detune: kEnumerableProperty,
|
|
325
|
+
buffer: kEnumerableProperty,
|
|
326
|
+
loop: kEnumerableProperty,
|
|
327
|
+
loopStart: kEnumerableProperty,
|
|
328
|
+
loopEnd: kEnumerableProperty,
|
|
329
|
+
start: kEnumerableProperty,
|
|
330
|
+
});
|
|
108
331
|
|
|
109
|
-
|
|
332
|
+
return AudioBufferSourceNode;
|
|
333
|
+
};
|