Add track looping logic
This commit is contained in:
parent
e47dbc5ab5
commit
7c68fee276
|
@ -20,6 +20,7 @@ export interface Sound {
|
|||
readonly currentTime: number
|
||||
readonly duration: number
|
||||
readonly buffered: number
|
||||
looping: boolean
|
||||
|
||||
play(): void | Promise<void>
|
||||
pause(): void | Promise<void>
|
||||
|
@ -27,6 +28,7 @@ export interface Sound {
|
|||
seekTo(seconds: number): void | Promise<void>
|
||||
seekBy(seconds: number): void | Promise<void>
|
||||
|
||||
onSoundLoop: EventHookOn<Sound>
|
||||
onSoundEnd: EventHookOn<Sound>
|
||||
}
|
||||
|
||||
|
@ -41,11 +43,13 @@ export const registerSoundImplementation = <T extends Constructor<Sound>>(implem
|
|||
@registerSoundImplementation
|
||||
export class HTMLSound implements Sound {
|
||||
#audio = new Audio()
|
||||
#soundLoopEventHook = createEventHook<HTMLSound>()
|
||||
#soundEndEventHook = createEventHook<HTMLSound>()
|
||||
|
||||
readonly isLoaded = ref(false)
|
||||
|
||||
audioNode = createAudioSource(this.#audio)
|
||||
onSoundLoop: EventHookOn<HTMLSound>
|
||||
onSoundEnd: EventHookOn<HTMLSound>
|
||||
|
||||
constructor (sources: SoundSource[]) {
|
||||
|
@ -54,11 +58,18 @@ export class HTMLSound implements Sound {
|
|||
this.#audio.preload = 'auto'
|
||||
|
||||
useEventListener(this.#audio, 'ended', () => this.#soundEndEventHook.trigger(this))
|
||||
useEventListener(this.#audio, 'timeupdate', () => {
|
||||
if (this.#audio.currentTime === 0) {
|
||||
this.#soundLoopEventHook.trigger(this)
|
||||
}
|
||||
})
|
||||
|
||||
useEventListener(this.#audio, 'loadeddata', () => {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/readyState
|
||||
this.isLoaded.value = this.#audio.readyState >= 2
|
||||
})
|
||||
|
||||
this.onSoundLoop = this.#soundLoopEventHook.on
|
||||
this.onSoundEnd = this.#soundEndEventHook.on
|
||||
}
|
||||
|
||||
|
@ -108,6 +119,14 @@ export class HTMLSound implements Sound {
|
|||
get currentTime () {
|
||||
return this.#audio.currentTime
|
||||
}
|
||||
|
||||
get looping () {
|
||||
return this.#audio.loop
|
||||
}
|
||||
|
||||
set looping (value: boolean) {
|
||||
this.#audio.loop = value
|
||||
}
|
||||
}
|
||||
|
||||
export const soundImplementation = refDefault(ref<Constructor<Sound>>(), HTMLSound)
|
||||
|
|
|
@ -62,11 +62,25 @@ export const toggleLooping = () => {
|
|||
looping.value %= MODE_MAX
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
const sound = currentSound.value
|
||||
if (!sound) return
|
||||
sound.looping = looping.value === LoopingMode.LoopTrack
|
||||
})
|
||||
|
||||
watch(currentSound, sound => {
|
||||
sound?.onSoundLoop(() => {
|
||||
currentTime.value = 0
|
||||
})
|
||||
})
|
||||
|
||||
// Duration
|
||||
export const duration = ref(0)
|
||||
watchEffect(() => {
|
||||
if (currentSound.value?.isLoaded.value) {
|
||||
duration.value = currentSound.value?.duration ?? 0
|
||||
const sound = currentSound.value
|
||||
if (sound?.isLoaded.value === true) {
|
||||
duration.value = sound.duration ?? 0
|
||||
currentTime.value = sound.currentTime
|
||||
return
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue