I'm trying to make a synthesizer/sequencer with the WebAudio API. Mostly trying to make something that can playback a song made up of notes and events like MIDI to control the multiple channels of the synth. But I still need to tackle the timing aspect.
I've read tutorials on the WebAudio API, but I don't quite understand how timing/scheduling/clock works. At first I made a polyphonic synthesizer that played notes for keypresses, and this did not need any consideration for timing. I then made the oscillator playback an an array of notes at specific time intervals using setInterval
. However I have noticed in the past when switching tabs in Google Chrome, the playback rate is significantly slowed down, I assume to be less resource intensive - but other synth libraries didn't have this issue. Also I can only assume that using setInterval
isn't great for smooth (is buffered the right word?) playback, especially when considering ADSR envelopes oscillators.
From what I am reading, the WebAudio API has an ever-increasing currentTime
timer variable. But if notes are stored in an array and I want to cycle it at a set rate, how would the WebAudio timer be manipulated to iterate an array over a set rate? My setInterval solution (volume warning) doesn't take into account the WebAudio timer at all, and just calls voice()
with setInterval
to play a note, overwriting the last voice played.
Are there better or efficient ways to playback/loop a sequence of notes other than setInterval
?
Just an update to clarify: When I wrote this question, I was using setInterval
to play a sequence of notes at fixed intervals (e.g. unscheduled--constantly starting/stopping oscillators) and was wondering about more reliable ways to play notes. I found that a better solution would be to use setValueAtTime
on osc.frequency
as well as a GainNode
. For a simple prototype synth, this works well, but a more advanced synth could use the timer on osc.start
and osc.stop
. The problem is looping the song. In order to loop, I need to constantly schedule more notes so that by the end of the song, it starts over. I can use setInterval
to schedule the entire song loop, but it still has to keep time with the song playing, and setInterval
(and even Web Workers' onmessage
calls) could be slowed down when the tab is inactive for example. setInterval's clock isn't even reliable, so I simply check every 5ms if (currentTime >= songTime)
and schedule if condition is met. That method may not be too efficient. What I have so far.