具有动态持续时间的setTimeout函数用于钢琴应用程序

时间:2013-10-16 13:52:23

标签: javascript jquery settimeout html5-audio piano

我正在开发钢琴应用程序。我有一个带有音符名称和播放时间的json数组。

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

我需要播放2C音符300微秒,2D音符播放400微秒,2E播放420,依此类推,即在完成前一个音符后播放下一个音符。

我有.ogg格式的所有音符的音频文件,所有音符都有相同的持续时间1018.776微秒。

为了播放上面json数据的注释,我尝试了javascript的setTimeout函数:

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

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

但这不起作用。主要问题是持续时间。当我使用console.log(value.value)时,结果是2C,2D,2E,2G,2F。这里2F和2G的顺序不正确。 那么,如何以正确的顺序播放这些音符及其各自的持续时间?

4 个答案:

答案 0 :(得分:4)

您需要使用递归函数而不是循环:

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);
        }
    }
}

这样,在当前音符完成之前,不会触发下一个音符开始播放。

答案 1 :(得分:0)

更喜欢在超时后调用其他值。

function callAudio (index) {
    var
    value = this[i],
    audioElement = document.createElement('audio');

    if (!value) return;

    audioElement.setAttribute('src', './audio/'+value.value+'.ogg');
    audioElement.play();
    setTimeout(callAudio.bind(this, index++), value.duration);
};

callAudio.call(data, 0);

答案 2 :(得分:0)

您可以使用接收数组和索引的函数,然后在延迟后使用下一个索引调用自身。

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

function playNote(data, index) {
    var audioElement = document.createElement('audio');
    audioElement.setAttribute('src', './audio/'+data[index].value+'.ogg');
    audioElement.play();

    if (index + 1 < data.length) {
        setTimeout(function() {
            playNote(data, index + 1);
        }, data[index].duration);
    }
}

playNote(data, 0);

答案 3 :(得分:0)

您正在使用此代码进行一些假设 - 我看到的第一个假设是声音文件立即加载。你可能遇到的问题是循环没有跟踪到目前为止的延迟 - 所以基本上你正在调用setTimeout({play},400)并且紧接在setTimeout({play},500之后)所以他们最终500ms后重叠直到800 ms。

我写出我认为你正在寻找的东西是这样的:

var audio = $.map(data, function(key,val) {return $("<audio>",{src:val.value})});
audio.each(function(indx, $ele) {
      if(indx !=0){
          audio[indx-1].on("ended", function(){$ele.get().play()});//play next sound when previous one finishes playing
      }
});