设置超时功能,具有钢琴应用程序的动态持续时间

setTimeout function with dynamic duration for Piano Application

本文关键字:应用程序 动态 持续时间 钢琴 超时 功能 设置      更新时间:2023-09-26

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

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

我需要按顺序播放 300 微秒的 2C 音符、400 微秒的 2D 音符、420 秒的 2E 等,即在完成上一个音符后播放下一个音符。

我为所有笔记提供了.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 的顺序不正确。那么,如何以正确的顺序和各自的持续时间演奏这些音符呢?

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

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

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

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

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

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

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);
你用

这段代码做了几个假设 - 我看到的第一个假设是声音文件会立即加载。您可能遇到的问题是循环到目前为止没有跟踪延迟 - 所以基本上你调用 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
      }
});