javascriptjquerysettimeouthtml5-audiopiano

setTimeout function with dynamic duration for Piano Application


I am developing a Piano application. I have a json array with note names and their duration of playing time.

var data= [{"duration":300,"value":"2C"},{"duration":400,"value":"2D"},{"duration":420,"value":"2E"},{"duration":600,"value":"2F"},{"duration":400,"value":"2G"}];

I need to play 2C note for 300 microseconds, 2D note for 400 microseconds, 2E for 420 and so on in a sequence, that is playing next note after completion of previous note.

I have audio files in .ogg format for all notes and all notes have same duration of 1018.776 microseconds.

To play the notes of above json data, I have tried setTimeout function of javascript:

$.each( data, function( key, value ) {
    setTimeout(function(){
        var audioElement = document.createElement('audio');
        audioElement.setAttribute('src', './audio/'+value.value+'.ogg');
        audioElement.play();

    }, value.duration*key); 
});

But this is not working. The main problem is on duration. When I use console.log(value.value), the result was 2C, 2D, 2E, 2G, 2F. Here the sequence of 2F and 2G is not in correct order. So, How to play these notes in correct sequence with their respective duration?


Solution

  • You need to use a recursive function instead of loop:

    function playNotes(notes) {
        var i = 0;
        playNextNote();
        function playNextNote() {
            if (i < notes.length) {
                var value = notes[i];
                var audioElement = document.createElement('audio');
                audioElement.setAttribute('src', './audio/'+value.value+'.ogg');
                audioElement.play();
                i++;
                setTimeout(playNextNote, value.duration);
            }
        }
    }
    

    In this way, the next note isn't triggered to start playing until the current note has completed.