| 
									
										
										
										
											2020-05-19 09:08:28 +00:00
										 |  |  | import { MusicInstanceInterface, SoundInstanceInterface, SoundInterface, MUSIC, SOUNDS } from "../sound"; | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  | import { cachebust } from "../../core/cachebust"; | 
					
						
							|  |  |  | import { createLogger } from "../../core/logging"; | 
					
						
							| 
									
										
										
										
											2020-05-19 09:08:28 +00:00
										 |  |  | import { globalConfig } from "../../core/config"; | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | const { Howl, Howler } = require("howler"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const logger = createLogger("sound/browser"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-19 09:11:08 +00:00
										 |  |  | // @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2020-05-19 09:08:28 +00:00
										 |  |  | const sprites = require("../../built-temp/sfx.json"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SoundSpritesContainer { | 
					
						
							|  |  |  |     constructor() { | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |         this.howl = null; | 
					
						
							| 
									
										
										
										
											2020-05-19 09:08:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.loadingPromise = null; | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     load() { | 
					
						
							| 
									
										
										
										
											2020-05-19 09:08:28 +00:00
										 |  |  |         if (this.loadingPromise) { | 
					
						
							|  |  |  |             return this.loadingPromise; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return (this.loadingPromise = Promise.race([ | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |             new Promise((resolve, reject) => { | 
					
						
							|  |  |  |                 setTimeout(reject, G_IS_DEV ? 5000 : 60000); | 
					
						
							|  |  |  |             }), | 
					
						
							|  |  |  |             new Promise(resolve => { | 
					
						
							|  |  |  |                 this.howl = new Howl({ | 
					
						
							| 
									
										
										
										
											2020-05-19 09:08:28 +00:00
										 |  |  |                     src: cachebust("res/sounds/sfx.mp3"), | 
					
						
							|  |  |  |                     sprite: sprites.sprite, | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |                     autoplay: false, | 
					
						
							|  |  |  |                     loop: false, | 
					
						
							|  |  |  |                     volume: 0, | 
					
						
							|  |  |  |                     preload: true, | 
					
						
							| 
									
										
										
										
											2020-05-14 17:12:58 +00:00
										 |  |  |                     pool: 20, | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |                     onload: () => { | 
					
						
							|  |  |  |                         resolve(); | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                     onloaderror: (id, err) => { | 
					
						
							| 
									
										
										
										
											2020-05-19 09:08:28 +00:00
										 |  |  |                         logger.warn("SFX failed to load:", id, err); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |                         this.howl = null; | 
					
						
							|  |  |  |                         resolve(); | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                     onplayerror: (id, err) => { | 
					
						
							| 
									
										
										
										
											2020-05-19 09:08:28 +00:00
										 |  |  |                         logger.warn("SFX failed to play:", id, err); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |                     }, | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |             }), | 
					
						
							| 
									
										
										
										
											2020-05-19 09:08:28 +00:00
										 |  |  |         ])); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-19 09:08:28 +00:00
										 |  |  |     play(volume, key) { | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |         if (this.howl) { | 
					
						
							| 
									
										
										
										
											2020-05-19 09:08:28 +00:00
										 |  |  |             const instance = this.howl.play(key); | 
					
						
							| 
									
										
										
										
											2020-05-14 17:12:58 +00:00
										 |  |  |             this.howl.volume(volume, instance); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     deinitialize() { | 
					
						
							|  |  |  |         if (this.howl) { | 
					
						
							|  |  |  |             this.howl.unload(); | 
					
						
							|  |  |  |             this.howl = null; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-19 09:08:28 +00:00
										 |  |  | class WrappedSoundInstance extends SoundInstanceInterface { | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param {SoundSpritesContainer} spriteContainer | 
					
						
							|  |  |  |      * @param {string} key | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     constructor(spriteContainer, key) { | 
					
						
							|  |  |  |         super(key, "sfx.mp3"); | 
					
						
							|  |  |  |         this.spriteContainer = spriteContainer; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** @returns {Promise<void>} */ | 
					
						
							|  |  |  |     load() { | 
					
						
							|  |  |  |         return this.spriteContainer.load(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     play(volume) { | 
					
						
							|  |  |  |         this.spriteContainer.play(volume, this.key); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     deinitialize() { | 
					
						
							|  |  |  |         return this.spriteContainer.deinitialize(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  | class MusicInstance extends MusicInstanceInterface { | 
					
						
							|  |  |  |     constructor(key, url) { | 
					
						
							|  |  |  |         super(key, url); | 
					
						
							|  |  |  |         this.howl = null; | 
					
						
							|  |  |  |         this.instance = null; | 
					
						
							|  |  |  |         this.playing = false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     load() { | 
					
						
							|  |  |  |         return Promise.race([ | 
					
						
							|  |  |  |             new Promise((resolve, reject) => { | 
					
						
							|  |  |  |                 setTimeout(reject, G_IS_DEV ? 5000 : 60000); | 
					
						
							|  |  |  |             }), | 
					
						
							|  |  |  |             new Promise((resolve, reject) => { | 
					
						
							|  |  |  |                 this.howl = new Howl({ | 
					
						
							|  |  |  |                     src: cachebust("res/sounds/music/" + this.url), | 
					
						
							|  |  |  |                     autoplay: false, | 
					
						
							|  |  |  |                     loop: true, | 
					
						
							|  |  |  |                     html5: true, | 
					
						
							| 
									
										
										
										
											2020-05-16 07:49:00 +00:00
										 |  |  |                     volume: 1, | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |                     preload: true, | 
					
						
							|  |  |  |                     pool: 2, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-16 07:49:00 +00:00
										 |  |  |                     onunlock: () => { | 
					
						
							|  |  |  |                         if (this.playing) { | 
					
						
							|  |  |  |                             logger.log("Playing music after manual unlock"); | 
					
						
							|  |  |  |                             this.play(); | 
					
						
							|  |  |  |                         } | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |                     onload: () => { | 
					
						
							|  |  |  |                         resolve(); | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                     onloaderror: (id, err) => { | 
					
						
							|  |  |  |                         logger.warn(this, "Music", this.url, "failed to load:", id, err); | 
					
						
							|  |  |  |                         this.howl = null; | 
					
						
							|  |  |  |                         resolve(); | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                     onplayerror: (id, err) => { | 
					
						
							|  |  |  |                         logger.warn(this, "Music", this.url, "failed to play:", id, err); | 
					
						
							|  |  |  |                     }, | 
					
						
							|  |  |  |                 }); | 
					
						
							|  |  |  |             }), | 
					
						
							|  |  |  |         ]); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     stop() { | 
					
						
							|  |  |  |         if (this.howl && this.instance) { | 
					
						
							|  |  |  |             this.playing = false; | 
					
						
							|  |  |  |             this.howl.pause(this.instance); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     isPlaying() { | 
					
						
							|  |  |  |         return this.playing; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     play() { | 
					
						
							|  |  |  |         if (this.howl) { | 
					
						
							|  |  |  |             this.playing = true; | 
					
						
							|  |  |  |             if (this.instance) { | 
					
						
							|  |  |  |                 this.howl.play(this.instance); | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 this.instance = this.howl.play(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     deinitialize() { | 
					
						
							|  |  |  |         if (this.howl) { | 
					
						
							|  |  |  |             this.howl.unload(); | 
					
						
							|  |  |  |             this.howl = null; | 
					
						
							|  |  |  |             this.instance = null; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class SoundImplBrowser extends SoundInterface { | 
					
						
							|  |  |  |     constructor(app) { | 
					
						
							| 
									
										
										
										
											2020-05-14 17:12:58 +00:00
										 |  |  |         Howler.mobileAutoEnable = true; | 
					
						
							|  |  |  |         Howler.autoUnlock = true; | 
					
						
							|  |  |  |         Howler.autoSuspend = false; | 
					
						
							|  |  |  |         Howler.html5PoolSize = 20; | 
					
						
							|  |  |  |         Howler.pos(0, 0, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-19 09:08:28 +00:00
										 |  |  |         super(app, WrappedSoundInstance, MusicInstance); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     initialize() { | 
					
						
							| 
									
										
										
										
											2020-05-19 09:08:28 +00:00
										 |  |  |         this.sfxHandle = new SoundSpritesContainer(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // @ts-ignore
 | 
					
						
							|  |  |  |         const keys = Object.values(SOUNDS); | 
					
						
							|  |  |  |         keys.forEach(key => { | 
					
						
							|  |  |  |             this.sounds[key] = new WrappedSoundInstance(this.sfxHandle, key); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |         for (const musicKey in MUSIC) { | 
					
						
							|  |  |  |             const musicPath = MUSIC[musicKey]; | 
					
						
							|  |  |  |             const music = new this.musicClass(musicKey, musicPath); | 
					
						
							|  |  |  |             this.music[musicPath] = music; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.musicMuted = this.app.settings.getAllSettings().musicMuted; | 
					
						
							|  |  |  |         this.soundsMuted = this.app.settings.getAllSettings().soundsMuted; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (G_IS_DEV && globalConfig.debug.disableMusic) { | 
					
						
							|  |  |  |             this.musicMuted = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return Promise.resolve(); | 
					
						
							| 
									
										
										
										
											2020-05-09 14:45:23 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     deinitialize() { | 
					
						
							|  |  |  |         return super.deinitialize().then(() => Howler.unload()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |