/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { hookstate, State, useHookstate } from '@hookstate/core' import { AudioEngine, AudioEngineListenerInterface, PlaySoundOptions, SOUND_TYPE, StopSoundOptions, } from '../audio/audio-engine' export type AudioHookStateType = { volume: Record<SOUND_TYPE, number> currentlyPlayingSounds: string[] } const AudioEngineInstance = new AudioEngine() const globalAudioHookState = hookstate<AudioHookStateType>({ volume: { [SOUND_TYPE.MUSIC]: AudioEngineInstance.getVolume(SOUND_TYPE.MUSIC), [SOUND_TYPE.SFX]: AudioEngineInstance.getVolume(SOUND_TYPE.SFX), [SOUND_TYPE.AMBIENT]: AudioEngineInstance.getVolume(SOUND_TYPE.AMBIENT), }, currentlyPlayingSounds: [], }) const AudioEngineHookstateListener: AudioEngineListenerInterface = { setVolume: (type: SOUND_TYPE, volume: number) => { if (globalAudioHookState.volume[type].get() === volume) { return } globalAudioHookState.volume[type].set(volume) }, playSound: (_sound) => { const sounds = AudioEngineInstance.getPlayingSounds().map((s) => { return s.name }) globalAudioHookState.currentlyPlayingSounds.set(sounds) }, stopSound: (_sound) => { const sounds = AudioEngineInstance.getPlayingSounds().map((s) => { return s.name }) globalAudioHookState.currentlyPlayingSounds.set(sounds) }, } AudioEngineInstance.addListener(AudioEngineHookstateListener) const getAudioHookStateController = (state: State<AudioHookStateType>) => { return { _state: state, addSound: (urls: string[], name: string, type: SOUND_TYPE) => { AudioEngineInstance.addSound(urls, name, type); }, exists: (name: string) => { return AudioEngineInstance.exists(name) }, getVolume: (type: SOUND_TYPE) => { return state.volume[type].get() }, setVolume: (type: SOUND_TYPE, volume: number) => { return AudioEngineInstance.setVolume(type, volume) }, /** * Helper to play sound. * Since this interacts with the AudioEngine, you can just call that directly. * @param sound * @param opts */ play: (sound: string, opts: PlaySoundOptions = {}) => { if (AudioEngineInstance.getType(sound) === SOUND_TYPE.MUSIC) { AudioEngineInstance.changeMusic(sound, opts, { fadeOut: true, fadeTime: 500, }) } else { AudioEngineInstance.playSound(sound, opts) } }, stop: (sound: string, opts: StopSoundOptions = {}) => { AudioEngineInstance.stopSound(sound, opts) }, stopAll: (opts: StopSoundOptions = {}) => { AudioEngineInstance.stopAllSounds(opts) }, stopMusic: (opts: StopSoundOptions = {}) => { AudioEngineInstance.stopAllSoundsOfType(SOUND_TYPE.MUSIC, opts) }, getCurrentlyPlayingSoundIds: () => { return state.currentlyPlayingSounds.get() }, getCurrentlyPlayingSounds: () => { return [...AudioEngineInstance.getPlayingSounds()] }, getCurrentlyPlayingSoundsOfType: (type: SOUND_TYPE) => { return [...AudioEngineInstance.getPlayingSoundsOfType(type)] }, isPlaying: (name: string) => { const _status = state.currentlyPlayingSounds.get().indexOf(name) > -1 return _status }, } } export const AudioHookStateController = getAudioHookStateController(globalAudioHookState) export const useAudioHookState = () => { const state = useHookstate(globalAudioHookState) return getAudioHookStateController(state) }