JS Audio sequence of notes from Oscillator with Sleep function

310 Views Asked by At

I'm trying to create a simple function playTone(freq, dur) that plays a tone at freq hertz for dur (milli-)seconds.

I'm having trouble getting the function to wait for the previous note to finish before starting a new one. My code is below, using a sleep function from this site. I don't yet understand the synchronous/async thing with JS, and I'd like to keep things as simple as possible. Can anyone help to make my code work please? At present the notes all play together.

<script>
function sleep (time) {
  return new Promise((resolve) => setTimeout(resolve, time));
}

function playTone(freq, dur) {
    var audio = new AudioContext();
    var osc = audio.createOscillator();
    var gainNode = audio.createGain()
    gainNode.gain.value = 0.2
    osc.frequency.value = freq;
    osc.type = "square";
    osc.connect(gainNode);
    gainNode.connect(audio.destination);
    osc.start(0);
    osc.stop(dur);
}

for (var i = 0; i < 20; i++) {
    playTone(440 + 10 * i, 1);
    sleep(1000);
}
</script>
1

There are 1 best solutions below

2
On

It's not the best approach, but you could create a recursive method, like this:

function playTone(freqs, idx, dur) {
    var audio = new AudioContext();
    var osc = audio.createOscillator();
    var gainNode = audio.createGain()
    gainNode.gain.value = 0.2
    osc.frequency.value = freqs[idx];
    osc.type = "square";
    osc.connect(gainNode);
    gainNode.connect(audio.destination);
    osc.start(0);

    setTimeout(function() {
        osc.stop(0); //Now setTimeout controls the stop
        if (freqs[idx + 1]) {
            playTone(freqs, idx + 1, dur);
        }
    }, dur);
}

var frequencies = [];

for (var i = 0; i < 20; i++) {
    frequencies.push(440 + 10 * i);
}

playTone(frequencies, 0, 1000);