@mulsense/xnew 0.4.3 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,53 @@
1
+ declare const _default: {
2
+ load(path: string): {
3
+ promise: Promise<any>;
4
+ component: Function | null;
5
+ then(callback: Function): /*elided*/ any;
6
+ catch(callback: Function): /*elided*/ any;
7
+ finally(callback: Function): /*elided*/ any;
8
+ };
9
+ synthesizer(props: SynthesizerOptions): Synthesizer;
10
+ volume: number;
11
+ };
12
+
13
+ type SynthesizerOptions = {
14
+ oscillator: OscillatorOptions;
15
+ amp: AmpOptions;
16
+ filter?: FilterOptions;
17
+ reverb?: ReverbOptions;
18
+ bpm?: number;
19
+ };
20
+ type OscillatorOptions = {
21
+ type: OscillatorType;
22
+ envelope?: Envelope;
23
+ LFO?: LFO;
24
+ };
25
+ type FilterOptions = {
26
+ type: BiquadFilterType;
27
+ cutoff: number;
28
+ };
29
+ type AmpOptions = {
30
+ envelope: Envelope;
31
+ };
32
+ type ReverbOptions = {
33
+ time: number;
34
+ mix: number;
35
+ };
36
+ type Envelope = {
37
+ amount: number;
38
+ ADSR: [number, number, number, number];
39
+ };
40
+ type LFO = {
41
+ amount: number;
42
+ type: OscillatorType;
43
+ rate: number;
44
+ };
45
+ declare class Synthesizer {
46
+ props: SynthesizerOptions;
47
+ constructor(props: SynthesizerOptions);
48
+ press(frequency: number | string, duration?: number | string, wait?: number): {
49
+ release: () => void;
50
+ } | undefined;
51
+ }
52
+
53
+ export { _default as default };
@@ -0,0 +1,256 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@mulsense/xnew')) :
3
+ typeof define === 'function' && define.amd ? define(['@mulsense/xnew'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.xaudio = factory(global.xnew));
5
+ })(this, (function (xnew) { 'use strict';
6
+
7
+ var xaudio = {
8
+ load(path) {
9
+ const music = new AudioFile(path);
10
+ const object = {
11
+ play(options) {
12
+ const unit = xnew();
13
+ if (music.played === null) {
14
+ music.play(options);
15
+ unit.on('finalize', () => music.pause({ fade: options.fade }));
16
+ }
17
+ },
18
+ pause(options) {
19
+ music.pause(options);
20
+ }
21
+ };
22
+ return xnew.promise(music.promise).then(() => object);
23
+ },
24
+ synthesizer(props) {
25
+ return new Synthesizer(props);
26
+ },
27
+ get volume() {
28
+ return master.gain.value;
29
+ },
30
+ set volume(value) {
31
+ master.gain.value = value;
32
+ }
33
+ };
34
+ const context = window.AudioContext ? new window.AudioContext() : (null);
35
+ const master = context ? context.createGain() : (null);
36
+ if (context) {
37
+ master.gain.value = 0.1;
38
+ master.connect(context.destination);
39
+ }
40
+ class AudioFile {
41
+ constructor(path) {
42
+ this.promise = fetch(path)
43
+ .then((response) => response.arrayBuffer())
44
+ .then((response) => context.decodeAudioData(response))
45
+ .then((response) => { this.buffer = response; })
46
+ .catch(() => {
47
+ console.warn(`"${path}" could not be loaded.`);
48
+ });
49
+ this.amp = context.createGain();
50
+ this.amp.gain.value = 1.0;
51
+ this.amp.connect(master);
52
+ this.fade = context.createGain();
53
+ this.fade.gain.value = 1.0;
54
+ this.fade.connect(this.amp);
55
+ this.source = null;
56
+ this.played = null;
57
+ }
58
+ set volume(value) {
59
+ this.amp.gain.value = value;
60
+ }
61
+ get volume() {
62
+ return this.amp.gain.value;
63
+ }
64
+ play({ offset = 0, fade = 0, loop = false } = {}) {
65
+ if (this.buffer !== undefined && this.played === null) {
66
+ this.source = context.createBufferSource();
67
+ this.source.buffer = this.buffer;
68
+ this.source.loop = loop;
69
+ this.source.connect(this.fade);
70
+ this.played = context.currentTime;
71
+ this.source.playbackRate.value = 1;
72
+ this.source.start(context.currentTime, offset / 1000);
73
+ // Apply fade-in effect if fade duration is specified
74
+ if (fade > 0) {
75
+ this.fade.gain.setValueAtTime(0, context.currentTime);
76
+ this.fade.gain.linearRampToValueAtTime(1.0, context.currentTime + fade / 1000);
77
+ }
78
+ this.source.onended = () => {
79
+ var _a;
80
+ this.played = null;
81
+ (_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
82
+ this.source = null;
83
+ };
84
+ }
85
+ }
86
+ pause({ fade = 0 } = {}) {
87
+ var _a, _b;
88
+ if (this.buffer !== undefined && this.played !== null) {
89
+ const elapsed = (context.currentTime - this.played) % this.buffer.duration * 1000;
90
+ // Apply fade-out effect if fade duration is specified
91
+ if (fade > 0) {
92
+ this.fade.gain.setValueAtTime(1.0, context.currentTime);
93
+ this.fade.gain.linearRampToValueAtTime(0, context.currentTime + fade / 1000);
94
+ (_a = this.source) === null || _a === void 0 ? void 0 : _a.stop(context.currentTime + fade / 1000);
95
+ }
96
+ else {
97
+ (_b = this.source) === null || _b === void 0 ? void 0 : _b.stop(context.currentTime);
98
+ }
99
+ this.played = null;
100
+ return elapsed;
101
+ }
102
+ }
103
+ clear() {
104
+ var _a;
105
+ this.amp.disconnect();
106
+ this.fade.disconnect();
107
+ (_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
108
+ }
109
+ }
110
+ const keymap = {
111
+ 'A0': 27.500, 'A#0': 29.135, 'B0': 30.868,
112
+ 'C1': 32.703, 'C#1': 34.648, 'D1': 36.708, 'D#1': 38.891, 'E1': 41.203, 'F1': 43.654, 'F#1': 46.249, 'G1': 48.999, 'G#1': 51.913, 'A1': 55.000, 'A#1': 58.270, 'B1': 61.735,
113
+ 'C2': 65.406, 'C#2': 69.296, 'D2': 73.416, 'D#2': 77.782, 'E2': 82.407, 'F2': 87.307, 'F#2': 92.499, 'G2': 97.999, 'G#2': 103.826, 'A2': 110.000, 'A#2': 116.541, 'B2': 123.471,
114
+ 'C3': 130.813, 'C#3': 138.591, 'D3': 146.832, 'D#3': 155.563, 'E3': 164.814, 'F3': 174.614, 'F#3': 184.997, 'G3': 195.998, 'G#3': 207.652, 'A3': 220.000, 'A#3': 233.082, 'B3': 246.942,
115
+ 'C4': 261.626, 'C#4': 277.183, 'D4': 293.665, 'D#4': 311.127, 'E4': 329.628, 'F4': 349.228, 'F#4': 369.994, 'G4': 391.995, 'G#4': 415.305, 'A4': 440.000, 'A#4': 466.164, 'B4': 493.883,
116
+ 'C5': 523.251, 'C#5': 554.365, 'D5': 587.330, 'D#5': 622.254, 'E5': 659.255, 'F5': 698.456, 'F#5': 739.989, 'G5': 783.991, 'G#5': 830.609, 'A5': 880.000, 'A#5': 932.328, 'B5': 987.767,
117
+ 'C6': 1046.502, 'C#6': 1108.731, 'D6': 1174.659, 'D#6': 1244.508, 'E6': 1318.510, 'F6': 1396.913, 'F#6': 1479.978, 'G6': 1567.982, 'G#6': 1661.219, 'A6': 1760.000, 'A#6': 1864.655, 'B6': 1975.533,
118
+ 'C7': 2093.005, 'C#7': 2217.461, 'D7': 2349.318, 'D#7': 2489.016, 'E7': 2637.020, 'F7': 2793.826, 'F#7': 2959.955, 'G7': 3135.963, 'G#7': 3322.438, 'A7': 3520.000, 'A#7': 3729.310, 'B7': 3951.066,
119
+ 'C8': 4186.009,
120
+ };
121
+ const notemap = {
122
+ '1m': 4.000, '2n': 2.000, '4n': 1.000, '8n': 0.500, '16n': 0.250, '32n': 0.125,
123
+ };
124
+ class Synthesizer {
125
+ constructor(props) { this.props = props; }
126
+ press(frequency, duration, wait) {
127
+ var _a;
128
+ const props = this.props;
129
+ const fv = typeof frequency === 'string' ? keymap[frequency] : frequency;
130
+ const dv = typeof duration === 'string' ? (notemap[duration] * 60 / ((_a = props.bpm) !== null && _a !== void 0 ? _a : 120)) : (typeof duration === 'number' ? (duration / 1000) : 0);
131
+ const start = context.currentTime + (wait !== null && wait !== void 0 ? wait : 0) / 1000;
132
+ const nodes = {};
133
+ nodes.oscillator = context.createOscillator();
134
+ nodes.oscillator.type = props.oscillator.type;
135
+ nodes.oscillator.frequency.value = fv;
136
+ if (props.oscillator.LFO) {
137
+ nodes.oscillatorLFO = context.createOscillator();
138
+ nodes.oscillatorLFODepth = context.createGain();
139
+ nodes.oscillatorLFODepth.gain.value = fv * (Math.pow(2.0, props.oscillator.LFO.amount / 12.0) - 1.0);
140
+ nodes.oscillatorLFO.type = props.oscillator.LFO.type;
141
+ nodes.oscillatorLFO.frequency.value = props.oscillator.LFO.rate;
142
+ nodes.oscillatorLFO.start(start);
143
+ nodes.oscillatorLFO.connect(nodes.oscillatorLFODepth);
144
+ nodes.oscillatorLFODepth.connect(nodes.oscillator.frequency);
145
+ }
146
+ nodes.amp = context.createGain();
147
+ nodes.amp.gain.value = 0.0;
148
+ nodes.target = context.createGain();
149
+ nodes.target.gain.value = 1.0;
150
+ nodes.amp.connect(nodes.target);
151
+ nodes.target.connect(master);
152
+ if (props.filter) {
153
+ nodes.filter = context.createBiquadFilter();
154
+ nodes.filter.type = props.filter.type;
155
+ nodes.filter.frequency.value = props.filter.cutoff;
156
+ nodes.oscillator.connect(nodes.filter);
157
+ nodes.filter.connect(nodes.amp);
158
+ }
159
+ else {
160
+ nodes.oscillator.connect(nodes.amp);
161
+ }
162
+ if (props.reverb) {
163
+ nodes.convolver = context.createConvolver();
164
+ nodes.convolver.buffer = impulseResponse({ time: props.reverb.time });
165
+ nodes.convolverDepth = context.createGain();
166
+ nodes.convolverDepth.gain.value = 1.0;
167
+ nodes.convolverDepth.gain.value *= props.reverb.mix;
168
+ nodes.target.gain.value *= (1.0 - props.reverb.mix);
169
+ nodes.amp.connect(nodes.convolver);
170
+ nodes.convolver.connect(nodes.convolverDepth);
171
+ nodes.convolverDepth.connect(master);
172
+ }
173
+ if (props.oscillator.envelope) {
174
+ const amount = fv * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
175
+ startEnvelope(nodes.oscillator.frequency, fv, amount, props.oscillator.envelope.ADSR);
176
+ }
177
+ if (props.amp.envelope) {
178
+ startEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
179
+ }
180
+ nodes.oscillator.start(start);
181
+ if (dv > 0) {
182
+ release();
183
+ }
184
+ else {
185
+ return { release };
186
+ }
187
+ function release() {
188
+ let stop = null;
189
+ const end = dv > 0 ? dv : (context.currentTime - start);
190
+ if (props.amp.envelope) {
191
+ const ADSR = props.amp.envelope.ADSR;
192
+ const adsr = [ADSR[0] / 1000, ADSR[1] / 1000, ADSR[2], ADSR[3] / 1000];
193
+ const rate = adsr[0] === 0.0 ? 1.0 : Math.min(end / (adsr[0] + 0.001), 1.0);
194
+ stop = start + Math.max((adsr[0] + adsr[1]) * rate, end) + adsr[3];
195
+ }
196
+ else {
197
+ stop = start + end;
198
+ }
199
+ if (nodes.oscillatorLFO) {
200
+ nodes.oscillatorLFO.stop(stop);
201
+ }
202
+ if (props.oscillator.envelope) {
203
+ const amount = fv * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
204
+ stopEnvelope(nodes.oscillator.frequency, fv, amount, props.oscillator.envelope.ADSR);
205
+ }
206
+ if (props.amp.envelope) {
207
+ stopEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
208
+ }
209
+ nodes.oscillator.stop(stop);
210
+ setTimeout(() => {
211
+ var _a, _b, _c, _d, _e;
212
+ nodes.oscillator.disconnect();
213
+ nodes.amp.disconnect();
214
+ nodes.target.disconnect();
215
+ (_a = nodes.oscillatorLFO) === null || _a === void 0 ? void 0 : _a.disconnect();
216
+ (_b = nodes.oscillatorLFODepth) === null || _b === void 0 ? void 0 : _b.disconnect();
217
+ (_c = nodes.filter) === null || _c === void 0 ? void 0 : _c.disconnect();
218
+ (_d = nodes.convolver) === null || _d === void 0 ? void 0 : _d.disconnect();
219
+ (_e = nodes.convolverDepth) === null || _e === void 0 ? void 0 : _e.disconnect();
220
+ }, 2000);
221
+ }
222
+ function stopEnvelope(param, base, amount, ADSR) {
223
+ const end = dv > 0 ? dv : (context.currentTime - start);
224
+ const rate = ADSR[0] === 0.0 ? 1.0 : Math.min(end / (ADSR[0] / 1000), 1.0);
225
+ if (rate < 1.0) {
226
+ param.cancelScheduledValues(start);
227
+ param.setValueAtTime(base, start);
228
+ param.linearRampToValueAtTime(base + amount * rate, start + ADSR[0] / 1000 * rate);
229
+ param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000 * rate);
230
+ }
231
+ param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, dv));
232
+ param.linearRampToValueAtTime(base, start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, end) + ADSR[3] / 1000);
233
+ }
234
+ function startEnvelope(param, base, amount, ADSR) {
235
+ param.value = base;
236
+ param.setValueAtTime(base, start);
237
+ param.linearRampToValueAtTime(base + amount, start + ADSR[0] / 1000);
238
+ param.linearRampToValueAtTime(base + amount * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000);
239
+ }
240
+ function impulseResponse({ time, decay = 2.0 }) {
241
+ const length = context.sampleRate * time / 1000;
242
+ const impulse = context.createBuffer(2, length, context.sampleRate);
243
+ const ch0 = impulse.getChannelData(0);
244
+ const ch1 = impulse.getChannelData(1);
245
+ for (let i = 0; i < length; i++) {
246
+ ch0[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
247
+ ch1[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
248
+ }
249
+ return impulse;
250
+ }
251
+ }
252
+ }
253
+
254
+ return xaudio;
255
+
256
+ }));
@@ -0,0 +1,250 @@
1
+ import xnew from '@mulsense/xnew';
2
+
3
+ var xaudio = {
4
+ load(path) {
5
+ const music = new AudioFile(path);
6
+ const object = {
7
+ play(options) {
8
+ const unit = xnew();
9
+ if (music.played === null) {
10
+ music.play(options);
11
+ unit.on('finalize', () => music.pause({ fade: options.fade }));
12
+ }
13
+ },
14
+ pause(options) {
15
+ music.pause(options);
16
+ }
17
+ };
18
+ return xnew.promise(music.promise).then(() => object);
19
+ },
20
+ synthesizer(props) {
21
+ return new Synthesizer(props);
22
+ },
23
+ get volume() {
24
+ return master.gain.value;
25
+ },
26
+ set volume(value) {
27
+ master.gain.value = value;
28
+ }
29
+ };
30
+ const context = window.AudioContext ? new window.AudioContext() : (null);
31
+ const master = context ? context.createGain() : (null);
32
+ if (context) {
33
+ master.gain.value = 0.1;
34
+ master.connect(context.destination);
35
+ }
36
+ class AudioFile {
37
+ constructor(path) {
38
+ this.promise = fetch(path)
39
+ .then((response) => response.arrayBuffer())
40
+ .then((response) => context.decodeAudioData(response))
41
+ .then((response) => { this.buffer = response; })
42
+ .catch(() => {
43
+ console.warn(`"${path}" could not be loaded.`);
44
+ });
45
+ this.amp = context.createGain();
46
+ this.amp.gain.value = 1.0;
47
+ this.amp.connect(master);
48
+ this.fade = context.createGain();
49
+ this.fade.gain.value = 1.0;
50
+ this.fade.connect(this.amp);
51
+ this.source = null;
52
+ this.played = null;
53
+ }
54
+ set volume(value) {
55
+ this.amp.gain.value = value;
56
+ }
57
+ get volume() {
58
+ return this.amp.gain.value;
59
+ }
60
+ play({ offset = 0, fade = 0, loop = false } = {}) {
61
+ if (this.buffer !== undefined && this.played === null) {
62
+ this.source = context.createBufferSource();
63
+ this.source.buffer = this.buffer;
64
+ this.source.loop = loop;
65
+ this.source.connect(this.fade);
66
+ this.played = context.currentTime;
67
+ this.source.playbackRate.value = 1;
68
+ this.source.start(context.currentTime, offset / 1000);
69
+ // Apply fade-in effect if fade duration is specified
70
+ if (fade > 0) {
71
+ this.fade.gain.setValueAtTime(0, context.currentTime);
72
+ this.fade.gain.linearRampToValueAtTime(1.0, context.currentTime + fade / 1000);
73
+ }
74
+ this.source.onended = () => {
75
+ var _a;
76
+ this.played = null;
77
+ (_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
78
+ this.source = null;
79
+ };
80
+ }
81
+ }
82
+ pause({ fade = 0 } = {}) {
83
+ var _a, _b;
84
+ if (this.buffer !== undefined && this.played !== null) {
85
+ const elapsed = (context.currentTime - this.played) % this.buffer.duration * 1000;
86
+ // Apply fade-out effect if fade duration is specified
87
+ if (fade > 0) {
88
+ this.fade.gain.setValueAtTime(1.0, context.currentTime);
89
+ this.fade.gain.linearRampToValueAtTime(0, context.currentTime + fade / 1000);
90
+ (_a = this.source) === null || _a === void 0 ? void 0 : _a.stop(context.currentTime + fade / 1000);
91
+ }
92
+ else {
93
+ (_b = this.source) === null || _b === void 0 ? void 0 : _b.stop(context.currentTime);
94
+ }
95
+ this.played = null;
96
+ return elapsed;
97
+ }
98
+ }
99
+ clear() {
100
+ var _a;
101
+ this.amp.disconnect();
102
+ this.fade.disconnect();
103
+ (_a = this.source) === null || _a === void 0 ? void 0 : _a.disconnect();
104
+ }
105
+ }
106
+ const keymap = {
107
+ 'A0': 27.500, 'A#0': 29.135, 'B0': 30.868,
108
+ 'C1': 32.703, 'C#1': 34.648, 'D1': 36.708, 'D#1': 38.891, 'E1': 41.203, 'F1': 43.654, 'F#1': 46.249, 'G1': 48.999, 'G#1': 51.913, 'A1': 55.000, 'A#1': 58.270, 'B1': 61.735,
109
+ 'C2': 65.406, 'C#2': 69.296, 'D2': 73.416, 'D#2': 77.782, 'E2': 82.407, 'F2': 87.307, 'F#2': 92.499, 'G2': 97.999, 'G#2': 103.826, 'A2': 110.000, 'A#2': 116.541, 'B2': 123.471,
110
+ 'C3': 130.813, 'C#3': 138.591, 'D3': 146.832, 'D#3': 155.563, 'E3': 164.814, 'F3': 174.614, 'F#3': 184.997, 'G3': 195.998, 'G#3': 207.652, 'A3': 220.000, 'A#3': 233.082, 'B3': 246.942,
111
+ 'C4': 261.626, 'C#4': 277.183, 'D4': 293.665, 'D#4': 311.127, 'E4': 329.628, 'F4': 349.228, 'F#4': 369.994, 'G4': 391.995, 'G#4': 415.305, 'A4': 440.000, 'A#4': 466.164, 'B4': 493.883,
112
+ 'C5': 523.251, 'C#5': 554.365, 'D5': 587.330, 'D#5': 622.254, 'E5': 659.255, 'F5': 698.456, 'F#5': 739.989, 'G5': 783.991, 'G#5': 830.609, 'A5': 880.000, 'A#5': 932.328, 'B5': 987.767,
113
+ 'C6': 1046.502, 'C#6': 1108.731, 'D6': 1174.659, 'D#6': 1244.508, 'E6': 1318.510, 'F6': 1396.913, 'F#6': 1479.978, 'G6': 1567.982, 'G#6': 1661.219, 'A6': 1760.000, 'A#6': 1864.655, 'B6': 1975.533,
114
+ 'C7': 2093.005, 'C#7': 2217.461, 'D7': 2349.318, 'D#7': 2489.016, 'E7': 2637.020, 'F7': 2793.826, 'F#7': 2959.955, 'G7': 3135.963, 'G#7': 3322.438, 'A7': 3520.000, 'A#7': 3729.310, 'B7': 3951.066,
115
+ 'C8': 4186.009,
116
+ };
117
+ const notemap = {
118
+ '1m': 4.000, '2n': 2.000, '4n': 1.000, '8n': 0.500, '16n': 0.250, '32n': 0.125,
119
+ };
120
+ class Synthesizer {
121
+ constructor(props) { this.props = props; }
122
+ press(frequency, duration, wait) {
123
+ var _a;
124
+ const props = this.props;
125
+ const fv = typeof frequency === 'string' ? keymap[frequency] : frequency;
126
+ const dv = typeof duration === 'string' ? (notemap[duration] * 60 / ((_a = props.bpm) !== null && _a !== void 0 ? _a : 120)) : (typeof duration === 'number' ? (duration / 1000) : 0);
127
+ const start = context.currentTime + (wait !== null && wait !== void 0 ? wait : 0) / 1000;
128
+ const nodes = {};
129
+ nodes.oscillator = context.createOscillator();
130
+ nodes.oscillator.type = props.oscillator.type;
131
+ nodes.oscillator.frequency.value = fv;
132
+ if (props.oscillator.LFO) {
133
+ nodes.oscillatorLFO = context.createOscillator();
134
+ nodes.oscillatorLFODepth = context.createGain();
135
+ nodes.oscillatorLFODepth.gain.value = fv * (Math.pow(2.0, props.oscillator.LFO.amount / 12.0) - 1.0);
136
+ nodes.oscillatorLFO.type = props.oscillator.LFO.type;
137
+ nodes.oscillatorLFO.frequency.value = props.oscillator.LFO.rate;
138
+ nodes.oscillatorLFO.start(start);
139
+ nodes.oscillatorLFO.connect(nodes.oscillatorLFODepth);
140
+ nodes.oscillatorLFODepth.connect(nodes.oscillator.frequency);
141
+ }
142
+ nodes.amp = context.createGain();
143
+ nodes.amp.gain.value = 0.0;
144
+ nodes.target = context.createGain();
145
+ nodes.target.gain.value = 1.0;
146
+ nodes.amp.connect(nodes.target);
147
+ nodes.target.connect(master);
148
+ if (props.filter) {
149
+ nodes.filter = context.createBiquadFilter();
150
+ nodes.filter.type = props.filter.type;
151
+ nodes.filter.frequency.value = props.filter.cutoff;
152
+ nodes.oscillator.connect(nodes.filter);
153
+ nodes.filter.connect(nodes.amp);
154
+ }
155
+ else {
156
+ nodes.oscillator.connect(nodes.amp);
157
+ }
158
+ if (props.reverb) {
159
+ nodes.convolver = context.createConvolver();
160
+ nodes.convolver.buffer = impulseResponse({ time: props.reverb.time });
161
+ nodes.convolverDepth = context.createGain();
162
+ nodes.convolverDepth.gain.value = 1.0;
163
+ nodes.convolverDepth.gain.value *= props.reverb.mix;
164
+ nodes.target.gain.value *= (1.0 - props.reverb.mix);
165
+ nodes.amp.connect(nodes.convolver);
166
+ nodes.convolver.connect(nodes.convolverDepth);
167
+ nodes.convolverDepth.connect(master);
168
+ }
169
+ if (props.oscillator.envelope) {
170
+ const amount = fv * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
171
+ startEnvelope(nodes.oscillator.frequency, fv, amount, props.oscillator.envelope.ADSR);
172
+ }
173
+ if (props.amp.envelope) {
174
+ startEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
175
+ }
176
+ nodes.oscillator.start(start);
177
+ if (dv > 0) {
178
+ release();
179
+ }
180
+ else {
181
+ return { release };
182
+ }
183
+ function release() {
184
+ let stop = null;
185
+ const end = dv > 0 ? dv : (context.currentTime - start);
186
+ if (props.amp.envelope) {
187
+ const ADSR = props.amp.envelope.ADSR;
188
+ const adsr = [ADSR[0] / 1000, ADSR[1] / 1000, ADSR[2], ADSR[3] / 1000];
189
+ const rate = adsr[0] === 0.0 ? 1.0 : Math.min(end / (adsr[0] + 0.001), 1.0);
190
+ stop = start + Math.max((adsr[0] + adsr[1]) * rate, end) + adsr[3];
191
+ }
192
+ else {
193
+ stop = start + end;
194
+ }
195
+ if (nodes.oscillatorLFO) {
196
+ nodes.oscillatorLFO.stop(stop);
197
+ }
198
+ if (props.oscillator.envelope) {
199
+ const amount = fv * (Math.pow(2.0, props.oscillator.envelope.amount / 12.0) - 1.0);
200
+ stopEnvelope(nodes.oscillator.frequency, fv, amount, props.oscillator.envelope.ADSR);
201
+ }
202
+ if (props.amp.envelope) {
203
+ stopEnvelope(nodes.amp.gain, 0.0, props.amp.envelope.amount, props.amp.envelope.ADSR);
204
+ }
205
+ nodes.oscillator.stop(stop);
206
+ setTimeout(() => {
207
+ var _a, _b, _c, _d, _e;
208
+ nodes.oscillator.disconnect();
209
+ nodes.amp.disconnect();
210
+ nodes.target.disconnect();
211
+ (_a = nodes.oscillatorLFO) === null || _a === void 0 ? void 0 : _a.disconnect();
212
+ (_b = nodes.oscillatorLFODepth) === null || _b === void 0 ? void 0 : _b.disconnect();
213
+ (_c = nodes.filter) === null || _c === void 0 ? void 0 : _c.disconnect();
214
+ (_d = nodes.convolver) === null || _d === void 0 ? void 0 : _d.disconnect();
215
+ (_e = nodes.convolverDepth) === null || _e === void 0 ? void 0 : _e.disconnect();
216
+ }, 2000);
217
+ }
218
+ function stopEnvelope(param, base, amount, ADSR) {
219
+ const end = dv > 0 ? dv : (context.currentTime - start);
220
+ const rate = ADSR[0] === 0.0 ? 1.0 : Math.min(end / (ADSR[0] / 1000), 1.0);
221
+ if (rate < 1.0) {
222
+ param.cancelScheduledValues(start);
223
+ param.setValueAtTime(base, start);
224
+ param.linearRampToValueAtTime(base + amount * rate, start + ADSR[0] / 1000 * rate);
225
+ param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000 * rate);
226
+ }
227
+ param.linearRampToValueAtTime(base + amount * rate * ADSR[2], start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, dv));
228
+ param.linearRampToValueAtTime(base, start + Math.max((ADSR[0] + ADSR[1]) / 1000 * rate, end) + ADSR[3] / 1000);
229
+ }
230
+ function startEnvelope(param, base, amount, ADSR) {
231
+ param.value = base;
232
+ param.setValueAtTime(base, start);
233
+ param.linearRampToValueAtTime(base + amount, start + ADSR[0] / 1000);
234
+ param.linearRampToValueAtTime(base + amount * ADSR[2], start + (ADSR[0] + ADSR[1]) / 1000);
235
+ }
236
+ function impulseResponse({ time, decay = 2.0 }) {
237
+ const length = context.sampleRate * time / 1000;
238
+ const impulse = context.createBuffer(2, length, context.sampleRate);
239
+ const ch0 = impulse.getChannelData(0);
240
+ const ch1 = impulse.getChannelData(1);
241
+ for (let i = 0; i < length; i++) {
242
+ ch0[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
243
+ ch1[i] = (2 * Math.random() - 1) * Math.pow(1 - i / length, decay);
244
+ }
245
+ return impulse;
246
+ }
247
+ }
248
+ }
249
+
250
+ export { xaudio as default };