@goldenratio/wolf 0.0.2

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/target/wolf.js ADDED
@@ -0,0 +1,1606 @@
1
+ // src/utils.ts
2
+ function isHtml5Audio(node) {
3
+ return "play" in node && typeof node.play === "function";
4
+ }
5
+ function loadBuffer(howl, howler) {
6
+ const url = howl._src.toString();
7
+ const cache = howler.cache;
8
+ if (cache[url]) {
9
+ howl._duration = cache[url].duration;
10
+ loadSound(howl);
11
+ return;
12
+ }
13
+ if (/^data:[^;]+;base64,/.test(url)) {
14
+ const data = atob(url.split(",")[1] ?? "");
15
+ const dataView = new Uint8Array(data.length);
16
+ for (let i = 0; i < data.length; ++i) {
17
+ dataView[i] = data.charCodeAt(i);
18
+ }
19
+ decodeAudioData(dataView.buffer, howl, howler);
20
+ } else {
21
+ const xhr = new XMLHttpRequest();
22
+ xhr.open(howl._xhr.method, url, true);
23
+ xhr.withCredentials = howl._xhr.withCredentials;
24
+ xhr.responseType = "arraybuffer";
25
+ if (howl._xhr.headers) {
26
+ Object.keys(howl._xhr.headers).forEach((key) => {
27
+ xhr.setRequestHeader(key, howl._xhr.headers[key]);
28
+ });
29
+ }
30
+ xhr.onload = () => {
31
+ const code = String(xhr.status)[0];
32
+ if (code !== "0" && code !== "2" && code !== "3") {
33
+ howl._emit("loaderror", void 0, `Failed loading audio file with status: ${xhr.status}.`);
34
+ return;
35
+ }
36
+ decodeAudioData(xhr.response, howl, howler);
37
+ };
38
+ xhr.onerror = () => {
39
+ if (howl._webAudio) {
40
+ howl._html5 = true;
41
+ howl._webAudio = false;
42
+ howl._sounds = [];
43
+ delete cache[url];
44
+ howl.load();
45
+ }
46
+ };
47
+ safeXhrSend(xhr);
48
+ }
49
+ }
50
+ function safeXhrSend(xhr) {
51
+ try {
52
+ xhr.send();
53
+ } catch {
54
+ xhr.onerror?.(new ProgressEvent("error"));
55
+ }
56
+ }
57
+ function decodeAudioData(arrayBuffer, howl, howler) {
58
+ const error = () => howl._emit("loaderror", void 0, "Decoding audio data failed.");
59
+ const success = (buffer) => {
60
+ if (buffer && howl._sounds.length > 0) {
61
+ howler.cache[howl._src.toString()] = buffer;
62
+ loadSound(howl, buffer);
63
+ } else {
64
+ error();
65
+ }
66
+ };
67
+ if (typeof Promise !== "undefined" && howler.ctx?.decodeAudioData.length === 1) {
68
+ howler.ctx.decodeAudioData(arrayBuffer).then(success).catch(error);
69
+ } else {
70
+ howler.ctx?.decodeAudioData(arrayBuffer, success, error);
71
+ }
72
+ }
73
+ function loadSound(self, buffer) {
74
+ if (buffer && !self._duration) self._duration = buffer.duration;
75
+ if (Object.keys(self._sprite).length === 0) {
76
+ self._sprite = { "__default": [0, self._duration * 1e3] };
77
+ }
78
+ if (self._state !== "loaded") {
79
+ self._state = "loaded";
80
+ self._emit("load");
81
+ self._loadQueue();
82
+ }
83
+ }
84
+ function setupAudioContext(howler) {
85
+ if (!howler.usingWebAudio) {
86
+ return;
87
+ }
88
+ try {
89
+ if (typeof AudioContext !== "undefined") {
90
+ howler.ctx = new AudioContext();
91
+ } else if (typeof webkitAudioContext !== "undefined") {
92
+ howler.ctx = new webkitAudioContext();
93
+ } else {
94
+ howler.usingWebAudio = false;
95
+ }
96
+ } catch {
97
+ howler.usingWebAudio = false;
98
+ }
99
+ if (!howler.ctx) {
100
+ howler.usingWebAudio = false;
101
+ }
102
+ const iOS = /iP(hone|od|ad)/.test(howler._navigator?.platform ?? "");
103
+ const appVersion = howler._navigator?.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/);
104
+ const version = appVersion ? parseInt(appVersion[1] ?? "", 10) : void 0;
105
+ if (iOS && version && version < 9) {
106
+ const safari = /safari/.test((howler._navigator?.userAgent ?? "").toLowerCase());
107
+ if (howler._navigator && !safari) {
108
+ howler.usingWebAudio = false;
109
+ }
110
+ }
111
+ if (howler.usingWebAudio && howler.ctx) {
112
+ howler.masterGain = typeof howler.ctx.createGain === "undefined" ? howler.ctx["createGainNode"]() : howler.ctx.createGain();
113
+ howler.masterGain?.gain.setValueAtTime(howler._muted ? 0 : howler._volume, howler.ctx.currentTime);
114
+ howler.masterGain?.connect(howler.ctx.destination);
115
+ }
116
+ howler._setup();
117
+ }
118
+
119
+ // src/howler.ts
120
+ var HowlerGlobal = class {
121
+ // Internal
122
+ _counter;
123
+ _html5AudioPool;
124
+ html5PoolSize;
125
+ _codecs;
126
+ _howls;
127
+ _muted;
128
+ _volume;
129
+ _canPlayEvent;
130
+ _navigator;
131
+ _audioUnlocked;
132
+ _mobileUnloaded;
133
+ _scratchBuffer;
134
+ _suspendTimer;
135
+ _resumeAfterSuspend;
136
+ // Public
137
+ cache = {};
138
+ masterGain;
139
+ noAudio = false;
140
+ usingWebAudio = true;
141
+ autoSuspend = true;
142
+ ctx;
143
+ autoUnlock = true;
144
+ state = "suspended";
145
+ constructor() {
146
+ this._counter = 1e3;
147
+ this._html5AudioPool = [];
148
+ this.html5PoolSize = 10;
149
+ this._codecs = {};
150
+ this._howls = [];
151
+ this._muted = false;
152
+ this._volume = 1;
153
+ this._canPlayEvent = "canplaythrough";
154
+ this._navigator = typeof window !== "undefined" && window.navigator ? window.navigator : void 0;
155
+ this.masterGain = void 0;
156
+ this.noAudio = false;
157
+ this.usingWebAudio = true;
158
+ this.autoSuspend = true;
159
+ this.ctx = void 0;
160
+ this.autoUnlock = true;
161
+ this._setup();
162
+ }
163
+ volume(vol) {
164
+ const self = this;
165
+ const parsed = typeof vol === "undefined" ? void 0 : parseFloat(String(vol));
166
+ if (!self.ctx) {
167
+ setupAudioContext(self);
168
+ }
169
+ if (typeof parsed !== "undefined" && parsed >= 0 && parsed <= 1) {
170
+ self._volume = parsed;
171
+ if (self._muted) return self._volume;
172
+ if (self.usingWebAudio && self.masterGain && self.ctx) {
173
+ self.masterGain.gain.setValueAtTime(parsed, self.ctx.currentTime);
174
+ }
175
+ for (let i = 0; i < self._howls.length; i++) {
176
+ const howl = self._howls[i];
177
+ if (howl && !howl._webAudio) {
178
+ const ids = howl._getSoundIds();
179
+ for (let j = 0; j < ids.length; j++) {
180
+ const soundId = ids[j];
181
+ if (typeof soundId !== "number") {
182
+ continue;
183
+ }
184
+ const sound = howl._soundById(soundId);
185
+ if (sound && sound._node && isHtml5Audio(sound._node)) {
186
+ sound._node.volume = sound._volume * parsed;
187
+ }
188
+ }
189
+ }
190
+ }
191
+ return self;
192
+ }
193
+ return self._volume;
194
+ }
195
+ mute(muted) {
196
+ const self = this;
197
+ if (!self.ctx) {
198
+ setupAudioContext(self);
199
+ }
200
+ self._muted = muted;
201
+ if (self.usingWebAudio && self.masterGain && self.ctx) {
202
+ self.masterGain.gain.setValueAtTime(
203
+ muted ? 0 : self._volume,
204
+ self.ctx.currentTime
205
+ );
206
+ }
207
+ for (let i = 0; i < self._howls.length; i++) {
208
+ const howl = self._howls[i];
209
+ if (howl && !howl._webAudio) {
210
+ const ids = howl._getSoundIds();
211
+ for (let j = 0; j < ids.length; j++) {
212
+ const soundId = ids[j];
213
+ if (typeof soundId !== "number") {
214
+ continue;
215
+ }
216
+ const sound = howl._soundById(soundId);
217
+ if (sound && sound._node && isHtml5Audio(sound._node)) {
218
+ sound._node.muted = muted ? true : sound._muted;
219
+ }
220
+ }
221
+ }
222
+ }
223
+ return self;
224
+ }
225
+ stop() {
226
+ const self = this;
227
+ for (let i = 0; i < self._howls.length; i++) {
228
+ self._howls[i]?.stop();
229
+ }
230
+ return self;
231
+ }
232
+ unload() {
233
+ const self = this;
234
+ for (let i = self._howls.length - 1; i >= 0; i--) {
235
+ self._howls[i]?.unload();
236
+ }
237
+ if (self.usingWebAudio && self.ctx && typeof self.ctx.close !== "undefined") {
238
+ self.ctx.close();
239
+ self.ctx = void 0;
240
+ setupAudioContext(self);
241
+ }
242
+ return self;
243
+ }
244
+ codecs(ext) {
245
+ return this._codecs[ext.replace(/^x-/, "")] ?? false;
246
+ }
247
+ _setup() {
248
+ const self = this;
249
+ self.state = self.ctx ? self.ctx.state || "suspended" : "suspended";
250
+ self._autoSuspend();
251
+ if (!self.usingWebAudio) {
252
+ if (typeof Audio !== "undefined") {
253
+ try {
254
+ const test = new Audio();
255
+ if (typeof test.oncanplaythrough === "undefined") {
256
+ self._canPlayEvent = "canplay";
257
+ }
258
+ } catch {
259
+ self.noAudio = true;
260
+ }
261
+ } else {
262
+ self.noAudio = true;
263
+ }
264
+ }
265
+ try {
266
+ const test = new Audio();
267
+ if (test.muted) self.noAudio = true;
268
+ } catch {
269
+ }
270
+ if (!self.noAudio) {
271
+ self._setupCodecs();
272
+ }
273
+ }
274
+ _setupCodecs() {
275
+ const self = this;
276
+ let audioTest = void 0;
277
+ try {
278
+ audioTest = typeof Audio !== "undefined" ? new Audio() : void 0;
279
+ } catch {
280
+ return;
281
+ }
282
+ if (!audioTest || typeof audioTest.canPlayType !== "function") {
283
+ return;
284
+ }
285
+ const mpegTest = audioTest.canPlayType("audio/mpeg;").replace(/^no$/, "");
286
+ const ua = self._navigator ? self._navigator.userAgent : "";
287
+ const checkOpera = ua.match(/OPR\/(\d+)/g);
288
+ const isOldOpera = !!(checkOpera && parseInt(checkOpera[0]?.split("/")[1] ?? "", 10) < 33);
289
+ const checkSafari = ua.indexOf("Safari") !== -1 && ua.indexOf("Chrome") === -1;
290
+ const safariVersion = ua.match(/Version\/(.*?) /);
291
+ const isOldSafari = !!(checkSafari && safariVersion && parseInt(safariVersion[1] ?? "", 10) < 15);
292
+ self._codecs = {
293
+ "mp3": !!(!isOldOpera && (mpegTest || audioTest.canPlayType("audio/mp3;").replace(/^no$/, ""))),
294
+ "mpeg": !!mpegTest,
295
+ "opus": !!audioTest.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/, ""),
296
+ "ogg": !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ""),
297
+ "oga": !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ""),
298
+ "wav": !!(audioTest.canPlayType('audio/wav; codecs="1"') || audioTest.canPlayType("audio/wav")).replace(/^no$/, ""),
299
+ "aac": !!audioTest.canPlayType("audio/aac;").replace(/^no$/, ""),
300
+ "caf": !!audioTest.canPlayType("audio/x-caf;").replace(/^no$/, ""),
301
+ "m4a": !!(audioTest.canPlayType("audio/x-m4a;") || audioTest.canPlayType("audio/m4a;") || audioTest.canPlayType("audio/aac;")).replace(/^no$/, ""),
302
+ "m4b": !!(audioTest.canPlayType("audio/x-m4b;") || audioTest.canPlayType("audio/m4b;") || audioTest.canPlayType("audio/aac;")).replace(/^no$/, ""),
303
+ "mp4": !!(audioTest.canPlayType("audio/x-mp4;") || audioTest.canPlayType("audio/mp4;") || audioTest.canPlayType("audio/aac;")).replace(/^no$/, ""),
304
+ "weba": !!(!isOldSafari && audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, "")),
305
+ "webm": !!(!isOldSafari && audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, "")),
306
+ "dolby": !!audioTest.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/, ""),
307
+ "flac": !!(audioTest.canPlayType("audio/x-flac;") || audioTest.canPlayType("audio/flac;")).replace(/^no$/, "")
308
+ };
309
+ }
310
+ _unlockAudio() {
311
+ const self = this;
312
+ if (self._audioUnlocked || !self.ctx) {
313
+ return;
314
+ }
315
+ self._audioUnlocked = false;
316
+ self.autoUnlock = false;
317
+ if (!self._mobileUnloaded && self.ctx.sampleRate !== 44100) {
318
+ self._mobileUnloaded = true;
319
+ self.unload();
320
+ }
321
+ self._scratchBuffer = self.ctx.createBuffer(1, 1, 22050);
322
+ const unlock = () => {
323
+ while (self._html5AudioPool.length < self.html5PoolSize) {
324
+ try {
325
+ const audioNode = new Audio();
326
+ audioNode._unlocked = true;
327
+ self._releaseHtml5Audio(audioNode);
328
+ } catch {
329
+ self.noAudio = true;
330
+ break;
331
+ }
332
+ }
333
+ for (let i = 0; i < self._howls.length; i++) {
334
+ const howl = self._howls[i];
335
+ if (howl && !howl._webAudio) {
336
+ const ids = howl._getSoundIds();
337
+ for (let j = 0; j < ids.length; j++) {
338
+ const soundId = ids[j];
339
+ if (typeof soundId !== "number") {
340
+ continue;
341
+ }
342
+ const sound = howl._soundById(soundId);
343
+ if (sound && sound._node && isHtml5Audio(sound._node) && !sound._node._unlocked) {
344
+ sound._node._unlocked = true;
345
+ sound._node.load();
346
+ }
347
+ }
348
+ }
349
+ }
350
+ self._autoResume();
351
+ if (self.ctx) {
352
+ const source = self.ctx.createBufferSource();
353
+ source.buffer = self._scratchBuffer ?? null;
354
+ source.connect(self.ctx.destination);
355
+ if (typeof source.start === "undefined") {
356
+ if ("noteOn" in source && typeof source.noteOn === "function") {
357
+ source.noteOn(0);
358
+ }
359
+ } else {
360
+ source.start(0);
361
+ }
362
+ if (typeof self.ctx.resume === "function") {
363
+ self.ctx.resume();
364
+ }
365
+ source.onended = () => {
366
+ source.disconnect();
367
+ self._audioUnlocked = true;
368
+ document.removeEventListener("touchstart", unlock, true);
369
+ document.removeEventListener("touchend", unlock, true);
370
+ document.removeEventListener("click", unlock, true);
371
+ document.removeEventListener("keydown", unlock, true);
372
+ for (let i = 0; i < self._howls.length; i++) {
373
+ self._howls[i]?._emit("unlock");
374
+ }
375
+ };
376
+ }
377
+ };
378
+ document.addEventListener("touchstart", unlock, true);
379
+ document.addEventListener("touchend", unlock, true);
380
+ document.addEventListener("click", unlock, true);
381
+ document.addEventListener("keydown", unlock, true);
382
+ }
383
+ _obtainHtml5Audio() {
384
+ const self = this;
385
+ if (self._html5AudioPool.length) {
386
+ return self._html5AudioPool.pop();
387
+ }
388
+ const testPlay = new Audio().play();
389
+ testPlay.catch(() => {
390
+ });
391
+ return new Audio();
392
+ }
393
+ _releaseHtml5Audio(audio) {
394
+ const self = this;
395
+ if (audio._unlocked) {
396
+ self._html5AudioPool.push(audio);
397
+ }
398
+ return self;
399
+ }
400
+ _autoSuspend() {
401
+ const self = this;
402
+ if (!self.autoSuspend || !self.ctx || typeof self.ctx.suspend === "undefined" || !self.usingWebAudio) {
403
+ return;
404
+ }
405
+ for (let i = 0; i < self._howls.length; i++) {
406
+ const howl = self._howls[i];
407
+ if (howl && howl._webAudio) {
408
+ for (let j = 0; j < howl._sounds.length; j++) {
409
+ if (!howl._sounds[j]?._paused) {
410
+ return;
411
+ }
412
+ }
413
+ }
414
+ }
415
+ if (self._suspendTimer) {
416
+ clearTimeout(self._suspendTimer);
417
+ }
418
+ self._suspendTimer = setTimeout(() => {
419
+ if (!self.autoSuspend) {
420
+ return;
421
+ }
422
+ self._suspendTimer = void 0;
423
+ self.state = "suspending";
424
+ const handleSuspension = () => {
425
+ self.state = "suspended";
426
+ if (self._resumeAfterSuspend) {
427
+ delete self._resumeAfterSuspend;
428
+ self._autoResume();
429
+ }
430
+ };
431
+ self.ctx?.suspend().then(handleSuspension, handleSuspension);
432
+ }, 3e4);
433
+ }
434
+ _autoResume() {
435
+ const self = this;
436
+ if (!self.ctx || typeof self.ctx.resume === "undefined" || !self.usingWebAudio) {
437
+ return;
438
+ }
439
+ if (self.state === "running" && self.ctx.state !== "interrupted" && self._suspendTimer) {
440
+ clearTimeout(self._suspendTimer);
441
+ self._suspendTimer = void 0;
442
+ } else if (self.state === "suspended" || self.state === "running" && self.ctx.state === "interrupted") {
443
+ self.ctx.resume().then(() => {
444
+ self.state = "running";
445
+ for (let i = 0; i < self._howls.length; i++) {
446
+ self._howls[i]?._emit("resume");
447
+ }
448
+ });
449
+ if (self._suspendTimer) {
450
+ clearTimeout(self._suspendTimer);
451
+ self._suspendTimer = void 0;
452
+ }
453
+ } else if (self.state === "suspending") {
454
+ self._resumeAfterSuspend = true;
455
+ }
456
+ }
457
+ };
458
+ var Howler = new HowlerGlobal();
459
+
460
+ // src/sound.ts
461
+ var Sound = class {
462
+ howler;
463
+ parent;
464
+ _muted;
465
+ _loop;
466
+ _volume;
467
+ _rate;
468
+ _seek = 0;
469
+ _rateSeek = 0;
470
+ _paused = true;
471
+ _ended = true;
472
+ _sprite = "__default";
473
+ _id;
474
+ _node;
475
+ _panner;
476
+ _start = 0;
477
+ _stop = 0;
478
+ _playStart = 0;
479
+ _interval = void 0;
480
+ _fadeTo = void 0;
481
+ _errorFn;
482
+ _loadFn;
483
+ _endFn;
484
+ constructor(parent, howler) {
485
+ this.parent = parent;
486
+ this.howler = howler;
487
+ this._muted = parent._muted;
488
+ this._loop = parent._loop;
489
+ this._volume = parent._volume;
490
+ this._rate = parent._rate;
491
+ this._seek = 0;
492
+ this._paused = true;
493
+ this._ended = true;
494
+ this._sprite = "__default";
495
+ this._id = ++howler._counter;
496
+ parent._sounds.push(this);
497
+ const volume = this.howler._muted || this._muted || parent._muted ? 0 : this._volume;
498
+ if (parent._webAudio) {
499
+ const gain = typeof this.howler.ctx?.createGain === "undefined" ? this.howler.ctx["createGainNode"]() : this.howler.ctx.createGain();
500
+ this._node = gain;
501
+ this._node.gain.setValueAtTime(volume, this.howler.ctx?.currentTime ?? 0);
502
+ this._node.paused = true;
503
+ if (this.howler.masterGain) {
504
+ this._node.connect(this.howler.masterGain);
505
+ }
506
+ } else if (!this.howler.noAudio) {
507
+ this._node = this.howler._obtainHtml5Audio();
508
+ this._errorFn = this.errorListener.bind(this);
509
+ this._node.addEventListener("error", this._errorFn, false);
510
+ this._loadFn = this.loadListener.bind(this);
511
+ this._node.addEventListener(this.howler._canPlayEvent, this._loadFn, false);
512
+ this._endFn = this.endListener.bind(this);
513
+ this._node.addEventListener("ended", this._endFn, false);
514
+ this._node.src = parent._src.toString();
515
+ const preload = parent._preload === true ? "auto" : parent._preload;
516
+ this._node.preload = preload === false ? "" : preload;
517
+ this._node.volume = volume * this.howler.volume();
518
+ this._node.load();
519
+ }
520
+ }
521
+ reset() {
522
+ const self = this;
523
+ const parent = self.parent;
524
+ self._muted = parent._muted;
525
+ self._loop = parent._loop;
526
+ self._volume = parent._volume;
527
+ self._rate = parent._rate;
528
+ self._seek = 0;
529
+ self._rateSeek = 0;
530
+ self._paused = true;
531
+ self._ended = true;
532
+ self._sprite = "__default";
533
+ self._id = ++this.howler._counter;
534
+ return self;
535
+ }
536
+ errorListener() {
537
+ const self = this;
538
+ const html = self._node;
539
+ self.parent._emit("loaderror", self._id, html.error ? html.error.code.toString() : "0");
540
+ html.removeEventListener("error", self._errorFn, false);
541
+ }
542
+ loadListener() {
543
+ const self = this;
544
+ const parent = self.parent;
545
+ const html = self._node;
546
+ parent._duration = Math.ceil(html.duration * 10) / 10;
547
+ if (Object.keys(parent._sprite).length === 0) {
548
+ parent._sprite = { "__default": [0, parent._duration * 1e3] };
549
+ }
550
+ if (parent._state !== "loaded") {
551
+ parent._state = "loaded";
552
+ parent._emit("load");
553
+ parent._loadQueue();
554
+ }
555
+ html.removeEventListener(this.howler._canPlayEvent, self._loadFn, false);
556
+ }
557
+ endListener() {
558
+ const self = this;
559
+ const parent = self.parent;
560
+ const html = self._node;
561
+ if (parent._duration === Infinity) {
562
+ parent._duration = Math.ceil(html.duration * 10) / 10;
563
+ const defaultSprite = parent._sprite["__default"];
564
+ if (defaultSprite && defaultSprite[1] === Infinity) {
565
+ defaultSprite[1] = parent._duration * 1e3;
566
+ }
567
+ parent._ended(self);
568
+ }
569
+ html.removeEventListener("ended", self._endFn, false);
570
+ }
571
+ };
572
+
573
+ // src/howl.ts
574
+ var Howl = class {
575
+ howler;
576
+ // User-defined
577
+ _autoplay;
578
+ _format;
579
+ _html5;
580
+ _muted;
581
+ _loop;
582
+ _pool;
583
+ _preload;
584
+ _rate;
585
+ _sprite;
586
+ _src;
587
+ _volume;
588
+ _xhr;
589
+ // Internals
590
+ _duration = 0;
591
+ _state = "unloaded";
592
+ _sounds = [];
593
+ _endTimers = {};
594
+ _queue = [];
595
+ _playLock = false;
596
+ _webAudio = true;
597
+ _onend;
598
+ _onfade;
599
+ _onload;
600
+ _onloaderror;
601
+ _onplayerror;
602
+ _onpause;
603
+ _onplay;
604
+ _onstop;
605
+ _onmute;
606
+ _onvolume;
607
+ _onrate;
608
+ _onseek;
609
+ _onunlock;
610
+ _onresume;
611
+ constructor(options) {
612
+ this.howler = Howler;
613
+ if (!this.howler.ctx) {
614
+ setupAudioContext(this.howler);
615
+ }
616
+ this._autoplay = options["autoplay"] || false;
617
+ this._format = typeof options["format"] !== "string" ? options["format"] : [options["format"]];
618
+ this._html5 = options["html5"] || false;
619
+ this._muted = options["mute"] || false;
620
+ this._loop = options["loop"] || false;
621
+ this._pool = options["pool"] || 5;
622
+ this._preload = typeof options["preload"] === "boolean" || options["preload"] === "metadata" ? options["preload"] : true;
623
+ this._rate = options["rate"] || 1;
624
+ this._sprite = options["sprite"] || {};
625
+ this._src = typeof options["src"] !== "string" ? options["src"] : [options["src"]];
626
+ this._volume = options["volume"] !== void 0 ? options["volume"] : 1;
627
+ this._xhr = {
628
+ method: options["xhr"]?.method ?? "GET",
629
+ headers: options["xhr"]?.headers ?? void 0,
630
+ withCredentials: options["xhr"]?.withCredentials ?? false
631
+ };
632
+ this._duration = 0;
633
+ this._state = "unloaded";
634
+ this._sounds = [];
635
+ this._endTimers = {};
636
+ this._queue = [];
637
+ this._playLock = false;
638
+ this["_onend"] = options["onend"] ? [{ fn: options["onend"] }] : [];
639
+ this["_onfade"] = options["onfade"] ? [{ fn: options["onfade"] }] : [];
640
+ this["_onload"] = options["onload"] ? [{ fn: options["onload"] }] : [];
641
+ this["_onloaderror"] = options["onloaderror"] ? [{ fn: options["onloaderror"] }] : [];
642
+ this["_onplayerror"] = options["onplayerror"] ? [{ fn: options["onplayerror"] }] : [];
643
+ this["_onpause"] = options["onpause"] ? [{ fn: options["onpause"] }] : [];
644
+ this["_onplay"] = options["onplay"] ? [{ fn: options["onplay"] }] : [];
645
+ this["_onstop"] = options["onstop"] ? [{ fn: options["onstop"] }] : [];
646
+ this["_onmute"] = options["onmute"] ? [{ fn: options["onmute"] }] : [];
647
+ this["_onvolume"] = options["onvolume"] ? [{ fn: options["onvolume"] }] : [];
648
+ this["_onrate"] = options["onrate"] ? [{ fn: options["onrate"] }] : [];
649
+ this["_onseek"] = options["onseek"] ? [{ fn: options["onseek"] }] : [];
650
+ this["_onunlock"] = options["onunlock"] ? [{ fn: options["onunlock"] }] : [];
651
+ this["_onresume"] = options["onresume"] ? [{ fn: options["onresume"] }] : [];
652
+ this._webAudio = this.howler.usingWebAudio && !this._html5;
653
+ if (this.howler.ctx && this.howler.autoUnlock) {
654
+ this.howler._unlockAudio();
655
+ }
656
+ this.howler._howls.push(this);
657
+ if (this._autoplay) {
658
+ this._queue.push({ event: "play", action: () => this.play() });
659
+ }
660
+ if (this._preload && this._preload !== "none") {
661
+ this.load();
662
+ }
663
+ }
664
+ load() {
665
+ const self = this;
666
+ if (this.howler.noAudio) {
667
+ self._emit("loaderror", void 0, "No audio support.");
668
+ return;
669
+ }
670
+ let url = void 0;
671
+ for (let i = 0; i < self._src.length; i++) {
672
+ let ext;
673
+ let str;
674
+ if (self._format && self._format[i]) {
675
+ ext = self._format[i];
676
+ } else {
677
+ str = self._src[i] ?? "";
678
+ if (typeof str !== "string" || str === "") {
679
+ self._emit("loaderror", void 0, "Non-string found in selected audio sources - ignoring.");
680
+ continue;
681
+ }
682
+ const dataExt = /^data:audio\/([^;,]+);/i.exec(str);
683
+ if (dataExt) ext = dataExt[1]?.toLowerCase();
684
+ else {
685
+ const m = /\.([^.]+)$/.exec(str.split("?", 1)[0] ?? "");
686
+ if (m) {
687
+ ext = m[1]?.toLowerCase();
688
+ }
689
+ }
690
+ }
691
+ if (!ext) {
692
+ }
693
+ if (ext && this.howler.codecs(ext)) {
694
+ url = self._src[i];
695
+ break;
696
+ }
697
+ }
698
+ if (!url) {
699
+ self._emit("loaderror", void 0, "No codec support for selected audio sources.");
700
+ return;
701
+ }
702
+ self._src = [url];
703
+ self._state = "loading";
704
+ if (typeof window !== "undefined" && window.location.protocol === "https:" && url.slice(0, 5) === "http:") {
705
+ self._html5 = true;
706
+ self._webAudio = false;
707
+ }
708
+ new Sound(self, this.howler);
709
+ if (self._webAudio) {
710
+ loadBuffer(self, this.howler);
711
+ }
712
+ }
713
+ play(spriteOrId, internal) {
714
+ const self = this;
715
+ let id = void 0;
716
+ if (typeof spriteOrId === "number") {
717
+ id = spriteOrId;
718
+ spriteOrId = void 0;
719
+ } else if (typeof spriteOrId === "string" && self._state === "loaded" && !self._sprite[spriteOrId]) {
720
+ return void 0;
721
+ } else if (typeof spriteOrId === "undefined") {
722
+ spriteOrId = "__default";
723
+ if (!self._playLock) {
724
+ let num = 0;
725
+ for (let i = 0; i < self._sounds.length; i++) {
726
+ if (self._sounds[i]?._paused && !self._sounds[i]?._ended) {
727
+ num++;
728
+ id = self._sounds[i]?._id;
729
+ }
730
+ }
731
+ if (num === 1) {
732
+ spriteOrId = void 0;
733
+ } else {
734
+ id = void 0;
735
+ }
736
+ }
737
+ }
738
+ const sound = id ? self._soundById(id) : self._inactiveSound();
739
+ if (!sound) {
740
+ return void 0;
741
+ }
742
+ if (id && !spriteOrId) {
743
+ spriteOrId = sound._sprite || "__default";
744
+ }
745
+ if (self._state !== "loaded") {
746
+ sound._sprite = spriteOrId?.toString() ?? "__default";
747
+ sound._ended = false;
748
+ const soundId = sound._id;
749
+ self._queue.push({ event: "play", action: () => self.play(soundId) });
750
+ return soundId;
751
+ }
752
+ if (id && !sound._paused) {
753
+ if (!internal) self._loadQueue("play");
754
+ return sound._id;
755
+ }
756
+ if (self._webAudio) {
757
+ this.howler._autoResume();
758
+ }
759
+ const spriteName = spriteOrId ?? "__default";
760
+ const seek = Math.max(0, sound._seek > 0 ? sound._seek : (self._sprite[spriteName]?.[0] ?? 0) / 1e3);
761
+ const spriteDef = self._sprite[spriteName];
762
+ const duration = spriteDef ? Math.max(
763
+ 0,
764
+ (spriteDef[0] + spriteDef[1]) / 1e3 - seek
765
+ ) : 0;
766
+ const timeout = duration * 1e3 / Math.abs(sound._rate);
767
+ const start = spriteDef ? spriteDef[0] / 1e3 : 0;
768
+ const stop = spriteDef ? (spriteDef[0] + spriteDef[1]) / 1e3 : 0;
769
+ sound._sprite = spriteName;
770
+ sound._ended = false;
771
+ const setParams = () => {
772
+ sound._paused = false;
773
+ sound._seek = seek;
774
+ sound._start = start;
775
+ sound._stop = stop;
776
+ sound._loop = !!(sound._loop || (self._sprite[spriteName]?.[2] ?? false));
777
+ };
778
+ if (seek >= stop) {
779
+ self._ended(sound);
780
+ return sound._id;
781
+ }
782
+ const node = sound._node;
783
+ if (self._webAudio) {
784
+ const playWebAudio = () => {
785
+ self._playLock = false;
786
+ setParams();
787
+ self._refreshBuffer(sound);
788
+ const vol = sound._muted || self._muted ? 0 : sound._volume;
789
+ node.gain.setValueAtTime(vol, this.howler.ctx?.currentTime ?? 0);
790
+ sound._playStart = this.howler.ctx?.currentTime ?? 0;
791
+ const bs = node.bufferSource;
792
+ if (typeof bs.start === "undefined") {
793
+ if ("noteGrainOn" in bs && typeof bs.noteGrainOn === "function")
794
+ sound._loop ? bs.noteGrainOn(0, seek, 86400) : bs.noteGrainOn(0, seek, duration);
795
+ } else {
796
+ sound._loop ? bs.start(0, seek, 86400) : bs.start(0, seek, duration);
797
+ }
798
+ if (timeout !== Infinity) {
799
+ self._endTimers[sound._id] = setTimeout(() => self._ended(sound), timeout);
800
+ }
801
+ if (!internal) {
802
+ setTimeout(() => {
803
+ self._emit("play", sound._id);
804
+ self._loadQueue();
805
+ }, 0);
806
+ }
807
+ };
808
+ if (this.howler.state === "running" && this.howler.ctx?.state !== "interrupted") {
809
+ playWebAudio();
810
+ } else {
811
+ self._playLock = true;
812
+ self.once("resume", () => {
813
+ playWebAudio();
814
+ });
815
+ self._clearTimer(sound._id);
816
+ }
817
+ } else {
818
+ const html = node;
819
+ const playHtml5 = () => {
820
+ html.currentTime = seek;
821
+ html.muted = sound._muted || self._muted || this.howler._muted || html.muted;
822
+ html.volume = sound._volume * this.howler.volume();
823
+ html.playbackRate = sound._rate;
824
+ try {
825
+ const p = html.play();
826
+ if (p && typeof Promise !== "undefined" && (p instanceof Promise || typeof p["then"] === "function")) {
827
+ self._playLock = true;
828
+ setParams();
829
+ p.then(() => {
830
+ self._playLock = false;
831
+ html._unlocked = true;
832
+ if (!internal) self._emit("play", sound._id);
833
+ else self._loadQueue();
834
+ }).catch(() => {
835
+ self._playLock = false;
836
+ self._emit(
837
+ "playerror",
838
+ sound._id,
839
+ "Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction."
840
+ );
841
+ sound._ended = true;
842
+ sound._paused = true;
843
+ });
844
+ } else if (!internal) {
845
+ self._playLock = false;
846
+ setParams();
847
+ self._emit("play", sound._id);
848
+ }
849
+ html.playbackRate = sound._rate;
850
+ if (html.paused) {
851
+ self._emit(
852
+ "playerror",
853
+ sound._id,
854
+ "Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction."
855
+ );
856
+ return;
857
+ }
858
+ if (spriteName !== "__default" || sound._loop) {
859
+ self._endTimers[sound._id] = setTimeout(() => self._ended(sound), timeout);
860
+ } else {
861
+ self._endTimers[sound._id] = () => {
862
+ self._ended(sound);
863
+ html.removeEventListener("ended", self._endTimers[sound._id], false);
864
+ };
865
+ html.addEventListener("ended", self._endTimers[sound._id], false);
866
+ }
867
+ } catch (err) {
868
+ self._emit("playerror", sound._id, err);
869
+ }
870
+ };
871
+ if (html.src === "data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA") {
872
+ html.src = self._src.toString();
873
+ html.load();
874
+ }
875
+ if (html.readyState >= 3) {
876
+ playHtml5();
877
+ } else {
878
+ self._playLock = true;
879
+ self._state = "loading";
880
+ const listener = () => {
881
+ self._state = "loaded";
882
+ playHtml5();
883
+ html.removeEventListener(this.howler._canPlayEvent, listener, false);
884
+ };
885
+ html.addEventListener(this.howler._canPlayEvent, listener, false);
886
+ self._clearTimer(sound._id);
887
+ }
888
+ }
889
+ return sound._id;
890
+ }
891
+ state() {
892
+ return this._state;
893
+ }
894
+ /**
895
+ * Check if a sound (or any sound) is playing.
896
+ */
897
+ playing(id) {
898
+ const self = this;
899
+ if (typeof id === "number") {
900
+ const sound = self._soundById(id);
901
+ return sound ? !sound._paused : false;
902
+ }
903
+ for (let i = 0; i < self._sounds.length; i++) {
904
+ if (!self._sounds[i]?._paused) {
905
+ return true;
906
+ }
907
+ }
908
+ return false;
909
+ }
910
+ /**
911
+ * Duration of group, or sprite duration if sound id passed.
912
+ */
913
+ duration(id) {
914
+ const self = this;
915
+ let duration = self._duration;
916
+ const sound = typeof id === "number" ? self._soundById(id) : void 0;
917
+ if (sound) {
918
+ duration = (self._sprite[sound._sprite]?.[1] ?? 0) / 1e3;
919
+ }
920
+ return duration;
921
+ }
922
+ /**
923
+ * Pause playback and save current position.
924
+ */
925
+ pause(id, internal) {
926
+ const self = this;
927
+ if (self._state !== "loaded" || self._playLock) {
928
+ self._queue.push({ event: "pause", action: () => self.pause(id) });
929
+ return self;
930
+ }
931
+ const ids = self._getSoundIds(id);
932
+ for (let i = 0; i < ids.length; i++) {
933
+ self._clearTimer(ids[i] ?? 0);
934
+ const sound = self._soundById(ids[i] ?? 0);
935
+ if (sound && !sound._paused) {
936
+ sound._seek = self.seek(ids[i] ?? 0);
937
+ sound._rateSeek = 0;
938
+ sound._paused = true;
939
+ self._stopFade(ids[i] ?? 0);
940
+ if (sound._node) {
941
+ if (self._webAudio && !isHtml5Audio(sound._node)) {
942
+ const n = sound._node;
943
+ if (!n.bufferSource) continue;
944
+ if (typeof n.bufferSource.stop === "undefined") n.bufferSource.noteOff(0);
945
+ else n.bufferSource.stop(0);
946
+ self._cleanBuffer(n);
947
+ } else if (isHtml5Audio(sound._node) && (!isNaN(sound._node.duration) || sound._node.duration === Infinity)) {
948
+ sound._node.pause();
949
+ }
950
+ }
951
+ }
952
+ if (!internal) {
953
+ self._emit("pause", sound ? sound._id : void 0);
954
+ }
955
+ }
956
+ return self;
957
+ }
958
+ rate(rateOrId, idMaybe) {
959
+ const self = this;
960
+ const argsLen = arguments.length;
961
+ let rate;
962
+ let id;
963
+ if (argsLen === 0) {
964
+ id = self._sounds[0]?._id;
965
+ } else if (argsLen === 1) {
966
+ const ids = self._getSoundIds();
967
+ const index = ids.indexOf(rateOrId);
968
+ if (index >= 0) id = parseInt(String(rateOrId), 10);
969
+ else rate = parseFloat(String(rateOrId));
970
+ } else if (argsLen === 2) {
971
+ rate = parseFloat(String(rateOrId));
972
+ id = parseInt(String(idMaybe), 10);
973
+ }
974
+ if (typeof rate === "number") {
975
+ if (self._state !== "loaded" || self._playLock) {
976
+ const capturedArgs = [...arguments];
977
+ self._queue.push({
978
+ event: "rate",
979
+ action: () => self.rate.apply(self, capturedArgs)
980
+ });
981
+ return self;
982
+ }
983
+ if (typeof id === "undefined") self._rate = rate;
984
+ const ids = self._getSoundIds(id);
985
+ for (let i = 0; i < ids.length; i++) {
986
+ const sound2 = self._soundById(ids[i] ?? 0);
987
+ if (!sound2) continue;
988
+ if (self.playing(ids[i])) {
989
+ sound2._rateSeek = self.seek(ids[i] ?? 0);
990
+ sound2._playStart = self._webAudio ? Howler.ctx.currentTime : sound2._playStart;
991
+ }
992
+ sound2._rate = rate;
993
+ if (self._webAudio && sound2._node && !isHtml5Audio(sound2._node)) {
994
+ const n = sound2._node;
995
+ if (n.bufferSource) n.bufferSource.playbackRate.setValueAtTime(rate, Howler.ctx.currentTime);
996
+ } else if (sound2._node && isHtml5Audio(sound2._node)) {
997
+ sound2._node.playbackRate = rate;
998
+ }
999
+ const seek = self.seek(ids[i] ?? 0);
1000
+ const sprite = self._sprite[sound2._sprite];
1001
+ const duration = sprite ? (sprite[0] + sprite[1]) / 1e3 - seek : 0;
1002
+ const timeout = duration * 1e3 / Math.abs(sound2._rate);
1003
+ const sId = ids[i];
1004
+ if (typeof sId === "number" && self._endTimers[sId] || !sound2._paused) {
1005
+ if (typeof sId === "number") {
1006
+ self._clearTimer(sId);
1007
+ self._endTimers[sId] = setTimeout(() => self._ended(sound2), timeout);
1008
+ }
1009
+ }
1010
+ self._emit("rate", sound2._id);
1011
+ }
1012
+ return self;
1013
+ }
1014
+ const sound = id ? self._soundById(id) : void 0;
1015
+ return sound ? sound._rate : self._rate;
1016
+ }
1017
+ seek(seekOrId, idMaybe) {
1018
+ const self = this;
1019
+ const argsLen = arguments.length;
1020
+ let seek = void 0;
1021
+ let id = void 0;
1022
+ if (argsLen === 0) {
1023
+ if (self._sounds.length) {
1024
+ id = self._sounds[0]?._id;
1025
+ }
1026
+ } else if (argsLen === 1) {
1027
+ const ids = self._getSoundIds();
1028
+ const index = ids.indexOf(seekOrId);
1029
+ if (index >= 0) {
1030
+ id = parseInt(String(seekOrId), 10);
1031
+ } else if (self._sounds.length) {
1032
+ id = self._sounds[0]?._id;
1033
+ seek = parseFloat(String(seekOrId));
1034
+ }
1035
+ } else if (argsLen === 2) {
1036
+ seek = parseFloat(String(seekOrId));
1037
+ id = parseInt(String(idMaybe), 10);
1038
+ }
1039
+ if (typeof id === "undefined") return 0;
1040
+ if (typeof seek === "number" && (self._state !== "loaded" || self._playLock)) {
1041
+ const capturedArgs = [...arguments];
1042
+ self._queue.push({
1043
+ event: "seek",
1044
+ action: () => self.seek.apply(self, capturedArgs)
1045
+ });
1046
+ return self;
1047
+ }
1048
+ const sound = self._soundById(id);
1049
+ if (!sound) {
1050
+ return self;
1051
+ }
1052
+ if (typeof seek === "number" && seek >= 0) {
1053
+ const wasPlaying = self.playing(id);
1054
+ if (wasPlaying) {
1055
+ self.pause(id, true);
1056
+ }
1057
+ sound._seek = seek;
1058
+ sound._ended = false;
1059
+ self._clearTimer(id);
1060
+ if (!self._webAudio && sound._node && isHtml5Audio(sound._node) && !isNaN(sound._node.duration)) {
1061
+ sound._node.currentTime = seek;
1062
+ }
1063
+ const seekAndEmit = () => {
1064
+ if (wasPlaying) {
1065
+ self.play(id, true);
1066
+ }
1067
+ self._emit("seek", id);
1068
+ };
1069
+ if (wasPlaying && !self._webAudio) {
1070
+ const emitSeek = () => {
1071
+ if (!self._playLock) seekAndEmit();
1072
+ else setTimeout(emitSeek, 0);
1073
+ };
1074
+ setTimeout(emitSeek, 0);
1075
+ } else {
1076
+ seekAndEmit();
1077
+ }
1078
+ return self;
1079
+ }
1080
+ if (self._webAudio) {
1081
+ const realTime = self.playing(id) ? Howler.ctx.currentTime - sound._playStart : 0;
1082
+ const rateSeek = sound._rateSeek ? sound._rateSeek - sound._seek : 0;
1083
+ return sound._seek + (rateSeek + realTime * Math.abs(sound._rate));
1084
+ }
1085
+ if (sound._node && isHtml5Audio(sound._node)) {
1086
+ return sound._node.currentTime;
1087
+ }
1088
+ return 0;
1089
+ }
1090
+ stop(id, internal) {
1091
+ if (typeof id === "undefined") {
1092
+ const ids = this._getSoundIds();
1093
+ for (const sid of ids) {
1094
+ this.stop(sid, internal);
1095
+ }
1096
+ return this;
1097
+ }
1098
+ const sound = this._soundById(id);
1099
+ if (sound) {
1100
+ this._clearTimer(id);
1101
+ sound._seek = sound._start || 0;
1102
+ sound._rateSeek = 0;
1103
+ sound._paused = true;
1104
+ sound._ended = true;
1105
+ if (sound._node) {
1106
+ if (this._webAudio) {
1107
+ const n = sound._node;
1108
+ if (n.bufferSource) {
1109
+ if (typeof n.bufferSource.stop === "undefined") {
1110
+ if ("noteOff" in n.bufferSource && typeof n.bufferSource.noteOff === "function") {
1111
+ n.bufferSource.noteOff(0);
1112
+ }
1113
+ } else {
1114
+ n.bufferSource.stop(0);
1115
+ }
1116
+ this._cleanBuffer(n);
1117
+ }
1118
+ } else if (isHtml5Audio(sound._node)) {
1119
+ const a = sound._node;
1120
+ a.currentTime = sound._start || 0;
1121
+ a.pause();
1122
+ if (a.duration === Infinity) {
1123
+ this._clearSound(a);
1124
+ }
1125
+ }
1126
+ }
1127
+ if (!internal) this._emit("stop", sound._id);
1128
+ }
1129
+ return this;
1130
+ }
1131
+ /**
1132
+ * Mute/unmute a single sound or all sounds in this Howl group.
1133
+ * @param muted Set to true to mute and false to unmute.
1134
+ * @param id The sound ID to update (omit to mute/unmute all).
1135
+ */
1136
+ mute(muted, id) {
1137
+ const self = this;
1138
+ if (typeof id === "undefined" && typeof muted !== "boolean") {
1139
+ return self._muted;
1140
+ }
1141
+ if (self._state !== "loaded" || self._playLock) {
1142
+ self._queue.push({
1143
+ event: "mute",
1144
+ action: () => {
1145
+ self.mute(muted, id);
1146
+ }
1147
+ });
1148
+ return self;
1149
+ }
1150
+ if (typeof id === "undefined" && typeof muted === "boolean") {
1151
+ self._muted = muted;
1152
+ }
1153
+ const ids = self._getSoundIds(id);
1154
+ for (let i = 0; i < ids.length; i++) {
1155
+ const sound = self._soundById(ids[i] ?? 0);
1156
+ if (!sound) continue;
1157
+ sound._muted = muted;
1158
+ if (sound._interval) self._stopFade(sound._id);
1159
+ if (self._webAudio && sound._node && !isHtml5Audio(sound._node)) {
1160
+ sound._node.gain.setValueAtTime(
1161
+ muted ? 0 : sound._volume,
1162
+ Howler.ctx.currentTime
1163
+ );
1164
+ } else if (sound._node && isHtml5Audio(sound._node)) {
1165
+ sound._node.muted = Howler._muted ? true : muted;
1166
+ }
1167
+ self._emit("mute", sound._id);
1168
+ }
1169
+ return self;
1170
+ }
1171
+ volume(volOrId, idMaybe, internal) {
1172
+ const self = this;
1173
+ const argsLen = arguments.length;
1174
+ let vol;
1175
+ let id;
1176
+ if (argsLen === 0) {
1177
+ return self._volume;
1178
+ }
1179
+ if (argsLen === 1 || argsLen === 2 && typeof idMaybe === "undefined") {
1180
+ const ids = self._getSoundIds();
1181
+ const index = ids.indexOf(volOrId);
1182
+ if (index >= 0) {
1183
+ id = parseInt(String(volOrId), 10);
1184
+ } else {
1185
+ vol = parseFloat(String(volOrId));
1186
+ }
1187
+ } else if (argsLen >= 2) {
1188
+ vol = parseFloat(String(volOrId));
1189
+ id = parseInt(String(idMaybe), 10);
1190
+ }
1191
+ if (typeof vol !== "undefined" && vol >= 0 && vol <= 1) {
1192
+ if (self._state !== "loaded" || self._playLock) {
1193
+ const capturedArgs = [...arguments];
1194
+ self._queue.push({
1195
+ event: "volume",
1196
+ action: () => self.volume.apply(self, capturedArgs)
1197
+ });
1198
+ return self;
1199
+ }
1200
+ if (typeof id === "undefined") {
1201
+ self._volume = vol;
1202
+ }
1203
+ const ids = self._getSoundIds(id);
1204
+ for (let i = 0; i < ids.length; i++) {
1205
+ const sound2 = self._soundById(ids[i] ?? 0);
1206
+ if (!sound2) continue;
1207
+ sound2._volume = vol;
1208
+ if (!internal) self._stopFade(ids[i] ?? 0);
1209
+ if (self._webAudio && sound2._node && !sound2._muted && !isHtml5Audio(sound2._node)) {
1210
+ sound2._node.gain.setValueAtTime(vol, Howler.ctx.currentTime);
1211
+ } else if (sound2._node && !sound2._muted && isHtml5Audio(sound2._node)) {
1212
+ sound2._node.volume = vol * Howler.volume();
1213
+ }
1214
+ self._emit("volume", sound2._id);
1215
+ }
1216
+ return self;
1217
+ }
1218
+ const sound = id ? self._soundById(id) : self._sounds[0];
1219
+ return sound ? sound._volume : 0;
1220
+ }
1221
+ /**
1222
+ * Fade a currently playing sound between two volumes (if no id is passed, all sounds will fade).
1223
+ */
1224
+ fade(from, to, len, id) {
1225
+ const self = this;
1226
+ if (self._state !== "loaded" || self._playLock) {
1227
+ self._queue.push({
1228
+ event: "fade",
1229
+ action: () => self.fade(from, to, len, id)
1230
+ });
1231
+ return self;
1232
+ }
1233
+ from = Math.min(Math.max(0, parseFloat(String(from))), 1);
1234
+ to = Math.min(Math.max(0, parseFloat(String(to))), 1);
1235
+ len = parseFloat(String(len));
1236
+ self.volume(from, id);
1237
+ const ids = self._getSoundIds(id);
1238
+ for (let i = 0; i < ids.length; i++) {
1239
+ const sound = self._soundById(ids[i] ?? 0);
1240
+ if (!sound) continue;
1241
+ if (!id) self._stopFade(ids[i] ?? 0);
1242
+ if (self._webAudio && !sound._muted && sound._node && !isHtml5Audio(sound._node)) {
1243
+ const currentTime = Howler.ctx.currentTime;
1244
+ const end = currentTime + len / 1e3;
1245
+ sound._volume = from;
1246
+ sound._node.gain.setValueAtTime(from, currentTime);
1247
+ sound._node.gain.linearRampToValueAtTime(to, end);
1248
+ }
1249
+ self._startFadeInterval(sound, from, to, len, ids[i] ?? 0, typeof id === "undefined");
1250
+ }
1251
+ return self;
1252
+ }
1253
+ loop(loopOrId, idMaybe) {
1254
+ const self = this;
1255
+ const argsLen = arguments.length;
1256
+ let loopVal = false;
1257
+ let id;
1258
+ if (argsLen === 0) return self._loop;
1259
+ if (argsLen === 1) {
1260
+ if (typeof loopOrId === "boolean") {
1261
+ loopVal = loopOrId;
1262
+ self._loop = loopVal;
1263
+ } else {
1264
+ const sound = self._soundById(parseInt(String(loopOrId), 10));
1265
+ return sound ? sound._loop : false;
1266
+ }
1267
+ } else if (argsLen === 2) {
1268
+ loopVal = loopOrId;
1269
+ id = parseInt(String(idMaybe), 10);
1270
+ }
1271
+ const ids = self._getSoundIds(id);
1272
+ for (let i = 0; i < ids.length; i++) {
1273
+ const sound = self._soundById(ids[i] ?? 0);
1274
+ if (!sound) continue;
1275
+ sound._loop = loopVal;
1276
+ if (self._webAudio && sound._node && !isHtml5Audio(sound._node)) {
1277
+ const n = sound._node;
1278
+ if (n.bufferSource) {
1279
+ n.bufferSource.loop = loopVal;
1280
+ if (loopVal) {
1281
+ n.bufferSource.loopStart = sound._start || 0;
1282
+ n.bufferSource.loopEnd = sound._stop;
1283
+ if (self.playing(ids[i])) {
1284
+ self.pause(ids[i], true);
1285
+ self.play(ids[i], true);
1286
+ }
1287
+ }
1288
+ }
1289
+ }
1290
+ }
1291
+ return self;
1292
+ }
1293
+ unload() {
1294
+ const self = this;
1295
+ const sounds = self._sounds;
1296
+ for (let i = 0; i < sounds.length; i++) {
1297
+ if (!sounds[i]?._paused) {
1298
+ self.stop(sounds[i]?._id);
1299
+ }
1300
+ const currentNode = sounds[i]?._node;
1301
+ if (!self._webAudio && currentNode && isHtml5Audio(currentNode)) {
1302
+ self._clearSound(currentNode);
1303
+ if ("_errorFn" in currentNode) {
1304
+ currentNode.removeEventListener("error", currentNode._errorFn, false);
1305
+ }
1306
+ if ("_loadFn" in currentNode) {
1307
+ currentNode.removeEventListener(this.howler._canPlayEvent, currentNode._loadFn, false);
1308
+ }
1309
+ if ("_endFn" in currentNode) {
1310
+ currentNode.removeEventListener("ended", currentNode._endFn, false);
1311
+ }
1312
+ this.howler._releaseHtml5Audio(currentNode);
1313
+ }
1314
+ delete sounds[i]?._node;
1315
+ self._clearTimer(sounds[i]?._id ?? 0);
1316
+ }
1317
+ const index = this.howler._howls.indexOf(self);
1318
+ if (index >= 0) this.howler._howls.splice(index, 1);
1319
+ let remCache = true;
1320
+ for (let i = 0; i < this.howler._howls.length; i++) {
1321
+ const hs = this.howler._howls[i]?._src.toString();
1322
+ if (hs === self._src.toString() || hs && self._src.indexOf(hs) >= 0) {
1323
+ remCache = false;
1324
+ break;
1325
+ }
1326
+ }
1327
+ if (this.howler.cache && remCache) {
1328
+ delete this.howler.cache[self._src.toString()];
1329
+ }
1330
+ this.howler.noAudio = false;
1331
+ self._state = "unloaded";
1332
+ self._sounds = [];
1333
+ }
1334
+ on(event, fn, id, once) {
1335
+ const eventName = "_on" + event;
1336
+ const events = this[eventName];
1337
+ if (typeof fn === "function") {
1338
+ events.push(once ? { id, fn, once } : { id, fn });
1339
+ }
1340
+ return this;
1341
+ }
1342
+ off(event, fn, id) {
1343
+ const self = this;
1344
+ if (typeof fn === "number") {
1345
+ id = fn;
1346
+ fn = void 0;
1347
+ }
1348
+ if (event) {
1349
+ const eventName = "_on" + event;
1350
+ const events = self[eventName];
1351
+ if (fn || id) {
1352
+ for (let i = 0; i < events.length; i++) {
1353
+ const isId = id === events[i]?.id;
1354
+ if (fn === events[i]?.fn && isId || !fn && isId) {
1355
+ events.splice(i, 1);
1356
+ break;
1357
+ }
1358
+ }
1359
+ } else {
1360
+ self[eventName] = [];
1361
+ }
1362
+ } else {
1363
+ const keys = Object.keys(self);
1364
+ for (let i = 0; i < keys.length; i++) {
1365
+ if (keys[i].indexOf("_on") === 0 && Array.isArray(self[keys[i]])) {
1366
+ self[keys[i]] = [];
1367
+ }
1368
+ }
1369
+ }
1370
+ return self;
1371
+ }
1372
+ once(event, fn, id) {
1373
+ return this.on(event, fn, id, true);
1374
+ }
1375
+ /**
1376
+ * Starts the internal interval to fade a sound.
1377
+ */
1378
+ _startFadeInterval(sound, from, to, len, _id, isGroup) {
1379
+ const self = this;
1380
+ let vol = from;
1381
+ const diff = to - from;
1382
+ const steps = Math.abs(diff / 0.01);
1383
+ const stepLen = Math.max(4, steps > 0 ? len / steps : len);
1384
+ let lastTick = Date.now();
1385
+ sound._fadeTo = to;
1386
+ sound._interval = setInterval(() => {
1387
+ const tick = (Date.now() - lastTick) / len;
1388
+ lastTick = Date.now();
1389
+ vol += diff * tick;
1390
+ vol = Math.round(vol * 100) / 100;
1391
+ if (diff < 0) vol = Math.max(to, vol);
1392
+ else vol = Math.min(to, vol);
1393
+ if (self._webAudio) {
1394
+ sound._volume = vol;
1395
+ } else {
1396
+ self.volume(vol, sound._id, true);
1397
+ }
1398
+ if (isGroup) self._volume = vol;
1399
+ if (to < from && vol <= to || to > from && vol >= to) {
1400
+ clearInterval(sound._interval);
1401
+ sound._interval = void 0;
1402
+ sound._fadeTo = void 0;
1403
+ self.volume(to, sound._id);
1404
+ self._emit("fade", sound._id);
1405
+ }
1406
+ }, stepLen);
1407
+ }
1408
+ /**
1409
+ * Stop an active fade.
1410
+ */
1411
+ _stopFade(id) {
1412
+ const self = this;
1413
+ const sound = self._soundById(id);
1414
+ if (sound && sound._interval) {
1415
+ if (self._webAudio && sound._node && !isHtml5Audio(sound._node)) {
1416
+ sound._node.gain.cancelScheduledValues(Howler.ctx?.currentTime ?? 0);
1417
+ }
1418
+ clearInterval(sound._interval);
1419
+ sound._interval = void 0;
1420
+ if (typeof sound._fadeTo === "number") {
1421
+ self.volume(sound._fadeTo, id);
1422
+ }
1423
+ sound._fadeTo = void 0;
1424
+ self._emit("fade", id);
1425
+ }
1426
+ return self;
1427
+ }
1428
+ _emit(event, id, errorMsg) {
1429
+ const self = this;
1430
+ const eventType = "_on" + event;
1431
+ const events = self[eventType];
1432
+ for (let i = events.length - 1; i >= 0; i--) {
1433
+ const currentEvent = events[i];
1434
+ if (currentEvent && (!currentEvent.id || currentEvent.id === id || event === "load")) {
1435
+ setTimeout(() => {
1436
+ currentEvent?.fn.call(self, id, errorMsg);
1437
+ }, 0);
1438
+ if (currentEvent.once) {
1439
+ self.off(event, currentEvent.fn, currentEvent.id);
1440
+ }
1441
+ }
1442
+ }
1443
+ self._loadQueue(event);
1444
+ return self;
1445
+ }
1446
+ _loadQueue(event) {
1447
+ const self = this;
1448
+ if (self._queue.length > 0) {
1449
+ const task = self._queue[0];
1450
+ if (task) {
1451
+ if (event && task.event === event) {
1452
+ self._queue.shift();
1453
+ self._loadQueue();
1454
+ }
1455
+ if (!event) {
1456
+ task.action();
1457
+ }
1458
+ }
1459
+ }
1460
+ return self;
1461
+ }
1462
+ _ended(sound) {
1463
+ const self = this;
1464
+ const sprite = sound._sprite;
1465
+ if (!self._webAudio && sound._node && isHtml5Audio(sound._node) && !sound._node.paused && !sound._node.ended && sound._node.currentTime < sound._stop) {
1466
+ setTimeout(() => self._ended(sound), 100);
1467
+ return self;
1468
+ }
1469
+ const loop = !!(sound._loop || self._sprite[sprite]?.[2]);
1470
+ self._emit("end", sound._id);
1471
+ if (!self._webAudio && loop) {
1472
+ self.stop(sound._id, true).play(sound._id);
1473
+ }
1474
+ if (self._webAudio && loop) {
1475
+ self._emit("play", sound._id);
1476
+ sound._seek = sound._start || 0;
1477
+ sound._rateSeek = 0;
1478
+ sound._playStart = this.howler.ctx?.currentTime ?? 0;
1479
+ const timeout = (sound._stop - sound._start) * 1e3 / Math.abs(sound._rate);
1480
+ self._endTimers[sound._id] = setTimeout(() => self._ended(sound), timeout);
1481
+ }
1482
+ if (self._webAudio && !loop) {
1483
+ sound._paused = true;
1484
+ sound._ended = true;
1485
+ sound._seek = sound._start || 0;
1486
+ sound._rateSeek = 0;
1487
+ self._clearTimer(sound._id);
1488
+ self._cleanBuffer(sound._node);
1489
+ this.howler._autoSuspend();
1490
+ }
1491
+ if (!self._webAudio && !loop) {
1492
+ self.stop(sound._id, true);
1493
+ }
1494
+ return self;
1495
+ }
1496
+ _clearTimer(id) {
1497
+ const self = this;
1498
+ if (self._endTimers[id]) {
1499
+ if (typeof self._endTimers[id] !== "function") {
1500
+ clearTimeout(self._endTimers[id]);
1501
+ } else {
1502
+ const sound = self._soundById(id);
1503
+ if (sound && sound._node && isHtml5Audio(sound._node)) {
1504
+ sound._node.removeEventListener("ended", self._endTimers[id], false);
1505
+ }
1506
+ }
1507
+ delete self._endTimers[id];
1508
+ }
1509
+ return self;
1510
+ }
1511
+ _soundById(id) {
1512
+ for (let i = 0; i < this._sounds.length; i++) {
1513
+ if (id === this._sounds[i]?._id) {
1514
+ return this._sounds[i];
1515
+ }
1516
+ }
1517
+ return void 0;
1518
+ }
1519
+ _inactiveSound() {
1520
+ this._drain();
1521
+ for (let i = 0; i < this._sounds.length; i++) {
1522
+ if (this._sounds[i]?._ended) {
1523
+ const sound = this._sounds[i]?.reset();
1524
+ if (sound) {
1525
+ return sound;
1526
+ }
1527
+ }
1528
+ }
1529
+ return new Sound(this, this.howler);
1530
+ }
1531
+ _drain() {
1532
+ const limit = this._pool;
1533
+ if (this._sounds.length < limit) return;
1534
+ let cnt = 0;
1535
+ for (let i = 0; i < this._sounds.length; i++) {
1536
+ if (this._sounds[i]?._ended) {
1537
+ cnt++;
1538
+ }
1539
+ }
1540
+ for (let i = this._sounds.length - 1; i >= 0; i--) {
1541
+ if (cnt <= limit) {
1542
+ return;
1543
+ }
1544
+ if (this._sounds[i]?._ended) {
1545
+ const currentNode = this._sounds[i]?._node;
1546
+ if (this._webAudio && currentNode && !isHtml5Audio(currentNode)) {
1547
+ currentNode["disconnect"]?.(0);
1548
+ }
1549
+ this._sounds.splice(i, 1);
1550
+ cnt--;
1551
+ }
1552
+ }
1553
+ }
1554
+ _getSoundIds(id) {
1555
+ if (typeof id === "undefined") return this._sounds.map((s) => s._id);
1556
+ return [id];
1557
+ }
1558
+ _refreshBuffer(sound) {
1559
+ sound._node = sound._node;
1560
+ sound._node.bufferSource = this.howler.ctx?.createBufferSource();
1561
+ if (!sound._node?.bufferSource) {
1562
+ return;
1563
+ }
1564
+ const bufferSource = sound._node.bufferSource;
1565
+ bufferSource.buffer = this.howler.cache[this._src.toString()] ?? null;
1566
+ if (sound._panner) {
1567
+ bufferSource.connect(sound._panner);
1568
+ } else {
1569
+ bufferSource.connect(sound._node);
1570
+ }
1571
+ bufferSource.loop = sound._loop;
1572
+ if (sound._loop) {
1573
+ bufferSource.loopStart = sound._start || 0;
1574
+ bufferSource.loopEnd = sound._stop || 0;
1575
+ }
1576
+ bufferSource.playbackRate.setValueAtTime(sound._rate, this.howler.ctx?.currentTime ?? 0);
1577
+ }
1578
+ _cleanBuffer(node) {
1579
+ const isIOS = !!(this.howler._navigator && this.howler._navigator.vendor.indexOf("Apple") >= 0);
1580
+ if (!node.bufferSource) {
1581
+ return;
1582
+ }
1583
+ if (this.howler._scratchBuffer && node.bufferSource) {
1584
+ node.bufferSource.onended = null;
1585
+ node.bufferSource.disconnect(0);
1586
+ if (isIOS) {
1587
+ try {
1588
+ node.bufferSource.buffer = this.howler._scratchBuffer;
1589
+ } catch {
1590
+ }
1591
+ }
1592
+ }
1593
+ node.bufferSource = void 0;
1594
+ }
1595
+ _clearSound(node) {
1596
+ const checkIE = this.howler._navigator && /MSIE |Trident\//.test(this.howler._navigator && this.howler._navigator.userAgent);
1597
+ if (!checkIE) {
1598
+ node.src = "data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA";
1599
+ }
1600
+ }
1601
+ };
1602
+ export {
1603
+ Howl,
1604
+ Howler
1605
+ };
1606
+ //# sourceMappingURL=wolf.js.map