2

我正在开发一个钢琴应用程序。我有一个带有音符名称及其播放时间的 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

4 回答 4

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

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

于 2013-10-16T14:05:21.870 回答
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);
于 2013-10-16T13:58:28.343 回答
0

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

我会写我认为你正在寻找的方式是这样的:

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
      }
});
于 2013-10-16T14:20:34.410 回答
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);
于 2013-10-16T14:04:45.130 回答