@tsparticles/plugin-sounds 4.0.0-alpha.5 → 4.0.0-beta.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/30.min.js +33 -0
- package/915.min.js +1 -0
- package/browser/Options/Classes/Sounds.js +5 -0
- package/browser/Options/Classes/SoundsAudio.js +2 -0
- package/browser/Options/Classes/SoundsEvent.js +5 -0
- package/browser/Options/Classes/SoundsIcon.js +5 -0
- package/browser/Options/Classes/SoundsIcons.js +5 -0
- package/browser/Options/Classes/SoundsMelody.js +3 -0
- package/browser/Options/Classes/SoundsNote.js +2 -0
- package/browser/Options/Classes/SoundsVolume.js +4 -0
- package/browser/SoundsPlugin.js +2 -1
- package/browser/SoundsPluginInstance.js +247 -240
- package/browser/index.js +1 -1
- package/cjs/Options/Classes/Sounds.js +5 -0
- package/cjs/Options/Classes/SoundsAudio.js +2 -0
- package/cjs/Options/Classes/SoundsEvent.js +5 -0
- package/cjs/Options/Classes/SoundsIcon.js +5 -0
- package/cjs/Options/Classes/SoundsIcons.js +5 -0
- package/cjs/Options/Classes/SoundsMelody.js +3 -0
- package/cjs/Options/Classes/SoundsNote.js +2 -0
- package/cjs/Options/Classes/SoundsVolume.js +4 -0
- package/cjs/SoundsPlugin.js +2 -1
- package/cjs/SoundsPluginInstance.js +247 -240
- package/cjs/index.js +1 -1
- package/dist_browser_SoundsPluginInstance_js.js +3 -3
- package/dist_browser_SoundsPlugin_js.js +12 -12
- package/esm/Options/Classes/Sounds.js +5 -0
- package/esm/Options/Classes/SoundsAudio.js +2 -0
- package/esm/Options/Classes/SoundsEvent.js +5 -0
- package/esm/Options/Classes/SoundsIcon.js +5 -0
- package/esm/Options/Classes/SoundsIcons.js +5 -0
- package/esm/Options/Classes/SoundsMelody.js +3 -0
- package/esm/Options/Classes/SoundsNote.js +2 -0
- package/esm/Options/Classes/SoundsVolume.js +4 -0
- package/esm/SoundsPlugin.js +2 -1
- package/esm/SoundsPluginInstance.js +247 -240
- package/esm/index.js +1 -1
- package/package.json +2 -2
- package/report.html +3 -3
- package/tsparticles.plugin.sounds.js +31 -19
- package/tsparticles.plugin.sounds.min.js +2 -2
- package/types/SoundsPlugin.d.ts +1 -1
- package/umd/Options/Classes/Sounds.js +5 -0
- package/umd/Options/Classes/SoundsAudio.js +2 -0
- package/umd/Options/Classes/SoundsEvent.js +5 -0
- package/umd/Options/Classes/SoundsIcon.js +5 -0
- package/umd/Options/Classes/SoundsIcons.js +5 -0
- package/umd/Options/Classes/SoundsMelody.js +3 -0
- package/umd/Options/Classes/SoundsNote.js +2 -0
- package/umd/Options/Classes/SoundsVolume.js +4 -0
- package/umd/SoundsPlugin.js +2 -1
- package/umd/SoundsPluginInstance.js +247 -240
- package/umd/index.js +1 -1
- package/296.min.js +0 -2
- package/296.min.js.LICENSE.txt +0 -1
- package/340.min.js +0 -2
- package/340.min.js.LICENSE.txt +0 -1
- package/tsparticles.plugin.sounds.min.js.LICENSE.txt +0 -1
|
@@ -6,9 +6,7 @@ const zIndexOffset = 1, rightOffset = 1, minVolume = 0;
|
|
|
6
6
|
function initImage(data) {
|
|
7
7
|
const img = safeDocument().createElement("img"), { clickCb, container, display, iconOptions, margin, options, pos, rightOffsets } = data, { width, path, style, svg } = iconOptions, defaultAccumulator = 0;
|
|
8
8
|
setIconStyle(img, pos.top + margin, pos.right -
|
|
9
|
-
(margin * (rightOffsets.length + rightOffset) +
|
|
10
|
-
width +
|
|
11
|
-
rightOffsets.reduce((a, b) => a + b, defaultAccumulator)), display, options.fullScreen.zIndex + zIndexOffset, width, margin, style);
|
|
9
|
+
(margin * (rightOffsets.length + rightOffset) + width + rightOffsets.reduce((a, b) => a + b, defaultAccumulator)), display, options.fullScreen.zIndex + zIndexOffset, width, margin, style);
|
|
12
10
|
img.src = path ?? (svg ? `data:image/svg+xml;base64,${btoa(svg)}` : "");
|
|
13
11
|
const parent = container.canvas.element?.parentNode ?? safeDocument().body;
|
|
14
12
|
parent.append(img);
|
|
@@ -33,242 +31,17 @@ function setIconStyle(icon, top, left, display, zIndex, width, margin, style) {
|
|
|
33
31
|
icon.style.cssText += style;
|
|
34
32
|
}
|
|
35
33
|
export class SoundsPluginInstance {
|
|
34
|
+
_audioMap;
|
|
35
|
+
_audioSources;
|
|
36
|
+
_container;
|
|
37
|
+
_engine;
|
|
38
|
+
_gain;
|
|
39
|
+
_muteImg;
|
|
40
|
+
_unmuteImg;
|
|
41
|
+
_volume;
|
|
42
|
+
_volumeDownImg;
|
|
43
|
+
_volumeUpImg;
|
|
36
44
|
constructor(container, engine) {
|
|
37
|
-
this._addBuffer = audioCtx => {
|
|
38
|
-
const buffer = audioCtx.createBufferSource();
|
|
39
|
-
this._audioSources.push(buffer);
|
|
40
|
-
return buffer;
|
|
41
|
-
};
|
|
42
|
-
this._addOscillator = audioCtx => {
|
|
43
|
-
const oscillator = audioCtx.createOscillator();
|
|
44
|
-
this._audioSources.push(oscillator);
|
|
45
|
-
return oscillator;
|
|
46
|
-
};
|
|
47
|
-
this._initEvents = () => {
|
|
48
|
-
const container = this._container, soundsOptions = container.actualOptions.sounds;
|
|
49
|
-
if (!soundsOptions?.enable || !container.canvas.element) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
for (const event of soundsOptions.events) {
|
|
53
|
-
const cb = (args) => {
|
|
54
|
-
if (!args) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
void (async () => {
|
|
58
|
-
const filterNotValid = event.filter && !event.filter(args);
|
|
59
|
-
if (this._container !== args.container) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
if (!!this._container.muted || this._container.destroyed) {
|
|
63
|
-
executeOnSingleOrMultiple(event.event, item => {
|
|
64
|
-
this._engine.removeEventListener(item, cb);
|
|
65
|
-
});
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
if (filterNotValid) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
const defaultNoteIndex = 0;
|
|
72
|
-
if (event.audio) {
|
|
73
|
-
const audio = itemFromSingleOrMultiple(event.audio);
|
|
74
|
-
if (!audio) {
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
this._playBuffer(audio);
|
|
78
|
-
}
|
|
79
|
-
else if (event.melodies) {
|
|
80
|
-
const melody = itemFromArray(event.melodies);
|
|
81
|
-
if (!melody) {
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
if (melody.melodies.length) {
|
|
85
|
-
await Promise.allSettled(melody.melodies.map(m => this._playNote(m.notes, defaultNoteIndex, melody.loop)));
|
|
86
|
-
}
|
|
87
|
-
else {
|
|
88
|
-
await this._playNote(melody.notes, defaultNoteIndex, melody.loop);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
else if (event.notes) {
|
|
92
|
-
const note = itemFromArray(event.notes);
|
|
93
|
-
if (!note) {
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
await this._playNote([note], defaultNoteIndex, false);
|
|
97
|
-
}
|
|
98
|
-
})();
|
|
99
|
-
};
|
|
100
|
-
executeOnSingleOrMultiple(event.event, item => {
|
|
101
|
-
this._engine.addEventListener(item, cb);
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
this._mute = async () => {
|
|
106
|
-
const container = this._container, audioContext = this._getAudioContext();
|
|
107
|
-
for (const source of this._audioSources) {
|
|
108
|
-
this._removeAudioSource(source);
|
|
109
|
-
}
|
|
110
|
-
if (this._gain) {
|
|
111
|
-
this._gain.disconnect();
|
|
112
|
-
}
|
|
113
|
-
await audioContext.close();
|
|
114
|
-
container.audioContext = undefined;
|
|
115
|
-
this._engine.dispatchEvent(SoundsEventType.mute, { container: this._container });
|
|
116
|
-
};
|
|
117
|
-
this._playBuffer = audio => {
|
|
118
|
-
const audioBuffer = this._audioMap.get(audio.source);
|
|
119
|
-
if (!audioBuffer) {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
const audioCtx = this._container.audioContext;
|
|
123
|
-
if (!audioCtx) {
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
const source = this._addBuffer(audioCtx);
|
|
127
|
-
source.loop = audio.loop;
|
|
128
|
-
source.buffer = audioBuffer;
|
|
129
|
-
source.connect(this._gain ?? audioCtx.destination);
|
|
130
|
-
source.start();
|
|
131
|
-
};
|
|
132
|
-
this._playFrequency = async (frequency, duration) => {
|
|
133
|
-
if (!this._gain || this._container.muted) {
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
const audioContext = this._getAudioContext(), oscillator = this._addOscillator(audioContext);
|
|
137
|
-
oscillator.connect(this._gain);
|
|
138
|
-
oscillator.type = "sine";
|
|
139
|
-
oscillator.frequency.value = frequency;
|
|
140
|
-
oscillator.start();
|
|
141
|
-
return new Promise(resolve => {
|
|
142
|
-
setTimeout(() => {
|
|
143
|
-
this._removeAudioSource(oscillator);
|
|
144
|
-
resolve();
|
|
145
|
-
}, duration);
|
|
146
|
-
});
|
|
147
|
-
};
|
|
148
|
-
this._playMuteSound = () => {
|
|
149
|
-
if (this._container.muted) {
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
const audioContext = this._getAudioContext(), gain = audioContext.createGain();
|
|
153
|
-
gain.connect(audioContext.destination);
|
|
154
|
-
gain.gain.value = 0;
|
|
155
|
-
const oscillator = audioContext.createOscillator();
|
|
156
|
-
oscillator.connect(gain);
|
|
157
|
-
oscillator.type = "sine";
|
|
158
|
-
oscillator.frequency.value = 1;
|
|
159
|
-
oscillator.start();
|
|
160
|
-
setTimeout(() => {
|
|
161
|
-
oscillator.stop();
|
|
162
|
-
oscillator.disconnect();
|
|
163
|
-
gain.disconnect();
|
|
164
|
-
});
|
|
165
|
-
};
|
|
166
|
-
this._playNote = async (notes, noteIdx, loop) => {
|
|
167
|
-
if (this._container.muted) {
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
const note = notes[noteIdx];
|
|
171
|
-
if (!note) {
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
const value = note.value, promises = executeOnSingleOrMultiple(value, async (_, idx) => {
|
|
175
|
-
return this._playNoteValue(notes, noteIdx, idx);
|
|
176
|
-
});
|
|
177
|
-
await (isArray(promises) ? Promise.allSettled(promises) : promises);
|
|
178
|
-
const indexOffset = 1;
|
|
179
|
-
let nextNoteIdx = noteIdx + indexOffset;
|
|
180
|
-
if (loop && nextNoteIdx >= notes.length) {
|
|
181
|
-
nextNoteIdx = nextNoteIdx % notes.length;
|
|
182
|
-
}
|
|
183
|
-
await this._playNote(notes, nextNoteIdx, loop);
|
|
184
|
-
};
|
|
185
|
-
this._playNoteValue = async (notes, noteIdx, valueIdx) => {
|
|
186
|
-
const note = notes[noteIdx];
|
|
187
|
-
if (!note) {
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
const value = itemFromSingleOrMultiple(note.value, valueIdx, true);
|
|
191
|
-
if (!value) {
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
try {
|
|
195
|
-
const freq = getNoteFrequency(value);
|
|
196
|
-
if (!isNumber(freq)) {
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
await this._playFrequency(freq, note.duration);
|
|
200
|
-
}
|
|
201
|
-
catch (e) {
|
|
202
|
-
getLogger().error(e);
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
this._removeAudioSource = source => {
|
|
206
|
-
source.stop();
|
|
207
|
-
source.disconnect();
|
|
208
|
-
const deleteCount = 1;
|
|
209
|
-
this._audioSources.splice(this._audioSources.indexOf(source), deleteCount);
|
|
210
|
-
};
|
|
211
|
-
this._unmute = () => {
|
|
212
|
-
const container = this._container, options = container.actualOptions, soundsOptions = options.sounds;
|
|
213
|
-
if (!soundsOptions) {
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
const audioContext = this._getAudioContext(), gain = audioContext.createGain();
|
|
217
|
-
gain.connect(audioContext.destination);
|
|
218
|
-
gain.gain.value = soundsOptions.volume.value / percentDenominator;
|
|
219
|
-
this._gain = gain;
|
|
220
|
-
this._initEvents();
|
|
221
|
-
this._engine.dispatchEvent(SoundsEventType.unmute, { container: this._container });
|
|
222
|
-
};
|
|
223
|
-
this._updateMuteIcons = () => {
|
|
224
|
-
const container = this._container, soundsOptions = container.actualOptions.sounds;
|
|
225
|
-
if (!soundsOptions?.enable || !soundsOptions.icons.enable) {
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
const muteImg = this._muteImg, unmuteImg = this._unmuteImg;
|
|
229
|
-
if (muteImg) {
|
|
230
|
-
muteImg.style.display = container.muted ? "block" : "none";
|
|
231
|
-
}
|
|
232
|
-
if (unmuteImg) {
|
|
233
|
-
unmuteImg.style.display = container.muted ? "none" : "block";
|
|
234
|
-
}
|
|
235
|
-
};
|
|
236
|
-
this._updateMuteStatus = async () => {
|
|
237
|
-
const container = this._container, audioContext = this._getAudioContext();
|
|
238
|
-
if (container.muted) {
|
|
239
|
-
await audioContext.suspend();
|
|
240
|
-
await this._mute();
|
|
241
|
-
}
|
|
242
|
-
else {
|
|
243
|
-
await audioContext.resume();
|
|
244
|
-
this._unmute();
|
|
245
|
-
this._playMuteSound();
|
|
246
|
-
}
|
|
247
|
-
};
|
|
248
|
-
this._updateVolume = async () => {
|
|
249
|
-
const container = this._container, soundsOptions = container.actualOptions.sounds;
|
|
250
|
-
if (!soundsOptions?.enable) {
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
clamp(this._volume, soundsOptions.volume.min, soundsOptions.volume.max);
|
|
254
|
-
let stateChanged = false;
|
|
255
|
-
if (this._volume <= minVolume && !container.muted) {
|
|
256
|
-
this._volume = 0;
|
|
257
|
-
container.muted = true;
|
|
258
|
-
stateChanged = true;
|
|
259
|
-
}
|
|
260
|
-
else if (this._volume > minVolume && container.muted) {
|
|
261
|
-
container.muted = false;
|
|
262
|
-
stateChanged = true;
|
|
263
|
-
}
|
|
264
|
-
if (stateChanged) {
|
|
265
|
-
this._updateMuteIcons();
|
|
266
|
-
await this._updateMuteStatus();
|
|
267
|
-
}
|
|
268
|
-
if (this._gain?.gain) {
|
|
269
|
-
this._gain.gain.value = this._volume / percentDenominator;
|
|
270
|
-
}
|
|
271
|
-
};
|
|
272
45
|
this._container = container;
|
|
273
46
|
this._engine = engine;
|
|
274
47
|
this._volume = 0;
|
|
@@ -286,8 +59,7 @@ export class SoundsPluginInstance {
|
|
|
286
59
|
removeEventListener(touchStartEvent, firstClickHandler);
|
|
287
60
|
unmuteWindow();
|
|
288
61
|
void this.unmute();
|
|
289
|
-
}
|
|
290
|
-
const listenerOptions = {
|
|
62
|
+
}, listenerOptions = {
|
|
291
63
|
capture: true,
|
|
292
64
|
once: true,
|
|
293
65
|
};
|
|
@@ -422,9 +194,244 @@ export class SoundsPluginInstance {
|
|
|
422
194
|
this._volume += soundsOptions.volume.step;
|
|
423
195
|
await this._updateVolume();
|
|
424
196
|
}
|
|
197
|
+
_addBuffer = audioCtx => {
|
|
198
|
+
const buffer = audioCtx.createBufferSource();
|
|
199
|
+
this._audioSources.push(buffer);
|
|
200
|
+
return buffer;
|
|
201
|
+
};
|
|
202
|
+
_addOscillator = audioCtx => {
|
|
203
|
+
const oscillator = audioCtx.createOscillator();
|
|
204
|
+
this._audioSources.push(oscillator);
|
|
205
|
+
return oscillator;
|
|
206
|
+
};
|
|
425
207
|
_getAudioContext() {
|
|
426
208
|
const container = this._container;
|
|
427
209
|
container.audioContext ??= new AudioContext();
|
|
428
210
|
return container.audioContext;
|
|
429
211
|
}
|
|
212
|
+
_initEvents = () => {
|
|
213
|
+
const container = this._container, soundsOptions = container.actualOptions.sounds;
|
|
214
|
+
if (!soundsOptions?.enable || !container.canvas.element) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
for (const event of soundsOptions.events) {
|
|
218
|
+
const cb = (args) => {
|
|
219
|
+
if (!args) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
void (async () => {
|
|
223
|
+
const filterNotValid = event.filter && !event.filter(args);
|
|
224
|
+
if (this._container !== args.container) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (!!this._container.muted || this._container.destroyed) {
|
|
228
|
+
executeOnSingleOrMultiple(event.event, item => {
|
|
229
|
+
this._engine.removeEventListener(item, cb);
|
|
230
|
+
});
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
if (filterNotValid) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const defaultNoteIndex = 0;
|
|
237
|
+
if (event.audio) {
|
|
238
|
+
const audio = itemFromSingleOrMultiple(event.audio);
|
|
239
|
+
if (!audio) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
this._playBuffer(audio);
|
|
243
|
+
}
|
|
244
|
+
else if (event.melodies) {
|
|
245
|
+
const melody = itemFromArray(event.melodies);
|
|
246
|
+
if (!melody) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
if (melody.melodies.length) {
|
|
250
|
+
await Promise.allSettled(melody.melodies.map(m => this._playNote(m.notes, defaultNoteIndex, melody.loop)));
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
await this._playNote(melody.notes, defaultNoteIndex, melody.loop);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
else if (event.notes) {
|
|
257
|
+
const note = itemFromArray(event.notes);
|
|
258
|
+
if (!note) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
await this._playNote([note], defaultNoteIndex, false);
|
|
262
|
+
}
|
|
263
|
+
})();
|
|
264
|
+
};
|
|
265
|
+
executeOnSingleOrMultiple(event.event, item => {
|
|
266
|
+
this._engine.addEventListener(item, cb);
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
_mute = async () => {
|
|
271
|
+
const container = this._container, audioContext = this._getAudioContext();
|
|
272
|
+
for (const source of this._audioSources) {
|
|
273
|
+
this._removeAudioSource(source);
|
|
274
|
+
}
|
|
275
|
+
if (this._gain) {
|
|
276
|
+
this._gain.disconnect();
|
|
277
|
+
}
|
|
278
|
+
await audioContext.close();
|
|
279
|
+
container.audioContext = undefined;
|
|
280
|
+
this._engine.dispatchEvent(SoundsEventType.mute, { container: this._container });
|
|
281
|
+
};
|
|
282
|
+
_playBuffer = audio => {
|
|
283
|
+
const audioBuffer = this._audioMap.get(audio.source);
|
|
284
|
+
if (!audioBuffer) {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const audioCtx = this._container.audioContext;
|
|
288
|
+
if (!audioCtx) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const source = this._addBuffer(audioCtx);
|
|
292
|
+
source.loop = audio.loop;
|
|
293
|
+
source.buffer = audioBuffer;
|
|
294
|
+
source.connect(this._gain ?? audioCtx.destination);
|
|
295
|
+
source.start();
|
|
296
|
+
};
|
|
297
|
+
_playFrequency = async (frequency, duration) => {
|
|
298
|
+
if (!this._gain || this._container.muted) {
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
const audioContext = this._getAudioContext(), oscillator = this._addOscillator(audioContext);
|
|
302
|
+
oscillator.connect(this._gain);
|
|
303
|
+
oscillator.type = "sine";
|
|
304
|
+
oscillator.frequency.value = frequency;
|
|
305
|
+
oscillator.start();
|
|
306
|
+
return new Promise(resolve => {
|
|
307
|
+
setTimeout(() => {
|
|
308
|
+
this._removeAudioSource(oscillator);
|
|
309
|
+
resolve();
|
|
310
|
+
}, duration);
|
|
311
|
+
});
|
|
312
|
+
};
|
|
313
|
+
_playMuteSound = () => {
|
|
314
|
+
if (this._container.muted) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const audioContext = this._getAudioContext(), gain = audioContext.createGain();
|
|
318
|
+
gain.connect(audioContext.destination);
|
|
319
|
+
gain.gain.value = 0;
|
|
320
|
+
const oscillator = audioContext.createOscillator();
|
|
321
|
+
oscillator.connect(gain);
|
|
322
|
+
oscillator.type = "sine";
|
|
323
|
+
oscillator.frequency.value = 1;
|
|
324
|
+
oscillator.start();
|
|
325
|
+
setTimeout(() => {
|
|
326
|
+
oscillator.stop();
|
|
327
|
+
oscillator.disconnect();
|
|
328
|
+
gain.disconnect();
|
|
329
|
+
});
|
|
330
|
+
};
|
|
331
|
+
_playNote = async (notes, noteIdx, loop) => {
|
|
332
|
+
if (this._container.muted) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const note = notes[noteIdx];
|
|
336
|
+
if (!note) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
const value = note.value, promises = executeOnSingleOrMultiple(value, async (_, idx) => {
|
|
340
|
+
return this._playNoteValue(notes, noteIdx, idx);
|
|
341
|
+
});
|
|
342
|
+
await (isArray(promises) ? Promise.allSettled(promises) : promises);
|
|
343
|
+
const indexOffset = 1;
|
|
344
|
+
let nextNoteIdx = noteIdx + indexOffset;
|
|
345
|
+
if (loop && nextNoteIdx >= notes.length) {
|
|
346
|
+
nextNoteIdx = nextNoteIdx % notes.length;
|
|
347
|
+
}
|
|
348
|
+
await this._playNote(notes, nextNoteIdx, loop);
|
|
349
|
+
};
|
|
350
|
+
_playNoteValue = async (notes, noteIdx, valueIdx) => {
|
|
351
|
+
const note = notes[noteIdx];
|
|
352
|
+
if (!note) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const value = itemFromSingleOrMultiple(note.value, valueIdx, true);
|
|
356
|
+
if (!value) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
try {
|
|
360
|
+
const freq = getNoteFrequency(value);
|
|
361
|
+
if (!isNumber(freq)) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
await this._playFrequency(freq, note.duration);
|
|
365
|
+
}
|
|
366
|
+
catch (e) {
|
|
367
|
+
getLogger().error(e);
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
_removeAudioSource = source => {
|
|
371
|
+
source.stop();
|
|
372
|
+
source.disconnect();
|
|
373
|
+
const deleteCount = 1;
|
|
374
|
+
this._audioSources.splice(this._audioSources.indexOf(source), deleteCount);
|
|
375
|
+
};
|
|
376
|
+
_unmute = () => {
|
|
377
|
+
const container = this._container, options = container.actualOptions, soundsOptions = options.sounds;
|
|
378
|
+
if (!soundsOptions) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
const audioContext = this._getAudioContext(), gain = audioContext.createGain();
|
|
382
|
+
gain.connect(audioContext.destination);
|
|
383
|
+
gain.gain.value = soundsOptions.volume.value / percentDenominator;
|
|
384
|
+
this._gain = gain;
|
|
385
|
+
this._initEvents();
|
|
386
|
+
this._engine.dispatchEvent(SoundsEventType.unmute, { container: this._container });
|
|
387
|
+
};
|
|
388
|
+
_updateMuteIcons = () => {
|
|
389
|
+
const container = this._container, soundsOptions = container.actualOptions.sounds;
|
|
390
|
+
if (!soundsOptions?.enable || !soundsOptions.icons.enable) {
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
const muteImg = this._muteImg, unmuteImg = this._unmuteImg;
|
|
394
|
+
if (muteImg) {
|
|
395
|
+
muteImg.style.display = container.muted ? "block" : "none";
|
|
396
|
+
}
|
|
397
|
+
if (unmuteImg) {
|
|
398
|
+
unmuteImg.style.display = container.muted ? "none" : "block";
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
_updateMuteStatus = async () => {
|
|
402
|
+
const container = this._container, audioContext = this._getAudioContext();
|
|
403
|
+
if (container.muted) {
|
|
404
|
+
await audioContext.suspend();
|
|
405
|
+
await this._mute();
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
await audioContext.resume();
|
|
409
|
+
this._unmute();
|
|
410
|
+
this._playMuteSound();
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
_updateVolume = async () => {
|
|
414
|
+
const container = this._container, soundsOptions = container.actualOptions.sounds;
|
|
415
|
+
if (!soundsOptions?.enable) {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
clamp(this._volume, soundsOptions.volume.min, soundsOptions.volume.max);
|
|
419
|
+
let stateChanged = false;
|
|
420
|
+
if (this._volume <= minVolume && !container.muted) {
|
|
421
|
+
this._volume = 0;
|
|
422
|
+
container.muted = true;
|
|
423
|
+
stateChanged = true;
|
|
424
|
+
}
|
|
425
|
+
else if (this._volume > minVolume && container.muted) {
|
|
426
|
+
container.muted = false;
|
|
427
|
+
stateChanged = true;
|
|
428
|
+
}
|
|
429
|
+
if (stateChanged) {
|
|
430
|
+
this._updateMuteIcons();
|
|
431
|
+
await this._updateMuteStatus();
|
|
432
|
+
}
|
|
433
|
+
if (this._gain?.gain) {
|
|
434
|
+
this._gain.gain.value = this._volume / percentDenominator;
|
|
435
|
+
}
|
|
436
|
+
};
|
|
430
437
|
}
|
package/cjs/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Demo / Generator : https://particles.js.org/
|
|
5
5
|
* GitHub : https://www.github.com/matteobruni/tsparticles
|
|
6
6
|
* How to use? : Check the GitHub README
|
|
7
|
-
* v4.0.0-
|
|
7
|
+
* v4.0.0-beta.0
|
|
8
8
|
*/
|
|
9
9
|
"use strict";
|
|
10
10
|
/*
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
\**********************************************/
|
|
24
24
|
(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
|
|
25
25
|
|
|
26
|
-
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ SoundsPluginInstance: () => (/* binding */ SoundsPluginInstance)\n/* harmony export */ });\n/* harmony import */ var _tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tsparticles/engine */ \"@tsparticles/engine\");\n/* harmony import */ var _enums_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./enums.js */ \"./dist/browser/enums.js\");\n/* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils.js */ \"./dist/browser/utils.js\");\n/* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./constants.js */ \"./dist/browser/constants.js\");\n\n\n\n\nconst zIndexOffset = 1,\n rightOffset = 1,\n minVolume = 0;\nfunction initImage(data) {\n const img = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.safeDocument)().createElement(\"img\"),\n {\n clickCb,\n container,\n display,\n iconOptions,\n margin,\n options,\n pos,\n rightOffsets\n } = data,\n {\n width,\n path,\n style,\n svg\n } = iconOptions,\n defaultAccumulator = 0;\n setIconStyle(img, pos.top + margin, pos.right - (margin * (rightOffsets.length + rightOffset) + width + rightOffsets.reduce((a, b) => a + b, defaultAccumulator)), display, options.fullScreen.zIndex + zIndexOffset, width, margin, style);\n img.src = path ?? (svg ? `data:image/svg+xml;base64,${btoa(svg)}` : \"\");\n const parent = container.canvas.element?.parentNode ?? (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.safeDocument)().body;\n parent.append(img);\n img.addEventListener(\"click\", () => {\n void clickCb();\n });\n return img;\n}\nfunction removeImage(image) {\n if (!image) {\n return;\n }\n image.remove();\n}\nfunction setIconStyle(icon, top, left, display, zIndex, width, margin, style) {\n icon.style.userSelect = \"none\";\n icon.style.position = \"absolute\";\n icon.style.top = `${(top + margin).toString()}px`;\n icon.style.left = `${(left - margin - width).toString()}px`;\n icon.style.display = display;\n icon.style.zIndex = (zIndex + zIndexOffset).toString();\n icon.style.cssText += style;\n}\nclass SoundsPluginInstance {\n constructor(container, engine) {\n this._addBuffer = audioCtx => {\n const buffer = audioCtx.createBufferSource();\n this._audioSources.push(buffer);\n return buffer;\n };\n this._addOscillator = audioCtx => {\n const oscillator = audioCtx.createOscillator();\n this._audioSources.push(oscillator);\n return oscillator;\n };\n this._initEvents = () => {\n const container = this._container,\n soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable || !container.canvas.element) {\n return;\n }\n for (const event of soundsOptions.events) {\n const cb = args => {\n if (!args) {\n return;\n }\n void (async () => {\n const filterNotValid = event.filter && !event.filter(args);\n if (this._container !== args.container) {\n return;\n }\n if (!!this._container.muted || this._container.destroyed) {\n (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.executeOnSingleOrMultiple)(event.event, item => {\n this._engine.removeEventListener(item, cb);\n });\n return;\n }\n if (filterNotValid) {\n return;\n }\n const defaultNoteIndex = 0;\n if (event.audio) {\n const audio = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.itemFromSingleOrMultiple)(event.audio);\n if (!audio) {\n return;\n }\n this._playBuffer(audio);\n } else if (event.melodies) {\n const melody = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.itemFromArray)(event.melodies);\n if (!melody) {\n return;\n }\n if (melody.melodies.length) {\n await Promise.allSettled(melody.melodies.map(m => this._playNote(m.notes, defaultNoteIndex, melody.loop)));\n } else {\n await this._playNote(melody.notes, defaultNoteIndex, melody.loop);\n }\n } else if (event.notes) {\n const note = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.itemFromArray)(event.notes);\n if (!note) {\n return;\n }\n await this._playNote([note], defaultNoteIndex, false);\n }\n })();\n };\n (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.executeOnSingleOrMultiple)(event.event, item => {\n this._engine.addEventListener(item, cb);\n });\n }\n };\n this._mute = async () => {\n const container = this._container,\n audioContext = this._getAudioContext();\n for (const source of this._audioSources) {\n this._removeAudioSource(source);\n }\n if (this._gain) {\n this._gain.disconnect();\n }\n await audioContext.close();\n container.audioContext = undefined;\n this._engine.dispatchEvent(_enums_js__WEBPACK_IMPORTED_MODULE_1__.SoundsEventType.mute, {\n container: this._container\n });\n };\n this._playBuffer = audio => {\n const audioBuffer = this._audioMap.get(audio.source);\n if (!audioBuffer) {\n return;\n }\n const audioCtx = this._container.audioContext;\n if (!audioCtx) {\n return;\n }\n const source = this._addBuffer(audioCtx);\n source.loop = audio.loop;\n source.buffer = audioBuffer;\n source.connect(this._gain ?? audioCtx.destination);\n source.start();\n };\n this._playFrequency = async (frequency, duration) => {\n if (!this._gain || this._container.muted) {\n return;\n }\n const audioContext = this._getAudioContext(),\n oscillator = this._addOscillator(audioContext);\n oscillator.connect(this._gain);\n oscillator.type = \"sine\";\n oscillator.frequency.value = frequency;\n oscillator.start();\n return new Promise(resolve => {\n setTimeout(() => {\n this._removeAudioSource(oscillator);\n resolve();\n }, duration);\n });\n };\n this._playMuteSound = () => {\n if (this._container.muted) {\n return;\n }\n const audioContext = this._getAudioContext(),\n gain = audioContext.createGain();\n gain.connect(audioContext.destination);\n gain.gain.value = 0;\n const oscillator = audioContext.createOscillator();\n oscillator.connect(gain);\n oscillator.type = \"sine\";\n oscillator.frequency.value = 1;\n oscillator.start();\n setTimeout(() => {\n oscillator.stop();\n oscillator.disconnect();\n gain.disconnect();\n });\n };\n this._playNote = async (notes, noteIdx, loop) => {\n if (this._container.muted) {\n return;\n }\n const note = notes[noteIdx];\n if (!note) {\n return;\n }\n const value = note.value,\n promises = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.executeOnSingleOrMultiple)(value, async (_, idx) => {\n return this._playNoteValue(notes, noteIdx, idx);\n });\n await ((0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.isArray)(promises) ? Promise.allSettled(promises) : promises);\n const indexOffset = 1;\n let nextNoteIdx = noteIdx + indexOffset;\n if (loop && nextNoteIdx >= notes.length) {\n nextNoteIdx = nextNoteIdx % notes.length;\n }\n await this._playNote(notes, nextNoteIdx, loop);\n };\n this._playNoteValue = async (notes, noteIdx, valueIdx) => {\n const note = notes[noteIdx];\n if (!note) {\n return;\n }\n const value = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.itemFromSingleOrMultiple)(note.value, valueIdx, true);\n if (!value) {\n return;\n }\n try {\n const freq = (0,_utils_js__WEBPACK_IMPORTED_MODULE_2__.getNoteFrequency)(value);\n if (!(0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.isNumber)(freq)) {\n return;\n }\n await this._playFrequency(freq, note.duration);\n } catch (e) {\n (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.getLogger)().error(e);\n }\n };\n this._removeAudioSource = source => {\n source.stop();\n source.disconnect();\n const deleteCount = 1;\n this._audioSources.splice(this._audioSources.indexOf(source), deleteCount);\n };\n this._unmute = () => {\n const container = this._container,\n options = container.actualOptions,\n soundsOptions = options.sounds;\n if (!soundsOptions) {\n return;\n }\n const audioContext = this._getAudioContext(),\n gain = audioContext.createGain();\n gain.connect(audioContext.destination);\n gain.gain.value = soundsOptions.volume.value / _tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.percentDenominator;\n this._gain = gain;\n this._initEvents();\n this._engine.dispatchEvent(_enums_js__WEBPACK_IMPORTED_MODULE_1__.SoundsEventType.unmute, {\n container: this._container\n });\n };\n this._updateMuteIcons = () => {\n const container = this._container,\n soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable || !soundsOptions.icons.enable) {\n return;\n }\n const muteImg = this._muteImg,\n unmuteImg = this._unmuteImg;\n if (muteImg) {\n muteImg.style.display = container.muted ? \"block\" : \"none\";\n }\n if (unmuteImg) {\n unmuteImg.style.display = container.muted ? \"none\" : \"block\";\n }\n };\n this._updateMuteStatus = async () => {\n const container = this._container,\n audioContext = this._getAudioContext();\n if (container.muted) {\n await audioContext.suspend();\n await this._mute();\n } else {\n await audioContext.resume();\n this._unmute();\n this._playMuteSound();\n }\n };\n this._updateVolume = async () => {\n const container = this._container,\n soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable) {\n return;\n }\n (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.clamp)(this._volume, soundsOptions.volume.min, soundsOptions.volume.max);\n let stateChanged = false;\n if (this._volume <= minVolume && !container.muted) {\n this._volume = 0;\n container.muted = true;\n stateChanged = true;\n } else if (this._volume > minVolume && container.muted) {\n container.muted = false;\n stateChanged = true;\n }\n if (stateChanged) {\n this._updateMuteIcons();\n await this._updateMuteStatus();\n }\n if (this._gain?.gain) {\n this._gain.gain.value = this._volume / _tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.percentDenominator;\n }\n };\n this._container = container;\n this._engine = engine;\n this._volume = 0;\n this._audioSources = [];\n this._audioMap = new Map();\n }\n async init() {\n const container = this._container,\n options = container.actualOptions,\n soundsOptions = options.sounds;\n if (!soundsOptions?.enable) {\n return;\n }\n if (soundsOptions.autoPlay && (0,_utils_js__WEBPACK_IMPORTED_MODULE_2__.isWindowMuted)()) {\n const firstClickHandler = () => {\n removeEventListener(_constants_js__WEBPACK_IMPORTED_MODULE_3__.mouseDownEvent, firstClickHandler);\n removeEventListener(_constants_js__WEBPACK_IMPORTED_MODULE_3__.touchStartEvent, firstClickHandler);\n (0,_utils_js__WEBPACK_IMPORTED_MODULE_2__.unmuteWindow)();\n void this.unmute();\n };\n const listenerOptions = {\n capture: true,\n once: true\n };\n addEventListener(_constants_js__WEBPACK_IMPORTED_MODULE_3__.mouseDownEvent, firstClickHandler, listenerOptions);\n addEventListener(_constants_js__WEBPACK_IMPORTED_MODULE_3__.touchStartEvent, firstClickHandler, listenerOptions);\n }\n this._volume = soundsOptions.volume.value;\n const events = soundsOptions.events;\n this._audioMap = new Map();\n for (const event of events) {\n if (!event.audio) {\n continue;\n }\n const promises = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.executeOnSingleOrMultiple)(event.audio, async audio => {\n const response = await fetch(audio.source);\n if (!response.ok) {\n return;\n }\n const arrayBuffer = await response.arrayBuffer(),\n audioContext = this._getAudioContext(),\n audioBuffer = await audioContext.decodeAudioData(arrayBuffer);\n this._audioMap.set(audio.source, audioBuffer);\n });\n if (promises instanceof Promise) {\n await promises;\n } else {\n await Promise.allSettled(promises);\n }\n }\n }\n async mute() {\n if (!this._container.muted) {\n await this.toggleMute();\n }\n }\n async start() {\n const container = this._container,\n options = container.actualOptions,\n soundsOptions = options.sounds;\n if (!soundsOptions?.enable || !container.canvas.element) {\n return;\n }\n container.muted = true;\n const canvas = container.canvas.element,\n pos = {\n top: canvas.offsetTop,\n right: canvas.offsetLeft + canvas.offsetWidth\n },\n {\n mute,\n unmute,\n volumeDown,\n volumeUp\n } = soundsOptions.icons,\n margin = 10,\n toggleMute = async () => {\n await this.toggleMute();\n },\n enableIcons = soundsOptions.icons.enable,\n display = enableIcons ? _enums_js__WEBPACK_IMPORTED_MODULE_1__.ImageDisplay.Block : _enums_js__WEBPACK_IMPORTED_MODULE_1__.ImageDisplay.None;\n this._muteImg = initImage({\n container,\n options,\n pos,\n display,\n iconOptions: mute,\n margin,\n rightOffsets: [volumeDown.width, volumeUp.width],\n clickCb: toggleMute\n });\n this._unmuteImg = initImage({\n container,\n options,\n pos,\n display: _enums_js__WEBPACK_IMPORTED_MODULE_1__.ImageDisplay.None,\n iconOptions: unmute,\n margin,\n rightOffsets: [volumeDown.width, volumeUp.width],\n clickCb: toggleMute\n });\n this._volumeDownImg = initImage({\n container,\n options,\n pos,\n display,\n iconOptions: volumeDown,\n margin,\n rightOffsets: [volumeUp.width],\n clickCb: async () => {\n await this.volumeDown();\n }\n });\n this._volumeUpImg = initImage({\n container,\n options,\n pos,\n display,\n iconOptions: volumeUp,\n margin,\n rightOffsets: [],\n clickCb: async () => {\n await this.volumeUp();\n }\n });\n if (!(0,_utils_js__WEBPACK_IMPORTED_MODULE_2__.isWindowMuted)() && soundsOptions.autoPlay) {\n await this.unmute();\n }\n }\n stop() {\n this._container.muted = true;\n void (async () => {\n await this._mute();\n removeImage(this._muteImg);\n removeImage(this._unmuteImg);\n removeImage(this._volumeDownImg);\n removeImage(this._volumeUpImg);\n })();\n }\n async toggleMute() {\n const container = this._container;\n container.muted = !container.muted;\n this._updateMuteIcons();\n await this._updateMuteStatus();\n }\n async unmute() {\n if (this._container.muted) {\n await this.toggleMute();\n }\n }\n async volumeDown() {\n const container = this._container,\n soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable) {\n return;\n }\n if (container.muted) {\n this._volume = 0;\n }\n this._volume -= soundsOptions.volume.step;\n await this._updateVolume();\n }\n async volumeUp() {\n const container = this._container,\n soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable) {\n return;\n }\n this._volume += soundsOptions.volume.step;\n await this._updateVolume();\n }\n _getAudioContext() {\n const container = this._container;\n container.audioContext ??= new AudioContext();\n return container.audioContext;\n }\n}\n\n//# sourceURL=webpack://@tsparticles/plugin-sounds/./dist/browser/SoundsPluginInstance.js?\n}");
|
|
26
|
+
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ SoundsPluginInstance: () => (/* binding */ SoundsPluginInstance)\n/* harmony export */ });\n/* harmony import */ var _tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @tsparticles/engine */ \"@tsparticles/engine\");\n/* harmony import */ var _enums_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./enums.js */ \"./dist/browser/enums.js\");\n/* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils.js */ \"./dist/browser/utils.js\");\n/* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./constants.js */ \"./dist/browser/constants.js\");\n\n\n\n\nconst zIndexOffset = 1, rightOffset = 1, minVolume = 0;\nfunction initImage(data) {\n const img = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.safeDocument)().createElement(\"img\"), { clickCb, container, display, iconOptions, margin, options, pos, rightOffsets } = data, { width, path, style, svg } = iconOptions, defaultAccumulator = 0;\n setIconStyle(img, pos.top + margin, pos.right - (margin * (rightOffsets.length + rightOffset) + width + rightOffsets.reduce((a, b)=>a + b, defaultAccumulator)), display, options.fullScreen.zIndex + zIndexOffset, width, margin, style);\n img.src = path ?? (svg ? `data:image/svg+xml;base64,${btoa(svg)}` : \"\");\n const parent = container.canvas.element?.parentNode ?? (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.safeDocument)().body;\n parent.append(img);\n img.addEventListener(\"click\", ()=>{\n void clickCb();\n });\n return img;\n}\nfunction removeImage(image) {\n if (!image) {\n return;\n }\n image.remove();\n}\nfunction setIconStyle(icon, top, left, display, zIndex, width, margin, style) {\n icon.style.userSelect = \"none\";\n icon.style.position = \"absolute\";\n icon.style.top = `${(top + margin).toString()}px`;\n icon.style.left = `${(left - margin - width).toString()}px`;\n icon.style.display = display;\n icon.style.zIndex = (zIndex + zIndexOffset).toString();\n icon.style.cssText += style;\n}\nclass SoundsPluginInstance {\n _audioMap;\n _audioSources;\n _container;\n _engine;\n _gain;\n _muteImg;\n _unmuteImg;\n _volume;\n _volumeDownImg;\n _volumeUpImg;\n constructor(container, engine){\n this._container = container;\n this._engine = engine;\n this._volume = 0;\n this._audioSources = [];\n this._audioMap = new Map();\n }\n async init() {\n const container = this._container, options = container.actualOptions, soundsOptions = options.sounds;\n if (!soundsOptions?.enable) {\n return;\n }\n if (soundsOptions.autoPlay && (0,_utils_js__WEBPACK_IMPORTED_MODULE_2__.isWindowMuted)()) {\n const firstClickHandler = ()=>{\n removeEventListener(_constants_js__WEBPACK_IMPORTED_MODULE_3__.mouseDownEvent, firstClickHandler);\n removeEventListener(_constants_js__WEBPACK_IMPORTED_MODULE_3__.touchStartEvent, firstClickHandler);\n (0,_utils_js__WEBPACK_IMPORTED_MODULE_2__.unmuteWindow)();\n void this.unmute();\n }, listenerOptions = {\n capture: true,\n once: true\n };\n addEventListener(_constants_js__WEBPACK_IMPORTED_MODULE_3__.mouseDownEvent, firstClickHandler, listenerOptions);\n addEventListener(_constants_js__WEBPACK_IMPORTED_MODULE_3__.touchStartEvent, firstClickHandler, listenerOptions);\n }\n this._volume = soundsOptions.volume.value;\n const events = soundsOptions.events;\n this._audioMap = new Map();\n for (const event of events){\n if (!event.audio) {\n continue;\n }\n const promises = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.executeOnSingleOrMultiple)(event.audio, async (audio)=>{\n const response = await fetch(audio.source);\n if (!response.ok) {\n return;\n }\n const arrayBuffer = await response.arrayBuffer(), audioContext = this._getAudioContext(), audioBuffer = await audioContext.decodeAudioData(arrayBuffer);\n this._audioMap.set(audio.source, audioBuffer);\n });\n if (promises instanceof Promise) {\n await promises;\n } else {\n await Promise.allSettled(promises);\n }\n }\n }\n async mute() {\n if (!this._container.muted) {\n await this.toggleMute();\n }\n }\n async start() {\n const container = this._container, options = container.actualOptions, soundsOptions = options.sounds;\n if (!soundsOptions?.enable || !container.canvas.element) {\n return;\n }\n container.muted = true;\n const canvas = container.canvas.element, pos = {\n top: canvas.offsetTop,\n right: canvas.offsetLeft + canvas.offsetWidth\n }, { mute, unmute, volumeDown, volumeUp } = soundsOptions.icons, margin = 10, toggleMute = async ()=>{\n await this.toggleMute();\n }, enableIcons = soundsOptions.icons.enable, display = enableIcons ? _enums_js__WEBPACK_IMPORTED_MODULE_1__.ImageDisplay.Block : _enums_js__WEBPACK_IMPORTED_MODULE_1__.ImageDisplay.None;\n this._muteImg = initImage({\n container,\n options,\n pos,\n display,\n iconOptions: mute,\n margin,\n rightOffsets: [\n volumeDown.width,\n volumeUp.width\n ],\n clickCb: toggleMute\n });\n this._unmuteImg = initImage({\n container,\n options,\n pos,\n display: _enums_js__WEBPACK_IMPORTED_MODULE_1__.ImageDisplay.None,\n iconOptions: unmute,\n margin,\n rightOffsets: [\n volumeDown.width,\n volumeUp.width\n ],\n clickCb: toggleMute\n });\n this._volumeDownImg = initImage({\n container,\n options,\n pos,\n display,\n iconOptions: volumeDown,\n margin,\n rightOffsets: [\n volumeUp.width\n ],\n clickCb: async ()=>{\n await this.volumeDown();\n }\n });\n this._volumeUpImg = initImage({\n container,\n options,\n pos,\n display,\n iconOptions: volumeUp,\n margin,\n rightOffsets: [],\n clickCb: async ()=>{\n await this.volumeUp();\n }\n });\n if (!(0,_utils_js__WEBPACK_IMPORTED_MODULE_2__.isWindowMuted)() && soundsOptions.autoPlay) {\n await this.unmute();\n }\n }\n stop() {\n this._container.muted = true;\n void (async ()=>{\n await this._mute();\n removeImage(this._muteImg);\n removeImage(this._unmuteImg);\n removeImage(this._volumeDownImg);\n removeImage(this._volumeUpImg);\n })();\n }\n async toggleMute() {\n const container = this._container;\n container.muted = !container.muted;\n this._updateMuteIcons();\n await this._updateMuteStatus();\n }\n async unmute() {\n if (this._container.muted) {\n await this.toggleMute();\n }\n }\n async volumeDown() {\n const container = this._container, soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable) {\n return;\n }\n if (container.muted) {\n this._volume = 0;\n }\n this._volume -= soundsOptions.volume.step;\n await this._updateVolume();\n }\n async volumeUp() {\n const container = this._container, soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable) {\n return;\n }\n this._volume += soundsOptions.volume.step;\n await this._updateVolume();\n }\n _addBuffer = (audioCtx)=>{\n const buffer = audioCtx.createBufferSource();\n this._audioSources.push(buffer);\n return buffer;\n };\n _addOscillator = (audioCtx)=>{\n const oscillator = audioCtx.createOscillator();\n this._audioSources.push(oscillator);\n return oscillator;\n };\n _getAudioContext() {\n const container = this._container;\n container.audioContext ??= new AudioContext();\n return container.audioContext;\n }\n _initEvents = ()=>{\n const container = this._container, soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable || !container.canvas.element) {\n return;\n }\n for (const event of soundsOptions.events){\n const cb = (args)=>{\n if (!args) {\n return;\n }\n void (async ()=>{\n const filterNotValid = event.filter && !event.filter(args);\n if (this._container !== args.container) {\n return;\n }\n if (!!this._container.muted || this._container.destroyed) {\n (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.executeOnSingleOrMultiple)(event.event, (item)=>{\n this._engine.removeEventListener(item, cb);\n });\n return;\n }\n if (filterNotValid) {\n return;\n }\n const defaultNoteIndex = 0;\n if (event.audio) {\n const audio = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.itemFromSingleOrMultiple)(event.audio);\n if (!audio) {\n return;\n }\n this._playBuffer(audio);\n } else if (event.melodies) {\n const melody = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.itemFromArray)(event.melodies);\n if (!melody) {\n return;\n }\n if (melody.melodies.length) {\n await Promise.allSettled(melody.melodies.map((m)=>this._playNote(m.notes, defaultNoteIndex, melody.loop)));\n } else {\n await this._playNote(melody.notes, defaultNoteIndex, melody.loop);\n }\n } else if (event.notes) {\n const note = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.itemFromArray)(event.notes);\n if (!note) {\n return;\n }\n await this._playNote([\n note\n ], defaultNoteIndex, false);\n }\n })();\n };\n (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.executeOnSingleOrMultiple)(event.event, (item)=>{\n this._engine.addEventListener(item, cb);\n });\n }\n };\n _mute = async ()=>{\n const container = this._container, audioContext = this._getAudioContext();\n for (const source of this._audioSources){\n this._removeAudioSource(source);\n }\n if (this._gain) {\n this._gain.disconnect();\n }\n await audioContext.close();\n container.audioContext = undefined;\n this._engine.dispatchEvent(_enums_js__WEBPACK_IMPORTED_MODULE_1__.SoundsEventType.mute, {\n container: this._container\n });\n };\n _playBuffer = (audio)=>{\n const audioBuffer = this._audioMap.get(audio.source);\n if (!audioBuffer) {\n return;\n }\n const audioCtx = this._container.audioContext;\n if (!audioCtx) {\n return;\n }\n const source = this._addBuffer(audioCtx);\n source.loop = audio.loop;\n source.buffer = audioBuffer;\n source.connect(this._gain ?? audioCtx.destination);\n source.start();\n };\n _playFrequency = async (frequency, duration)=>{\n if (!this._gain || this._container.muted) {\n return;\n }\n const audioContext = this._getAudioContext(), oscillator = this._addOscillator(audioContext);\n oscillator.connect(this._gain);\n oscillator.type = \"sine\";\n oscillator.frequency.value = frequency;\n oscillator.start();\n return new Promise((resolve)=>{\n setTimeout(()=>{\n this._removeAudioSource(oscillator);\n resolve();\n }, duration);\n });\n };\n _playMuteSound = ()=>{\n if (this._container.muted) {\n return;\n }\n const audioContext = this._getAudioContext(), gain = audioContext.createGain();\n gain.connect(audioContext.destination);\n gain.gain.value = 0;\n const oscillator = audioContext.createOscillator();\n oscillator.connect(gain);\n oscillator.type = \"sine\";\n oscillator.frequency.value = 1;\n oscillator.start();\n setTimeout(()=>{\n oscillator.stop();\n oscillator.disconnect();\n gain.disconnect();\n });\n };\n _playNote = async (notes, noteIdx, loop)=>{\n if (this._container.muted) {\n return;\n }\n const note = notes[noteIdx];\n if (!note) {\n return;\n }\n const value = note.value, promises = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.executeOnSingleOrMultiple)(value, async (_, idx)=>{\n return this._playNoteValue(notes, noteIdx, idx);\n });\n await ((0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.isArray)(promises) ? Promise.allSettled(promises) : promises);\n const indexOffset = 1;\n let nextNoteIdx = noteIdx + indexOffset;\n if (loop && nextNoteIdx >= notes.length) {\n nextNoteIdx = nextNoteIdx % notes.length;\n }\n await this._playNote(notes, nextNoteIdx, loop);\n };\n _playNoteValue = async (notes, noteIdx, valueIdx)=>{\n const note = notes[noteIdx];\n if (!note) {\n return;\n }\n const value = (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.itemFromSingleOrMultiple)(note.value, valueIdx, true);\n if (!value) {\n return;\n }\n try {\n const freq = (0,_utils_js__WEBPACK_IMPORTED_MODULE_2__.getNoteFrequency)(value);\n if (!(0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.isNumber)(freq)) {\n return;\n }\n await this._playFrequency(freq, note.duration);\n } catch (e) {\n (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.getLogger)().error(e);\n }\n };\n _removeAudioSource = (source)=>{\n source.stop();\n source.disconnect();\n const deleteCount = 1;\n this._audioSources.splice(this._audioSources.indexOf(source), deleteCount);\n };\n _unmute = ()=>{\n const container = this._container, options = container.actualOptions, soundsOptions = options.sounds;\n if (!soundsOptions) {\n return;\n }\n const audioContext = this._getAudioContext(), gain = audioContext.createGain();\n gain.connect(audioContext.destination);\n gain.gain.value = soundsOptions.volume.value / _tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.percentDenominator;\n this._gain = gain;\n this._initEvents();\n this._engine.dispatchEvent(_enums_js__WEBPACK_IMPORTED_MODULE_1__.SoundsEventType.unmute, {\n container: this._container\n });\n };\n _updateMuteIcons = ()=>{\n const container = this._container, soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable || !soundsOptions.icons.enable) {\n return;\n }\n const muteImg = this._muteImg, unmuteImg = this._unmuteImg;\n if (muteImg) {\n muteImg.style.display = container.muted ? \"block\" : \"none\";\n }\n if (unmuteImg) {\n unmuteImg.style.display = container.muted ? \"none\" : \"block\";\n }\n };\n _updateMuteStatus = async ()=>{\n const container = this._container, audioContext = this._getAudioContext();\n if (container.muted) {\n await audioContext.suspend();\n await this._mute();\n } else {\n await audioContext.resume();\n this._unmute();\n this._playMuteSound();\n }\n };\n _updateVolume = async ()=>{\n const container = this._container, soundsOptions = container.actualOptions.sounds;\n if (!soundsOptions?.enable) {\n return;\n }\n (0,_tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.clamp)(this._volume, soundsOptions.volume.min, soundsOptions.volume.max);\n let stateChanged = false;\n if (this._volume <= minVolume && !container.muted) {\n this._volume = 0;\n container.muted = true;\n stateChanged = true;\n } else if (this._volume > minVolume && container.muted) {\n container.muted = false;\n stateChanged = true;\n }\n if (stateChanged) {\n this._updateMuteIcons();\n await this._updateMuteStatus();\n }\n if (this._gain?.gain) {\n this._gain.gain.value = this._volume / _tsparticles_engine__WEBPACK_IMPORTED_MODULE_0__.percentDenominator;\n }\n };\n}\n\n\n//# sourceURL=webpack://@tsparticles/plugin-sounds/./dist/browser/SoundsPluginInstance.js?\n}");
|
|
27
27
|
|
|
28
28
|
/***/ },
|
|
29
29
|
|
|
@@ -33,7 +33,7 @@ eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpa
|
|
|
33
33
|
\*******************************/
|
|
34
34
|
(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
|
|
35
35
|
|
|
36
|
-
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ImageDisplay: () => (/* binding */ ImageDisplay),\n/* harmony export */ SoundsEventType: () => (/* binding */ SoundsEventType)\n/* harmony export */ });\nvar SoundsEventType;\n(function
|
|
36
|
+
eval("{__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ImageDisplay: () => (/* binding */ ImageDisplay),\n/* harmony export */ SoundsEventType: () => (/* binding */ SoundsEventType)\n/* harmony export */ });\nvar SoundsEventType;\n(function(SoundsEventType) {\n SoundsEventType[\"mute\"] = \"soundsMuted\";\n SoundsEventType[\"unmute\"] = \"soundsUnmuted\";\n})(SoundsEventType || (SoundsEventType = {}));\nvar ImageDisplay;\n(function(ImageDisplay) {\n ImageDisplay[\"Block\"] = \"block\";\n ImageDisplay[\"None\"] = \"none\";\n})(ImageDisplay || (ImageDisplay = {}));\n\n\n//# sourceURL=webpack://@tsparticles/plugin-sounds/./dist/browser/enums.js?\n}");
|
|
37
37
|
|
|
38
38
|
/***/ }
|
|
39
39
|
|