diff --git a/dev_modules/tethr b/dev_modules/tethr index 5e9f2b4..1bf9dc7 160000 --- a/dev_modules/tethr +++ b/dev_modules/tethr @@ -1 +1 @@ -Subproject commit 5e9f2b438f1a5988b11d4eda776c42878754ec38 +Subproject commit 1bf9dc728afd3942c55dea5ca837c28af6b952af diff --git a/src/playSound.ts b/src/playSound.ts index 8317c42..f93094e 100644 --- a/src/playSound.ts +++ b/src/playSound.ts @@ -7,3 +7,20 @@ export function playSound(src: string) { }) sound.play() } + +export function seekAndPlay(sound: Howl, seconds: number): Promise { + return new Promise(resolve => { + sound.once('play', () => resolve()) + sound.stop() + sound.seek(seconds) + sound.play() + }) +} + +export function scrub(sound: Howl, seconds: number, durationMs: number) { + sound.once('play', () => { + setTimeout(() => sound.stop(), durationMs) + }) + sound.seek(seconds) + sound.play() +} diff --git a/src/stores/viewport.ts b/src/stores/viewport.ts index 1706cdc..ff978f2 100644 --- a/src/stores/viewport.ts +++ b/src/stores/viewport.ts @@ -3,6 +3,7 @@ import {clamp} from 'lodash' import {defineStore} from 'pinia' import {computed, ref, shallowRef, watch} from 'vue' +import {scrub, seekAndPlay} from '@/playSound' import {refWithSetter} from '@/use/refWithSetter' import {getObjectURL} from '@/util' @@ -51,7 +52,7 @@ export const useViewportStore = defineStore('viewport', () => { }) // Play - watch(isPlaying, () => { + watch(isPlaying, async () => { if (!isPlaying.value) { if (!project.isLooping && temporalFrame.value) { currentFrame.value = temporalFrame.value @@ -68,28 +69,36 @@ export const useViewportStore = defineStore('viewport', () => { if (howl.value) { const startSec = (inPoint + 150) / fps - howl.value.seek(startSec) - howl.value.play() + await seekAndPlay(howl.value, startSec) } - const startTime = new Date().getTime() + let startTime = new Date().getTime() const duration = outPoint - inPoint + 1 - function update() { + async function update() { if (!isPlaying.value) { temporalFrame.value = null return } - const elapsed = new Date().getTime() - startTime + const now = new Date().getTime() + const elapsed = now - startTime - const elapsedFrames = Math.round((elapsed / 1000) * fps) + let elapsedFrames = Math.round((elapsed / 1000) * fps) if (!project.isLooping && elapsedFrames >= duration) { currentFrame.value = outPoint isPlaying.value = false } else { + if (elapsedFrames >= duration) { + if (howl.value) { + await seekAndPlay(howl.value, (inPoint + 150) / fps) + } + startTime = now + elapsedFrames = 0 + } + temporalFrame.value = (elapsedFrames % duration) + inPoint requestAnimationFrame(update) } @@ -98,6 +107,13 @@ export const useViewportStore = defineStore('viewport', () => { update() }) + // Audio scrub + watch(currentFrame, currentFrame => { + if (!howl.value) return + + scrub(howl.value, (currentFrame + 150) / project.fps, 160) + }) + // Onionskin information const onionskin = computed(() => { if (isPlaying.value || liveToggle.value || project.onionskin === 0) {