Skip to content

Instantly share code, notes, and snippets.

@Ntropish
Last active August 21, 2019 18:36
Show Gist options
  • Save Ntropish/ba2c3a9752a80b634ab15922d6f29a59 to your computer and use it in GitHub Desktop.
Save Ntropish/ba2c3a9752a80b634ab15922d6f29a59 to your computer and use it in GitHub Desktop.
/*
handlers: {
start(time) {},
stop(time) {},
schedule(from, to, currentTime) {}
}
context: AudioContext
*/
const createScheduler = handlers => context => {
let lastSchedule = context.currentTime
// Context time during the last "play", used to calculate how
// long scheduler has been playing
let playStartContextTime = 0
let playFrom = 0
let playing = false
// At least this much time needs to be scheduled
// before any scheduling will be done
const schedulingThreashold = 0.1
// How far into the future to schedule
const extraSchedulingTime = 1
const resolveNextFrame = () => new Promise(r => requestAnimationFrame(r))
const beginScheduling = async () => {
const attemptScheduling = () => {
const timeToSchedule =
context.currentTime + extraSchedulingTime - lastSchedule
if (timeToSchedule > schedulingThreashold) {
const from = playFrom + lastSchedule - playStartContextTime
const to = from + timeToSchedule
lastSchedule = context.currentTime + extraSchedulingTime
if (handlers.schedule) handlers.schedule(from, to, currentTime())
}
}
playing = true
while (playing) {
await resolveNextFrame()
attemptScheduling()
}
}
const stopScheduling = () => {
playing = false
}
const currentTime = () => {
return playFrom + context.currentTime - playStartContextTime
}
const checkpoint = time => {
lastSchedule = context.currentTime
playFrom = time
playStartContextTime = context.currentTime
}
const play = (time = currentTime()) => {
checkpoint(time)
if (handlers.stop) handlers.stop(time)
if (handlers.start) handlers.start(time)
beginScheduling()
if (context.state === 'suspended') {
context.resume()
}
}
const pause = (time = currentTime()) => {
checkpoint(time)
if (handlers.stop) handlers.stop(currentTime())
stopScheduling()
if (context.state === 'running') context.suspend()
}
const stop = () => {
pause(0)
}
return {
play,
pause,
stop,
currentTime,
}
}
export default createScheduler
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment