@tsparticles/plugin-sounds 3.0.2 → 3.1.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/browser/Options/Classes/Sounds.js +4 -0
- package/browser/Options/Classes/SoundsEvent.js +4 -3
- package/browser/Options/Classes/SoundsIcon.js +1 -0
- package/browser/Options/Classes/SoundsIcons.js +4 -0
- package/browser/SoundsInstance.js +130 -69
- package/browser/index.js +13 -0
- package/browser/utils.js +11 -4
- package/cjs/Options/Classes/Sounds.js +4 -0
- package/cjs/Options/Classes/SoundsEvent.js +4 -3
- package/cjs/Options/Classes/SoundsIcon.js +1 -0
- package/cjs/Options/Classes/SoundsIcons.js +4 -0
- package/cjs/SoundsInstance.js +128 -67
- package/cjs/index.js +13 -0
- package/cjs/utils.js +14 -5
- package/esm/Options/Classes/Sounds.js +4 -0
- package/esm/Options/Classes/SoundsEvent.js +4 -3
- package/esm/Options/Classes/SoundsIcon.js +1 -0
- package/esm/Options/Classes/SoundsIcons.js +4 -0
- package/esm/SoundsInstance.js +130 -69
- package/esm/index.js +13 -0
- package/esm/utils.js +11 -4
- package/package.json +2 -2
- package/report.html +2 -2
- package/tsparticles.plugin.sounds.js +180 -77
- package/tsparticles.plugin.sounds.min.js +1 -1
- package/tsparticles.plugin.sounds.min.js.LICENSE.txt +1 -1
- package/types/Options/Classes/Sounds.d.ts +1 -0
- package/types/Options/Classes/SoundsEvent.d.ts +0 -5
- package/types/Options/Classes/SoundsIcon.d.ts +1 -0
- package/types/Options/Classes/SoundsIcons.d.ts +1 -0
- package/types/Options/Interfaces/ISounds.d.ts +1 -0
- package/types/Options/Interfaces/ISoundsIcon.d.ts +1 -0
- package/types/Options/Interfaces/ISoundsIcons.d.ts +1 -0
- package/types/SoundsInstance.d.ts +6 -0
- package/types/index.d.ts +1 -1
- package/types/types.d.ts +5 -5
- package/types/utils.d.ts +2 -0
- package/umd/Options/Classes/Sounds.js +4 -0
- package/umd/Options/Classes/SoundsEvent.js +4 -3
- package/umd/Options/Classes/SoundsIcon.js +1 -0
- package/umd/Options/Classes/SoundsIcons.js +4 -0
- package/umd/SoundsInstance.js +128 -67
- package/umd/index.js +14 -1
- package/umd/utils.js +14 -5
|
@@ -3,6 +3,7 @@ import { SoundsIcons } from "./SoundsIcons.js";
|
|
|
3
3
|
import { SoundsVolume } from "./SoundsVolume.js";
|
|
4
4
|
export class Sounds {
|
|
5
5
|
constructor() {
|
|
6
|
+
this.autoPlay = true;
|
|
6
7
|
this.enable = false;
|
|
7
8
|
this.events = [];
|
|
8
9
|
this.icons = new SoundsIcons();
|
|
@@ -12,6 +13,9 @@ export class Sounds {
|
|
|
12
13
|
if (!data) {
|
|
13
14
|
return;
|
|
14
15
|
}
|
|
16
|
+
if (data.autoPlay !== undefined) {
|
|
17
|
+
this.autoPlay = data.autoPlay;
|
|
18
|
+
}
|
|
15
19
|
if (data.enable !== undefined) {
|
|
16
20
|
this.enable = data.enable;
|
|
17
21
|
}
|
|
@@ -41,10 +41,11 @@ export class SoundsEvent {
|
|
|
41
41
|
return tmp;
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
|
-
if (data.filter
|
|
44
|
+
if (data.filter) {
|
|
45
45
|
if (isString(data.filter)) {
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
const filterFunc = window[data.filter];
|
|
47
|
+
if (isFunction(filterFunc)) {
|
|
48
|
+
this.filter = filterFunc;
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
else {
|
|
@@ -5,6 +5,7 @@ export class SoundsIcons {
|
|
|
5
5
|
this.unmute = new SoundsIcon();
|
|
6
6
|
this.volumeDown = new SoundsIcon();
|
|
7
7
|
this.volumeUp = new SoundsIcon();
|
|
8
|
+
this.enable = false;
|
|
8
9
|
this.mute.svg = `<?xml version="1.0"?>
|
|
9
10
|
<svg baseProfile="tiny" height="24px" version="1.2" viewBox="0 0 24 24" width="24px"
|
|
10
11
|
xml:space="preserve" xmlns="http://www.w3.org/2000/svg"
|
|
@@ -46,6 +47,9 @@ export class SoundsIcons {
|
|
|
46
47
|
if (!data) {
|
|
47
48
|
return;
|
|
48
49
|
}
|
|
50
|
+
if (data.enable !== undefined) {
|
|
51
|
+
this.enable = data.enable;
|
|
52
|
+
}
|
|
49
53
|
this.mute.load(data.mute);
|
|
50
54
|
this.unmute.load(data.unmute);
|
|
51
55
|
this.volumeDown.load(data.volumeDown);
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import { clamp, executeOnSingleOrMultiple, getLogger, isArray, isNumber, itemFromArray, itemFromSingleOrMultiple, } from "@tsparticles/engine";
|
|
2
|
-
import { getNoteFrequency } from "./utils.js";
|
|
1
|
+
import { clamp, executeOnSingleOrMultiple, getLogger, isArray, isNumber, itemFromArray, itemFromSingleOrMultiple, mouseDownEvent, percentDenominator, touchStartEvent, } from "@tsparticles/engine";
|
|
2
|
+
import { getNoteFrequency, isWindowMuted, unmuteWindow } from "./utils.js";
|
|
3
|
+
const zIndexOffset = 1, rightOffset = 1, minVolume = 0;
|
|
3
4
|
function initImage(data) {
|
|
4
|
-
const img = document.createElement("img"), { clickCb, container, display, iconOptions, margin, options, pos, rightOffsets } = data, { width, path, svg } = iconOptions;
|
|
5
|
-
setIconStyle(img, pos.top + margin, pos.right -
|
|
5
|
+
const img = document.createElement("img"), { clickCb, container, display, iconOptions, margin, options, pos, rightOffsets } = data, { width, path, style, svg } = iconOptions, defaultAccumulator = 0;
|
|
6
|
+
setIconStyle(img, pos.top + margin, pos.right -
|
|
7
|
+
(margin * (rightOffsets.length + rightOffset) +
|
|
8
|
+
width +
|
|
9
|
+
rightOffsets.reduce((a, b) => a + b, defaultAccumulator)), display, options.fullScreen.zIndex + zIndexOffset, width, margin, style);
|
|
6
10
|
img.src = path ?? (svg ? `data:image/svg+xml;base64,${btoa(svg)}` : "");
|
|
7
|
-
const parent = container.canvas.element?.parentNode
|
|
11
|
+
const parent = container.canvas.element?.parentNode ?? document.body;
|
|
8
12
|
parent.append(img);
|
|
9
|
-
img.addEventListener("click",
|
|
13
|
+
img.addEventListener("click", () => {
|
|
14
|
+
void clickCb();
|
|
15
|
+
});
|
|
10
16
|
return img;
|
|
11
17
|
}
|
|
12
18
|
function removeImage(image) {
|
|
@@ -15,14 +21,15 @@ function removeImage(image) {
|
|
|
15
21
|
}
|
|
16
22
|
image.remove();
|
|
17
23
|
}
|
|
18
|
-
function setIconStyle(icon, top, left, display, zIndex, width, margin) {
|
|
24
|
+
function setIconStyle(icon, top, left, display, zIndex, width, margin, style) {
|
|
19
25
|
icon.style.userSelect = "none";
|
|
20
26
|
icon.style.webkitUserSelect = "none";
|
|
21
27
|
icon.style.position = "absolute";
|
|
22
28
|
icon.style.top = `${top + margin}px`;
|
|
23
29
|
icon.style.left = `${left - margin - width}px`;
|
|
24
30
|
icon.style.display = display;
|
|
25
|
-
icon.style.zIndex = `${zIndex +
|
|
31
|
+
icon.style.zIndex = `${zIndex + zIndexOffset}`;
|
|
32
|
+
icon.style.cssText += style;
|
|
26
33
|
}
|
|
27
34
|
export class SoundsInstance {
|
|
28
35
|
constructor(container, engine) {
|
|
@@ -43,12 +50,12 @@ export class SoundsInstance {
|
|
|
43
50
|
}
|
|
44
51
|
for (const event of soundsOptions.events) {
|
|
45
52
|
const cb = (args) => {
|
|
46
|
-
(async () => {
|
|
53
|
+
void (async () => {
|
|
47
54
|
const filterNotValid = event.filter && !event.filter(args);
|
|
48
55
|
if (this._container !== args.container) {
|
|
49
56
|
return;
|
|
50
57
|
}
|
|
51
|
-
if (!this._container || this._container.muted || this._container.destroyed) {
|
|
58
|
+
if (!this._container || !!this._container.muted || this._container.destroyed) {
|
|
52
59
|
executeOnSingleOrMultiple(event.event, (item) => {
|
|
53
60
|
this._engine.removeEventListener(item, cb);
|
|
54
61
|
});
|
|
@@ -57,21 +64,22 @@ export class SoundsInstance {
|
|
|
57
64
|
if (filterNotValid) {
|
|
58
65
|
return;
|
|
59
66
|
}
|
|
67
|
+
const defaultNoteIndex = 0;
|
|
60
68
|
if (event.audio) {
|
|
61
69
|
this._playBuffer(itemFromSingleOrMultiple(event.audio));
|
|
62
70
|
}
|
|
63
71
|
else if (event.melodies) {
|
|
64
72
|
const melody = itemFromArray(event.melodies);
|
|
65
73
|
if (melody.melodies.length) {
|
|
66
|
-
await Promise.allSettled(melody.melodies.map((m) => this._playNote(m.notes,
|
|
74
|
+
await Promise.allSettled(melody.melodies.map((m) => this._playNote(m.notes, defaultNoteIndex, melody.loop)));
|
|
67
75
|
}
|
|
68
76
|
else {
|
|
69
|
-
await this._playNote(melody.notes,
|
|
77
|
+
await this._playNote(melody.notes, defaultNoteIndex, melody.loop);
|
|
70
78
|
}
|
|
71
79
|
}
|
|
72
80
|
else if (event.notes) {
|
|
73
81
|
const note = itemFromArray(event.notes);
|
|
74
|
-
await this._playNote([note],
|
|
82
|
+
await this._playNote([note], defaultNoteIndex, false);
|
|
75
83
|
}
|
|
76
84
|
})();
|
|
77
85
|
};
|
|
@@ -80,18 +88,15 @@ export class SoundsInstance {
|
|
|
80
88
|
});
|
|
81
89
|
}
|
|
82
90
|
};
|
|
83
|
-
this._mute = () => {
|
|
84
|
-
const container = this._container;
|
|
85
|
-
if (!container.audioContext) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
91
|
+
this._mute = async () => {
|
|
92
|
+
const container = this._container, audioContext = this._getAudioContext();
|
|
88
93
|
for (const source of this._audioSources) {
|
|
89
94
|
this._removeAudioSource(source);
|
|
90
95
|
}
|
|
91
96
|
if (this._gain) {
|
|
92
97
|
this._gain.disconnect();
|
|
93
98
|
}
|
|
94
|
-
|
|
99
|
+
await audioContext.close();
|
|
95
100
|
container.audioContext = undefined;
|
|
96
101
|
this._engine.dispatchEvent("soundsMuted", { container: this._container });
|
|
97
102
|
};
|
|
@@ -111,10 +116,10 @@ export class SoundsInstance {
|
|
|
111
116
|
source.start();
|
|
112
117
|
};
|
|
113
118
|
this._playFrequency = async (frequency, duration) => {
|
|
114
|
-
if (!this.
|
|
119
|
+
if (!this._gain || this._container.muted) {
|
|
115
120
|
return;
|
|
116
121
|
}
|
|
117
|
-
const oscillator = this._addOscillator(
|
|
122
|
+
const audioContext = this._getAudioContext(), oscillator = this._addOscillator(audioContext);
|
|
118
123
|
oscillator.connect(this._gain);
|
|
119
124
|
oscillator.type = "sine";
|
|
120
125
|
oscillator.frequency.value = frequency;
|
|
@@ -127,14 +132,13 @@ export class SoundsInstance {
|
|
|
127
132
|
});
|
|
128
133
|
};
|
|
129
134
|
this._playMuteSound = () => {
|
|
130
|
-
|
|
131
|
-
if (!container.audioContext) {
|
|
135
|
+
if (this._container.muted) {
|
|
132
136
|
return;
|
|
133
137
|
}
|
|
134
|
-
const gain =
|
|
135
|
-
gain.connect(
|
|
138
|
+
const audioContext = this._getAudioContext(), gain = audioContext.createGain();
|
|
139
|
+
gain.connect(audioContext.destination);
|
|
136
140
|
gain.gain.value = 0;
|
|
137
|
-
const oscillator =
|
|
141
|
+
const oscillator = audioContext.createOscillator();
|
|
138
142
|
oscillator.connect(gain);
|
|
139
143
|
oscillator.type = "sine";
|
|
140
144
|
oscillator.frequency.value = 1;
|
|
@@ -158,7 +162,8 @@ export class SoundsInstance {
|
|
|
158
162
|
return this._playNoteValue(notes, noteIdx, idx);
|
|
159
163
|
});
|
|
160
164
|
await (isArray(promises) ? Promise.allSettled(promises) : promises);
|
|
161
|
-
|
|
165
|
+
const indexOffset = 1;
|
|
166
|
+
let nextNoteIdx = noteIdx + indexOffset;
|
|
162
167
|
if (loop && nextNoteIdx >= notes.length) {
|
|
163
168
|
nextNoteIdx = nextNoteIdx % notes.length;
|
|
164
169
|
}
|
|
@@ -187,29 +192,31 @@ export class SoundsInstance {
|
|
|
187
192
|
this._removeAudioSource = (source) => {
|
|
188
193
|
source.stop();
|
|
189
194
|
source.disconnect();
|
|
190
|
-
|
|
195
|
+
const deleteCount = 1;
|
|
196
|
+
this._audioSources.splice(this._audioSources.indexOf(source), deleteCount);
|
|
191
197
|
};
|
|
192
198
|
this._unmute = () => {
|
|
193
199
|
const container = this._container, options = container.actualOptions, soundsOptions = options.sounds;
|
|
194
200
|
if (!soundsOptions) {
|
|
195
201
|
return;
|
|
196
202
|
}
|
|
197
|
-
|
|
198
|
-
container.audioContext = new AudioContext();
|
|
199
|
-
}
|
|
200
|
-
const { audioContext } = container;
|
|
203
|
+
const audioContext = this._getAudioContext();
|
|
201
204
|
if (!this._audioSources) {
|
|
202
205
|
this._audioSources = [];
|
|
203
206
|
}
|
|
204
207
|
const gain = audioContext.createGain();
|
|
205
208
|
gain.connect(audioContext.destination);
|
|
206
|
-
gain.gain.value = soundsOptions.volume.value /
|
|
209
|
+
gain.gain.value = soundsOptions.volume.value / percentDenominator;
|
|
207
210
|
this._gain = gain;
|
|
208
211
|
this._initEvents();
|
|
209
212
|
this._engine.dispatchEvent("soundsUnmuted", { container: this._container });
|
|
210
213
|
};
|
|
211
214
|
this._updateMuteIcons = () => {
|
|
212
|
-
const container = this._container,
|
|
215
|
+
const container = this._container, soundsOptions = container.actualOptions.sounds;
|
|
216
|
+
if (!soundsOptions?.enable || !soundsOptions.icons.enable) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const muteImg = this._muteImg, unmuteImg = this._unmuteImg;
|
|
213
220
|
if (muteImg) {
|
|
214
221
|
muteImg.style.display = container.muted ? "block" : "none";
|
|
215
222
|
}
|
|
@@ -218,13 +225,13 @@ export class SoundsInstance {
|
|
|
218
225
|
}
|
|
219
226
|
};
|
|
220
227
|
this._updateMuteStatus = async () => {
|
|
221
|
-
const container = this._container;
|
|
228
|
+
const container = this._container, audioContext = this._getAudioContext();
|
|
222
229
|
if (container.muted) {
|
|
223
|
-
await
|
|
224
|
-
this._mute();
|
|
230
|
+
await audioContext?.suspend();
|
|
231
|
+
await this._mute();
|
|
225
232
|
}
|
|
226
233
|
else {
|
|
227
|
-
await
|
|
234
|
+
await audioContext?.resume();
|
|
228
235
|
this._unmute();
|
|
229
236
|
this._playMuteSound();
|
|
230
237
|
}
|
|
@@ -236,12 +243,12 @@ export class SoundsInstance {
|
|
|
236
243
|
}
|
|
237
244
|
clamp(this._volume, soundsOptions.volume.min, soundsOptions.volume.max);
|
|
238
245
|
let stateChanged = false;
|
|
239
|
-
if (this._volume <=
|
|
246
|
+
if (this._volume <= minVolume && !container.muted) {
|
|
240
247
|
this._volume = 0;
|
|
241
248
|
container.muted = true;
|
|
242
249
|
stateChanged = true;
|
|
243
250
|
}
|
|
244
|
-
else if (this._volume >
|
|
251
|
+
else if (this._volume > minVolume && container.muted) {
|
|
245
252
|
container.muted = false;
|
|
246
253
|
stateChanged = true;
|
|
247
254
|
}
|
|
@@ -250,7 +257,7 @@ export class SoundsInstance {
|
|
|
250
257
|
await this._updateMuteStatus();
|
|
251
258
|
}
|
|
252
259
|
if (this._gain?.gain) {
|
|
253
|
-
this._gain.gain.value = this._volume /
|
|
260
|
+
this._gain.gain.value = this._volume / percentDenominator;
|
|
254
261
|
}
|
|
255
262
|
};
|
|
256
263
|
this._container = container;
|
|
@@ -264,6 +271,20 @@ export class SoundsInstance {
|
|
|
264
271
|
if (!soundsOptions?.enable) {
|
|
265
272
|
return;
|
|
266
273
|
}
|
|
274
|
+
if (soundsOptions.autoPlay && isWindowMuted()) {
|
|
275
|
+
const firstClickHandler = () => {
|
|
276
|
+
removeEventListener(mouseDownEvent, firstClickHandler);
|
|
277
|
+
removeEventListener(touchStartEvent, firstClickHandler);
|
|
278
|
+
unmuteWindow();
|
|
279
|
+
void this.unmute();
|
|
280
|
+
};
|
|
281
|
+
const listenerOptions = {
|
|
282
|
+
capture: true,
|
|
283
|
+
once: true,
|
|
284
|
+
};
|
|
285
|
+
addEventListener(mouseDownEvent, firstClickHandler, listenerOptions);
|
|
286
|
+
addEventListener(touchStartEvent, firstClickHandler, listenerOptions);
|
|
287
|
+
}
|
|
267
288
|
this._volume = soundsOptions.volume.value;
|
|
268
289
|
const events = soundsOptions.events;
|
|
269
290
|
this._audioMap = new Map();
|
|
@@ -271,16 +292,25 @@ export class SoundsInstance {
|
|
|
271
292
|
if (!event.audio) {
|
|
272
293
|
continue;
|
|
273
294
|
}
|
|
274
|
-
executeOnSingleOrMultiple(event.audio, async (audio) => {
|
|
295
|
+
const promises = executeOnSingleOrMultiple(event.audio, async (audio) => {
|
|
275
296
|
const response = await fetch(audio.source);
|
|
276
297
|
if (!response.ok) {
|
|
277
298
|
return;
|
|
278
299
|
}
|
|
279
|
-
const arrayBuffer = await response.arrayBuffer();
|
|
280
|
-
container.audioContext = new AudioContext();
|
|
281
|
-
const audioBuffer = await container.audioContext.decodeAudioData(arrayBuffer);
|
|
300
|
+
const arrayBuffer = await response.arrayBuffer(), audioContext = this._getAudioContext(), audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
|
|
282
301
|
this._audioMap.set(audio.source, audioBuffer);
|
|
283
302
|
});
|
|
303
|
+
if (promises instanceof Promise) {
|
|
304
|
+
await promises;
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
await Promise.allSettled(promises);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
async mute() {
|
|
312
|
+
if (!this._container.muted) {
|
|
313
|
+
await this.toggleMute();
|
|
284
314
|
}
|
|
285
315
|
}
|
|
286
316
|
async start() {
|
|
@@ -292,17 +322,14 @@ export class SoundsInstance {
|
|
|
292
322
|
const canvas = container.canvas.element, pos = {
|
|
293
323
|
top: canvas.offsetTop,
|
|
294
324
|
right: canvas.offsetLeft + canvas.offsetWidth,
|
|
295
|
-
}, { mute, unmute, volumeDown, volumeUp } = soundsOptions.icons, margin = 10
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
this._updateMuteIcons();
|
|
299
|
-
await this._updateMuteStatus();
|
|
300
|
-
};
|
|
325
|
+
}, { mute, unmute, volumeDown, volumeUp } = soundsOptions.icons, margin = 10, toggleMute = async () => {
|
|
326
|
+
await this.toggleMute();
|
|
327
|
+
}, enableIcons = soundsOptions.icons.enable, display = enableIcons ? "block" : "none";
|
|
301
328
|
this._muteImg = initImage({
|
|
302
329
|
container,
|
|
303
330
|
options,
|
|
304
331
|
pos,
|
|
305
|
-
display
|
|
332
|
+
display,
|
|
306
333
|
iconOptions: mute,
|
|
307
334
|
margin,
|
|
308
335
|
rightOffsets: [volumeDown.width, volumeUp.width],
|
|
@@ -322,41 +349,75 @@ export class SoundsInstance {
|
|
|
322
349
|
container,
|
|
323
350
|
options,
|
|
324
351
|
pos,
|
|
325
|
-
display
|
|
352
|
+
display,
|
|
326
353
|
iconOptions: volumeDown,
|
|
327
354
|
margin,
|
|
328
355
|
rightOffsets: [volumeUp.width],
|
|
329
356
|
clickCb: async () => {
|
|
330
|
-
|
|
331
|
-
this._volume = 0;
|
|
332
|
-
}
|
|
333
|
-
this._volume -= soundsOptions.volume.step;
|
|
334
|
-
await this._updateVolume();
|
|
357
|
+
await this.volumeDown();
|
|
335
358
|
},
|
|
336
359
|
});
|
|
337
360
|
this._volumeUpImg = initImage({
|
|
338
361
|
container,
|
|
339
362
|
options,
|
|
340
363
|
pos,
|
|
341
|
-
display
|
|
364
|
+
display,
|
|
342
365
|
iconOptions: volumeUp,
|
|
343
366
|
margin,
|
|
344
367
|
rightOffsets: [],
|
|
345
368
|
clickCb: async () => {
|
|
346
|
-
|
|
347
|
-
this._volume = 0;
|
|
348
|
-
}
|
|
349
|
-
this._volume += soundsOptions.volume.step;
|
|
350
|
-
await this._updateVolume();
|
|
369
|
+
await this.volumeUp();
|
|
351
370
|
},
|
|
352
371
|
});
|
|
372
|
+
if (!isWindowMuted() && soundsOptions.autoPlay) {
|
|
373
|
+
await this.unmute();
|
|
374
|
+
}
|
|
353
375
|
}
|
|
354
376
|
stop() {
|
|
355
377
|
this._container.muted = true;
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
378
|
+
void (async () => {
|
|
379
|
+
await this._mute();
|
|
380
|
+
removeImage(this._muteImg);
|
|
381
|
+
removeImage(this._unmuteImg);
|
|
382
|
+
removeImage(this._volumeDownImg);
|
|
383
|
+
removeImage(this._volumeUpImg);
|
|
384
|
+
})();
|
|
385
|
+
}
|
|
386
|
+
async toggleMute() {
|
|
387
|
+
const container = this._container;
|
|
388
|
+
container.muted = !container.muted;
|
|
389
|
+
this._updateMuteIcons();
|
|
390
|
+
await this._updateMuteStatus();
|
|
391
|
+
}
|
|
392
|
+
async unmute() {
|
|
393
|
+
if (this._container.muted) {
|
|
394
|
+
await this.toggleMute();
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
async volumeDown() {
|
|
398
|
+
const container = this._container, soundsOptions = container.actualOptions.sounds;
|
|
399
|
+
if (!soundsOptions?.enable) {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if (container.muted) {
|
|
403
|
+
this._volume = 0;
|
|
404
|
+
}
|
|
405
|
+
this._volume -= soundsOptions.volume.step;
|
|
406
|
+
await this._updateVolume();
|
|
407
|
+
}
|
|
408
|
+
async volumeUp() {
|
|
409
|
+
const container = this._container, soundsOptions = container.actualOptions.sounds;
|
|
410
|
+
if (!soundsOptions?.enable) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
this._volume += soundsOptions.volume.step;
|
|
414
|
+
await this._updateVolume();
|
|
415
|
+
}
|
|
416
|
+
_getAudioContext() {
|
|
417
|
+
const container = this._container;
|
|
418
|
+
if (!container.audioContext) {
|
|
419
|
+
container.audioContext = new AudioContext();
|
|
420
|
+
}
|
|
421
|
+
return container.audioContext;
|
|
361
422
|
}
|
|
362
423
|
}
|
package/browser/index.js
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
|
+
import { mouseDownEvent, touchStartEvent, } from "@tsparticles/engine";
|
|
1
2
|
import { Sounds } from "./Options/Classes/Sounds.js";
|
|
2
3
|
import { SoundsInstance } from "./SoundsInstance.js";
|
|
4
|
+
import { unmuteWindow } from "./utils.js";
|
|
5
|
+
const generalFirstClickHandler = () => {
|
|
6
|
+
removeEventListener(mouseDownEvent, generalFirstClickHandler);
|
|
7
|
+
removeEventListener(touchStartEvent, generalFirstClickHandler);
|
|
8
|
+
unmuteWindow();
|
|
9
|
+
};
|
|
3
10
|
class SoundsPlugin {
|
|
4
11
|
constructor(engine) {
|
|
5
12
|
this.id = "sounds";
|
|
6
13
|
this._engine = engine;
|
|
14
|
+
const listenerOptions = {
|
|
15
|
+
capture: true,
|
|
16
|
+
once: true,
|
|
17
|
+
};
|
|
18
|
+
addEventListener(mouseDownEvent, generalFirstClickHandler, listenerOptions);
|
|
19
|
+
addEventListener(touchStartEvent, generalFirstClickHandler, listenerOptions);
|
|
7
20
|
}
|
|
8
21
|
getPlugin(container) {
|
|
9
22
|
return new SoundsInstance(container, this._engine);
|
package/browser/utils.js
CHANGED
|
@@ -13,13 +13,20 @@ notes.set("Bb", [29.14, 58.27, 116.54, 233.08, 466.16, 932.33, 1864.66, 3729.31,
|
|
|
13
13
|
notes.set("B", [30.87, 61.74, 123.47, 246.94, 493.88, 987.77, 1975.53, 3951.07, 7902.13]);
|
|
14
14
|
notes.set("pause", [0]);
|
|
15
15
|
export function getNoteFrequency(note) {
|
|
16
|
-
const regex = /(([A-G]b?)(\d))|pause/i, result = regex.exec(note);
|
|
17
|
-
if (!result
|
|
16
|
+
const regex = /(([A-G]b?)(\d))|pause/i, result = regex.exec(note), groupKey = 2, defaultMatchKey = 0, innerGroupKey = 3;
|
|
17
|
+
if (!result?.length) {
|
|
18
18
|
return;
|
|
19
19
|
}
|
|
20
|
-
const noteKey = result[
|
|
20
|
+
const noteKey = result[groupKey] || result[defaultMatchKey], noteItem = notes.get(noteKey);
|
|
21
21
|
if (!noteItem) {
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
|
-
return noteItem[parseInt(result[
|
|
24
|
+
return noteItem[parseInt(result[innerGroupKey] || "0")];
|
|
25
25
|
}
|
|
26
|
+
let muted = true;
|
|
27
|
+
export const isWindowMuted = () => {
|
|
28
|
+
return muted;
|
|
29
|
+
};
|
|
30
|
+
export const unmuteWindow = () => {
|
|
31
|
+
muted = false;
|
|
32
|
+
};
|
|
@@ -6,6 +6,7 @@ const SoundsIcons_js_1 = require("./SoundsIcons.js");
|
|
|
6
6
|
const SoundsVolume_js_1 = require("./SoundsVolume.js");
|
|
7
7
|
class Sounds {
|
|
8
8
|
constructor() {
|
|
9
|
+
this.autoPlay = true;
|
|
9
10
|
this.enable = false;
|
|
10
11
|
this.events = [];
|
|
11
12
|
this.icons = new SoundsIcons_js_1.SoundsIcons();
|
|
@@ -15,6 +16,9 @@ class Sounds {
|
|
|
15
16
|
if (!data) {
|
|
16
17
|
return;
|
|
17
18
|
}
|
|
19
|
+
if (data.autoPlay !== undefined) {
|
|
20
|
+
this.autoPlay = data.autoPlay;
|
|
21
|
+
}
|
|
18
22
|
if (data.enable !== undefined) {
|
|
19
23
|
this.enable = data.enable;
|
|
20
24
|
}
|
|
@@ -44,10 +44,11 @@ class SoundsEvent {
|
|
|
44
44
|
return tmp;
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
|
-
if (data.filter
|
|
47
|
+
if (data.filter) {
|
|
48
48
|
if ((0, engine_1.isString)(data.filter)) {
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
const filterFunc = window[data.filter];
|
|
50
|
+
if ((0, engine_1.isFunction)(filterFunc)) {
|
|
51
|
+
this.filter = filterFunc;
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
else {
|
|
@@ -8,6 +8,7 @@ class SoundsIcons {
|
|
|
8
8
|
this.unmute = new SoundsIcon_js_1.SoundsIcon();
|
|
9
9
|
this.volumeDown = new SoundsIcon_js_1.SoundsIcon();
|
|
10
10
|
this.volumeUp = new SoundsIcon_js_1.SoundsIcon();
|
|
11
|
+
this.enable = false;
|
|
11
12
|
this.mute.svg = `<?xml version="1.0"?>
|
|
12
13
|
<svg baseProfile="tiny" height="24px" version="1.2" viewBox="0 0 24 24" width="24px"
|
|
13
14
|
xml:space="preserve" xmlns="http://www.w3.org/2000/svg"
|
|
@@ -49,6 +50,9 @@ class SoundsIcons {
|
|
|
49
50
|
if (!data) {
|
|
50
51
|
return;
|
|
51
52
|
}
|
|
53
|
+
if (data.enable !== undefined) {
|
|
54
|
+
this.enable = data.enable;
|
|
55
|
+
}
|
|
52
56
|
this.mute.load(data.mute);
|
|
53
57
|
this.unmute.load(data.unmute);
|
|
54
58
|
this.volumeDown.load(data.volumeDown);
|