Skip to content

Commit

Permalink
Support audio scrubbing
Browse files Browse the repository at this point in the history
  • Loading branch information
baku89 committed Oct 11, 2023
1 parent b1aa852 commit 8a7e2c3
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 8 deletions.
2 changes: 1 addition & 1 deletion dev_modules/tethr
Submodule tethr updated 1 files
+0 −1 src/Tethr.ts
17 changes: 17 additions & 0 deletions src/playSound.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,20 @@ export function playSound(src: string) {
})
sound.play()
}

export function seekAndPlay(sound: Howl, seconds: number): Promise<void> {
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()
}
30 changes: 23 additions & 7 deletions src/stores/viewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down Expand Up @@ -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
Expand All @@ -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)
}
Expand All @@ -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) {
Expand Down

0 comments on commit 8a7e2c3

Please sign in to comment.