@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.
Files changed (44) hide show
  1. package/browser/Options/Classes/Sounds.js +4 -0
  2. package/browser/Options/Classes/SoundsEvent.js +4 -3
  3. package/browser/Options/Classes/SoundsIcon.js +1 -0
  4. package/browser/Options/Classes/SoundsIcons.js +4 -0
  5. package/browser/SoundsInstance.js +130 -69
  6. package/browser/index.js +13 -0
  7. package/browser/utils.js +11 -4
  8. package/cjs/Options/Classes/Sounds.js +4 -0
  9. package/cjs/Options/Classes/SoundsEvent.js +4 -3
  10. package/cjs/Options/Classes/SoundsIcon.js +1 -0
  11. package/cjs/Options/Classes/SoundsIcons.js +4 -0
  12. package/cjs/SoundsInstance.js +128 -67
  13. package/cjs/index.js +13 -0
  14. package/cjs/utils.js +14 -5
  15. package/esm/Options/Classes/Sounds.js +4 -0
  16. package/esm/Options/Classes/SoundsEvent.js +4 -3
  17. package/esm/Options/Classes/SoundsIcon.js +1 -0
  18. package/esm/Options/Classes/SoundsIcons.js +4 -0
  19. package/esm/SoundsInstance.js +130 -69
  20. package/esm/index.js +13 -0
  21. package/esm/utils.js +11 -4
  22. package/package.json +2 -2
  23. package/report.html +2 -2
  24. package/tsparticles.plugin.sounds.js +180 -77
  25. package/tsparticles.plugin.sounds.min.js +1 -1
  26. package/tsparticles.plugin.sounds.min.js.LICENSE.txt +1 -1
  27. package/types/Options/Classes/Sounds.d.ts +1 -0
  28. package/types/Options/Classes/SoundsEvent.d.ts +0 -5
  29. package/types/Options/Classes/SoundsIcon.d.ts +1 -0
  30. package/types/Options/Classes/SoundsIcons.d.ts +1 -0
  31. package/types/Options/Interfaces/ISounds.d.ts +1 -0
  32. package/types/Options/Interfaces/ISoundsIcon.d.ts +1 -0
  33. package/types/Options/Interfaces/ISoundsIcons.d.ts +1 -0
  34. package/types/SoundsInstance.d.ts +6 -0
  35. package/types/index.d.ts +1 -1
  36. package/types/types.d.ts +5 -5
  37. package/types/utils.d.ts +2 -0
  38. package/umd/Options/Classes/Sounds.js +4 -0
  39. package/umd/Options/Classes/SoundsEvent.js +4 -3
  40. package/umd/Options/Classes/SoundsIcon.js +1 -0
  41. package/umd/Options/Classes/SoundsIcons.js +4 -0
  42. package/umd/SoundsInstance.js +128 -67
  43. package/umd/index.js +14 -1
  44. package/umd/utils.js +14 -5
@@ -1,5 +1,6 @@
1
1
  import type { ISoundsIcon } from "./ISoundsIcon.js";
2
2
  export interface ISoundsIcons {
3
+ enable: boolean;
3
4
  mute: ISoundsIcon;
4
5
  unmute: ISoundsIcon;
5
6
  volumeDown: ISoundsIcon;
@@ -13,10 +13,16 @@ export declare class SoundsInstance implements IContainerPlugin {
13
13
  private _volumeUpImg?;
14
14
  constructor(container: SoundsContainer, engine: Engine);
15
15
  init(): Promise<void>;
16
+ mute(): Promise<void>;
16
17
  start(): Promise<void>;
17
18
  stop(): void;
19
+ toggleMute(): Promise<void>;
20
+ unmute(): Promise<void>;
21
+ volumeDown(): Promise<void>;
22
+ volumeUp(): Promise<void>;
18
23
  private readonly _addBuffer;
19
24
  private readonly _addOscillator;
25
+ private _getAudioContext;
20
26
  private readonly _initEvents;
21
27
  private readonly _mute;
22
28
  private readonly _playBuffer;
package/types/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import type { Engine } from "@tsparticles/engine";
1
+ import { type Engine } from "@tsparticles/engine";
2
2
  export declare function loadSoundsPlugin(engine: Engine, refresh?: boolean): Promise<void>;
package/types/types.d.ts CHANGED
@@ -15,12 +15,12 @@ export type SoundsContainer = Container & {
15
15
  audioContext?: AudioContext;
16
16
  muted?: boolean;
17
17
  };
18
- export type ImageMargins = {
18
+ export interface ImageMargins {
19
19
  right: number;
20
20
  top: number;
21
- };
22
- export type InitImageData = {
23
- clickCb: () => void;
21
+ }
22
+ export interface InitImageData {
23
+ clickCb: () => Promise<void>;
24
24
  container: SoundsContainer;
25
25
  display: ImageDisplay;
26
26
  iconOptions: SoundsIcon;
@@ -28,4 +28,4 @@ export type InitImageData = {
28
28
  options: Options;
29
29
  pos: ImageMargins;
30
30
  rightOffsets: number[];
31
- };
31
+ }
package/types/utils.d.ts CHANGED
@@ -1 +1,3 @@
1
1
  export declare function getNoteFrequency(note: string): number | undefined;
2
+ export declare const isWindowMuted: () => boolean;
3
+ export declare const unmuteWindow: () => void;
@@ -15,6 +15,7 @@
15
15
  const SoundsVolume_js_1 = require("./SoundsVolume.js");
16
16
  class Sounds {
17
17
  constructor() {
18
+ this.autoPlay = true;
18
19
  this.enable = false;
19
20
  this.events = [];
20
21
  this.icons = new SoundsIcons_js_1.SoundsIcons();
@@ -24,6 +25,9 @@
24
25
  if (!data) {
25
26
  return;
26
27
  }
28
+ if (data.autoPlay !== undefined) {
29
+ this.autoPlay = data.autoPlay;
30
+ }
27
31
  if (data.enable !== undefined) {
28
32
  this.enable = data.enable;
29
33
  }
@@ -53,10 +53,11 @@
53
53
  return tmp;
54
54
  });
55
55
  }
56
- if (data.filter !== undefined) {
56
+ if (data.filter) {
57
57
  if ((0, engine_1.isString)(data.filter)) {
58
- if ((0, engine_1.isFunction)(window[data.filter])) {
59
- this.filter = window[data.filter];
58
+ const filterFunc = window[data.filter];
59
+ if ((0, engine_1.isFunction)(filterFunc)) {
60
+ this.filter = filterFunc;
60
61
  }
61
62
  }
62
63
  else {
@@ -14,6 +14,7 @@
14
14
  constructor() {
15
15
  this.width = 24;
16
16
  this.height = 24;
17
+ this.style = "";
17
18
  }
18
19
  load(data) {
19
20
  if (!data) {
@@ -17,6 +17,7 @@
17
17
  this.unmute = new SoundsIcon_js_1.SoundsIcon();
18
18
  this.volumeDown = new SoundsIcon_js_1.SoundsIcon();
19
19
  this.volumeUp = new SoundsIcon_js_1.SoundsIcon();
20
+ this.enable = false;
20
21
  this.mute.svg = `<?xml version="1.0"?>
21
22
  <svg baseProfile="tiny" height="24px" version="1.2" viewBox="0 0 24 24" width="24px"
22
23
  xml:space="preserve" xmlns="http://www.w3.org/2000/svg"
@@ -58,6 +59,9 @@
58
59
  if (!data) {
59
60
  return;
60
61
  }
62
+ if (data.enable !== undefined) {
63
+ this.enable = data.enable;
64
+ }
61
65
  this.mute.load(data.mute);
62
66
  this.unmute.load(data.unmute);
63
67
  this.volumeDown.load(data.volumeDown);
@@ -12,13 +12,19 @@
12
12
  exports.SoundsInstance = void 0;
13
13
  const engine_1 = require("@tsparticles/engine");
14
14
  const utils_js_1 = require("./utils.js");
15
+ const zIndexOffset = 1, rightOffset = 1, minVolume = 0;
15
16
  function initImage(data) {
16
- const img = document.createElement("img"), { clickCb, container, display, iconOptions, margin, options, pos, rightOffsets } = data, { width, path, svg } = iconOptions;
17
- setIconStyle(img, pos.top + margin, pos.right - (margin * (rightOffsets.length + 1) + width + rightOffsets.reduce((a, b) => a + b, 0)), display, options.fullScreen.zIndex + 1, width, margin);
17
+ const img = document.createElement("img"), { clickCb, container, display, iconOptions, margin, options, pos, rightOffsets } = data, { width, path, style, svg } = iconOptions, defaultAccumulator = 0;
18
+ setIconStyle(img, pos.top + margin, pos.right -
19
+ (margin * (rightOffsets.length + rightOffset) +
20
+ width +
21
+ rightOffsets.reduce((a, b) => a + b, defaultAccumulator)), display, options.fullScreen.zIndex + zIndexOffset, width, margin, style);
18
22
  img.src = path ?? (svg ? `data:image/svg+xml;base64,${btoa(svg)}` : "");
19
- const parent = container.canvas.element?.parentNode || document.body;
23
+ const parent = container.canvas.element?.parentNode ?? document.body;
20
24
  parent.append(img);
21
- img.addEventListener("click", clickCb);
25
+ img.addEventListener("click", () => {
26
+ void clickCb();
27
+ });
22
28
  return img;
23
29
  }
24
30
  function removeImage(image) {
@@ -27,14 +33,15 @@
27
33
  }
28
34
  image.remove();
29
35
  }
30
- function setIconStyle(icon, top, left, display, zIndex, width, margin) {
36
+ function setIconStyle(icon, top, left, display, zIndex, width, margin, style) {
31
37
  icon.style.userSelect = "none";
32
38
  icon.style.webkitUserSelect = "none";
33
39
  icon.style.position = "absolute";
34
40
  icon.style.top = `${top + margin}px`;
35
41
  icon.style.left = `${left - margin - width}px`;
36
42
  icon.style.display = display;
37
- icon.style.zIndex = `${zIndex + 1}`;
43
+ icon.style.zIndex = `${zIndex + zIndexOffset}`;
44
+ icon.style.cssText += style;
38
45
  }
39
46
  class SoundsInstance {
40
47
  constructor(container, engine) {
@@ -55,12 +62,12 @@
55
62
  }
56
63
  for (const event of soundsOptions.events) {
57
64
  const cb = (args) => {
58
- (async () => {
65
+ void (async () => {
59
66
  const filterNotValid = event.filter && !event.filter(args);
60
67
  if (this._container !== args.container) {
61
68
  return;
62
69
  }
63
- if (!this._container || this._container.muted || this._container.destroyed) {
70
+ if (!this._container || !!this._container.muted || this._container.destroyed) {
64
71
  (0, engine_1.executeOnSingleOrMultiple)(event.event, (item) => {
65
72
  this._engine.removeEventListener(item, cb);
66
73
  });
@@ -69,21 +76,22 @@
69
76
  if (filterNotValid) {
70
77
  return;
71
78
  }
79
+ const defaultNoteIndex = 0;
72
80
  if (event.audio) {
73
81
  this._playBuffer((0, engine_1.itemFromSingleOrMultiple)(event.audio));
74
82
  }
75
83
  else if (event.melodies) {
76
84
  const melody = (0, engine_1.itemFromArray)(event.melodies);
77
85
  if (melody.melodies.length) {
78
- await Promise.allSettled(melody.melodies.map((m) => this._playNote(m.notes, 0, melody.loop)));
86
+ await Promise.allSettled(melody.melodies.map((m) => this._playNote(m.notes, defaultNoteIndex, melody.loop)));
79
87
  }
80
88
  else {
81
- await this._playNote(melody.notes, 0, melody.loop);
89
+ await this._playNote(melody.notes, defaultNoteIndex, melody.loop);
82
90
  }
83
91
  }
84
92
  else if (event.notes) {
85
93
  const note = (0, engine_1.itemFromArray)(event.notes);
86
- await this._playNote([note], 0, false);
94
+ await this._playNote([note], defaultNoteIndex, false);
87
95
  }
88
96
  })();
89
97
  };
@@ -92,18 +100,15 @@
92
100
  });
93
101
  }
94
102
  };
95
- this._mute = () => {
96
- const container = this._container;
97
- if (!container.audioContext) {
98
- return;
99
- }
103
+ this._mute = async () => {
104
+ const container = this._container, audioContext = this._getAudioContext();
100
105
  for (const source of this._audioSources) {
101
106
  this._removeAudioSource(source);
102
107
  }
103
108
  if (this._gain) {
104
109
  this._gain.disconnect();
105
110
  }
106
- container.audioContext.close();
111
+ await audioContext.close();
107
112
  container.audioContext = undefined;
108
113
  this._engine.dispatchEvent("soundsMuted", { container: this._container });
109
114
  };
@@ -123,10 +128,10 @@
123
128
  source.start();
124
129
  };
125
130
  this._playFrequency = async (frequency, duration) => {
126
- if (!this._container.audioContext || !this._gain) {
131
+ if (!this._gain || this._container.muted) {
127
132
  return;
128
133
  }
129
- const oscillator = this._addOscillator(this._container.audioContext);
134
+ const audioContext = this._getAudioContext(), oscillator = this._addOscillator(audioContext);
130
135
  oscillator.connect(this._gain);
131
136
  oscillator.type = "sine";
132
137
  oscillator.frequency.value = frequency;
@@ -139,14 +144,13 @@
139
144
  });
140
145
  };
141
146
  this._playMuteSound = () => {
142
- const container = this._container;
143
- if (!container.audioContext) {
147
+ if (this._container.muted) {
144
148
  return;
145
149
  }
146
- const gain = container.audioContext.createGain();
147
- gain.connect(container.audioContext.destination);
150
+ const audioContext = this._getAudioContext(), gain = audioContext.createGain();
151
+ gain.connect(audioContext.destination);
148
152
  gain.gain.value = 0;
149
- const oscillator = container.audioContext.createOscillator();
153
+ const oscillator = audioContext.createOscillator();
150
154
  oscillator.connect(gain);
151
155
  oscillator.type = "sine";
152
156
  oscillator.frequency.value = 1;
@@ -170,7 +174,8 @@
170
174
  return this._playNoteValue(notes, noteIdx, idx);
171
175
  });
172
176
  await ((0, engine_1.isArray)(promises) ? Promise.allSettled(promises) : promises);
173
- let nextNoteIdx = noteIdx + 1;
177
+ const indexOffset = 1;
178
+ let nextNoteIdx = noteIdx + indexOffset;
174
179
  if (loop && nextNoteIdx >= notes.length) {
175
180
  nextNoteIdx = nextNoteIdx % notes.length;
176
181
  }
@@ -199,29 +204,31 @@
199
204
  this._removeAudioSource = (source) => {
200
205
  source.stop();
201
206
  source.disconnect();
202
- this._audioSources.splice(this._audioSources.indexOf(source), 1);
207
+ const deleteCount = 1;
208
+ this._audioSources.splice(this._audioSources.indexOf(source), deleteCount);
203
209
  };
204
210
  this._unmute = () => {
205
211
  const container = this._container, options = container.actualOptions, soundsOptions = options.sounds;
206
212
  if (!soundsOptions) {
207
213
  return;
208
214
  }
209
- if (!container.audioContext) {
210
- container.audioContext = new AudioContext();
211
- }
212
- const { audioContext } = container;
215
+ const audioContext = this._getAudioContext();
213
216
  if (!this._audioSources) {
214
217
  this._audioSources = [];
215
218
  }
216
219
  const gain = audioContext.createGain();
217
220
  gain.connect(audioContext.destination);
218
- gain.gain.value = soundsOptions.volume.value / 100;
221
+ gain.gain.value = soundsOptions.volume.value / engine_1.percentDenominator;
219
222
  this._gain = gain;
220
223
  this._initEvents();
221
224
  this._engine.dispatchEvent("soundsUnmuted", { container: this._container });
222
225
  };
223
226
  this._updateMuteIcons = () => {
224
- const container = this._container, muteImg = this._muteImg, unmuteImg = this._unmuteImg;
227
+ const container = this._container, soundsOptions = container.actualOptions.sounds;
228
+ if (!soundsOptions?.enable || !soundsOptions.icons.enable) {
229
+ return;
230
+ }
231
+ const muteImg = this._muteImg, unmuteImg = this._unmuteImg;
225
232
  if (muteImg) {
226
233
  muteImg.style.display = container.muted ? "block" : "none";
227
234
  }
@@ -230,13 +237,13 @@
230
237
  }
231
238
  };
232
239
  this._updateMuteStatus = async () => {
233
- const container = this._container;
240
+ const container = this._container, audioContext = this._getAudioContext();
234
241
  if (container.muted) {
235
- await container.audioContext?.suspend();
236
- this._mute();
242
+ await audioContext?.suspend();
243
+ await this._mute();
237
244
  }
238
245
  else {
239
- await container.audioContext?.resume();
246
+ await audioContext?.resume();
240
247
  this._unmute();
241
248
  this._playMuteSound();
242
249
  }
@@ -248,12 +255,12 @@
248
255
  }
249
256
  (0, engine_1.clamp)(this._volume, soundsOptions.volume.min, soundsOptions.volume.max);
250
257
  let stateChanged = false;
251
- if (this._volume <= 0 && !container.muted) {
258
+ if (this._volume <= minVolume && !container.muted) {
252
259
  this._volume = 0;
253
260
  container.muted = true;
254
261
  stateChanged = true;
255
262
  }
256
- else if (this._volume > 0 && container.muted) {
263
+ else if (this._volume > minVolume && container.muted) {
257
264
  container.muted = false;
258
265
  stateChanged = true;
259
266
  }
@@ -262,7 +269,7 @@
262
269
  await this._updateMuteStatus();
263
270
  }
264
271
  if (this._gain?.gain) {
265
- this._gain.gain.value = this._volume / 100;
272
+ this._gain.gain.value = this._volume / engine_1.percentDenominator;
266
273
  }
267
274
  };
268
275
  this._container = container;
@@ -276,6 +283,20 @@
276
283
  if (!soundsOptions?.enable) {
277
284
  return;
278
285
  }
286
+ if (soundsOptions.autoPlay && (0, utils_js_1.isWindowMuted)()) {
287
+ const firstClickHandler = () => {
288
+ removeEventListener(engine_1.mouseDownEvent, firstClickHandler);
289
+ removeEventListener(engine_1.touchStartEvent, firstClickHandler);
290
+ (0, utils_js_1.unmuteWindow)();
291
+ void this.unmute();
292
+ };
293
+ const listenerOptions = {
294
+ capture: true,
295
+ once: true,
296
+ };
297
+ addEventListener(engine_1.mouseDownEvent, firstClickHandler, listenerOptions);
298
+ addEventListener(engine_1.touchStartEvent, firstClickHandler, listenerOptions);
299
+ }
279
300
  this._volume = soundsOptions.volume.value;
280
301
  const events = soundsOptions.events;
281
302
  this._audioMap = new Map();
@@ -283,16 +304,25 @@
283
304
  if (!event.audio) {
284
305
  continue;
285
306
  }
286
- (0, engine_1.executeOnSingleOrMultiple)(event.audio, async (audio) => {
307
+ const promises = (0, engine_1.executeOnSingleOrMultiple)(event.audio, async (audio) => {
287
308
  const response = await fetch(audio.source);
288
309
  if (!response.ok) {
289
310
  return;
290
311
  }
291
- const arrayBuffer = await response.arrayBuffer();
292
- container.audioContext = new AudioContext();
293
- const audioBuffer = await container.audioContext.decodeAudioData(arrayBuffer);
312
+ const arrayBuffer = await response.arrayBuffer(), audioContext = this._getAudioContext(), audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
294
313
  this._audioMap.set(audio.source, audioBuffer);
295
314
  });
315
+ if (promises instanceof Promise) {
316
+ await promises;
317
+ }
318
+ else {
319
+ await Promise.allSettled(promises);
320
+ }
321
+ }
322
+ }
323
+ async mute() {
324
+ if (!this._container.muted) {
325
+ await this.toggleMute();
296
326
  }
297
327
  }
298
328
  async start() {
@@ -304,17 +334,14 @@
304
334
  const canvas = container.canvas.element, pos = {
305
335
  top: canvas.offsetTop,
306
336
  right: canvas.offsetLeft + canvas.offsetWidth,
307
- }, { mute, unmute, volumeDown, volumeUp } = soundsOptions.icons, margin = 10;
308
- const toggleMute = async () => {
309
- container.muted = !container.muted;
310
- this._updateMuteIcons();
311
- await this._updateMuteStatus();
312
- };
337
+ }, { mute, unmute, volumeDown, volumeUp } = soundsOptions.icons, margin = 10, toggleMute = async () => {
338
+ await this.toggleMute();
339
+ }, enableIcons = soundsOptions.icons.enable, display = enableIcons ? "block" : "none";
313
340
  this._muteImg = initImage({
314
341
  container,
315
342
  options,
316
343
  pos,
317
- display: "block",
344
+ display,
318
345
  iconOptions: mute,
319
346
  margin,
320
347
  rightOffsets: [volumeDown.width, volumeUp.width],
@@ -334,42 +361,76 @@
334
361
  container,
335
362
  options,
336
363
  pos,
337
- display: "block",
364
+ display,
338
365
  iconOptions: volumeDown,
339
366
  margin,
340
367
  rightOffsets: [volumeUp.width],
341
368
  clickCb: async () => {
342
- if (container.muted) {
343
- this._volume = 0;
344
- }
345
- this._volume -= soundsOptions.volume.step;
346
- await this._updateVolume();
369
+ await this.volumeDown();
347
370
  },
348
371
  });
349
372
  this._volumeUpImg = initImage({
350
373
  container,
351
374
  options,
352
375
  pos,
353
- display: "block",
376
+ display,
354
377
  iconOptions: volumeUp,
355
378
  margin,
356
379
  rightOffsets: [],
357
380
  clickCb: async () => {
358
- if (container.muted) {
359
- this._volume = 0;
360
- }
361
- this._volume += soundsOptions.volume.step;
362
- await this._updateVolume();
381
+ await this.volumeUp();
363
382
  },
364
383
  });
384
+ if (!(0, utils_js_1.isWindowMuted)() && soundsOptions.autoPlay) {
385
+ await this.unmute();
386
+ }
365
387
  }
366
388
  stop() {
367
389
  this._container.muted = true;
368
- this._mute();
369
- removeImage(this._muteImg);
370
- removeImage(this._unmuteImg);
371
- removeImage(this._volumeDownImg);
372
- removeImage(this._volumeUpImg);
390
+ void (async () => {
391
+ await this._mute();
392
+ removeImage(this._muteImg);
393
+ removeImage(this._unmuteImg);
394
+ removeImage(this._volumeDownImg);
395
+ removeImage(this._volumeUpImg);
396
+ })();
397
+ }
398
+ async toggleMute() {
399
+ const container = this._container;
400
+ container.muted = !container.muted;
401
+ this._updateMuteIcons();
402
+ await this._updateMuteStatus();
403
+ }
404
+ async unmute() {
405
+ if (this._container.muted) {
406
+ await this.toggleMute();
407
+ }
408
+ }
409
+ async volumeDown() {
410
+ const container = this._container, soundsOptions = container.actualOptions.sounds;
411
+ if (!soundsOptions?.enable) {
412
+ return;
413
+ }
414
+ if (container.muted) {
415
+ this._volume = 0;
416
+ }
417
+ this._volume -= soundsOptions.volume.step;
418
+ await this._updateVolume();
419
+ }
420
+ async volumeUp() {
421
+ const container = this._container, soundsOptions = container.actualOptions.sounds;
422
+ if (!soundsOptions?.enable) {
423
+ return;
424
+ }
425
+ this._volume += soundsOptions.volume.step;
426
+ await this._updateVolume();
427
+ }
428
+ _getAudioContext() {
429
+ const container = this._container;
430
+ if (!container.audioContext) {
431
+ container.audioContext = new AudioContext();
432
+ }
433
+ return container.audioContext;
373
434
  }
374
435
  }
375
436
  exports.SoundsInstance = SoundsInstance;
package/umd/index.js CHANGED
@@ -4,18 +4,31 @@
4
4
  if (v !== undefined) module.exports = v;
5
5
  }
6
6
  else if (typeof define === "function" && define.amd) {
7
- define(["require", "exports", "./Options/Classes/Sounds.js", "./SoundsInstance.js"], factory);
7
+ define(["require", "exports", "@tsparticles/engine", "./Options/Classes/Sounds.js", "./SoundsInstance.js", "./utils.js"], factory);
8
8
  }
9
9
  })(function (require, exports) {
10
10
  "use strict";
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.loadSoundsPlugin = void 0;
13
+ const engine_1 = require("@tsparticles/engine");
13
14
  const Sounds_js_1 = require("./Options/Classes/Sounds.js");
14
15
  const SoundsInstance_js_1 = require("./SoundsInstance.js");
16
+ const utils_js_1 = require("./utils.js");
17
+ const generalFirstClickHandler = () => {
18
+ removeEventListener(engine_1.mouseDownEvent, generalFirstClickHandler);
19
+ removeEventListener(engine_1.touchStartEvent, generalFirstClickHandler);
20
+ (0, utils_js_1.unmuteWindow)();
21
+ };
15
22
  class SoundsPlugin {
16
23
  constructor(engine) {
17
24
  this.id = "sounds";
18
25
  this._engine = engine;
26
+ const listenerOptions = {
27
+ capture: true,
28
+ once: true,
29
+ };
30
+ addEventListener(engine_1.mouseDownEvent, generalFirstClickHandler, listenerOptions);
31
+ addEventListener(engine_1.touchStartEvent, generalFirstClickHandler, listenerOptions);
19
32
  }
20
33
  getPlugin(container) {
21
34
  return new SoundsInstance_js_1.SoundsInstance(container, this._engine);
package/umd/utils.js CHANGED
@@ -9,7 +9,7 @@
9
9
  })(function (require, exports) {
10
10
  "use strict";
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.getNoteFrequency = void 0;
12
+ exports.unmuteWindow = exports.isWindowMuted = exports.getNoteFrequency = void 0;
13
13
  const notes = new Map();
14
14
  notes.set("C", [16.35, 32.7, 65.41, 130.81, 261.63, 523.25, 1046.5, 2093.0, 4186.01]);
15
15
  notes.set("Db", [17.32, 34.65, 69.3, 138.59, 277.18, 554.37, 1108.73, 2217.46, 4434.92]);
@@ -25,15 +25,24 @@
25
25
  notes.set("B", [30.87, 61.74, 123.47, 246.94, 493.88, 987.77, 1975.53, 3951.07, 7902.13]);
26
26
  notes.set("pause", [0]);
27
27
  function getNoteFrequency(note) {
28
- const regex = /(([A-G]b?)(\d))|pause/i, result = regex.exec(note);
29
- if (!result || !result.length) {
28
+ const regex = /(([A-G]b?)(\d))|pause/i, result = regex.exec(note), groupKey = 2, defaultMatchKey = 0, innerGroupKey = 3;
29
+ if (!result?.length) {
30
30
  return;
31
31
  }
32
- const noteKey = result[2] || result[0], noteItem = notes.get(noteKey);
32
+ const noteKey = result[groupKey] || result[defaultMatchKey], noteItem = notes.get(noteKey);
33
33
  if (!noteItem) {
34
34
  return;
35
35
  }
36
- return noteItem[parseInt(result[3] || "0")];
36
+ return noteItem[parseInt(result[innerGroupKey] || "0")];
37
37
  }
38
38
  exports.getNoteFrequency = getNoteFrequency;
39
+ let muted = true;
40
+ const isWindowMuted = () => {
41
+ return muted;
42
+ };
43
+ exports.isWindowMuted = isWindowMuted;
44
+ const unmuteWindow = () => {
45
+ muted = false;
46
+ };
47
+ exports.unmuteWindow = unmuteWindow;
39
48
  });