Last active
August 21, 2019 18:36
-
-
Save Ntropish/ba2c3a9752a80b634ab15922d6f29a59 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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