2

作为一个个人项目,我正在尝试使用 p5.js、Web Midi Api 和 Web Audio Font 重现钢琴卷(就像 DAW 中的那些)。在实现播放功能时,我首先使用了一个while循环,但我意识到我无法停止播放曲目,因为javascript是单线程的。所以我尝试用这段代码递归地播放音符:

function playTrackRecursively(id) {
  var delay = 0;
  isTrackPlaying = true;
  playNote(mainTrack[id][0], 0);
  if (id < mainTrack.length - 1 && isTrackPlaying){
    delay = mainTrack[id + 1][1] - mainTrack[id][1];
    recursiveID = setTimeout(function() {
      playTrackRecursively(id + 1);
    }, delay * 1000);
  }
  isTrackPlaying = false;
}

它工作正常,除了当我尝试同时播放多个音符时,它们一个接一个地播放,延迟大约 100 毫秒。

我能做什么 ?谢谢你。

4

1 回答 1

3

我在评论中在@user120242 的帮助下找到了解决方案。

所以这只是我所拥有的两种解决方案的混合。我递归地遍历曲目中的每个时间戳,每次我得到一个数组中从这里开始的所有音符,然后我一个一个地演奏它们(它的速度足以产生同时性的错觉)。所以尽管我读到了,这确实是可能的。

这是代码:

function playTrackRecursively(id) {
  var delay = 0;
  isTrackPlaying = true;
  var notesBatch = getNotesOfSameStartTime(mainTrack[id][1]);
  playNotesInBatch(notesBatch);
  if (id + notesBatch.length < mainTrack.length && isTrackPlaying){
    delay = mainTrack[id + notesBatch.length][1] - mainTrack[id][1];
    recursiveID = setTimeout(function() {
      playTrackRecursively(id + notesBatch.length);
    }, delay * 1000);
  }
}

function playNotesInBatch(notes) {
  for (var i = 0; i < notes.length; i++) {
    playNote(notes[i][0], notes[i][1]);
  }
}

function getNotesOfSameStartTime(startTime) {
  var indexArray = []
  for (var i = 0; i < mainTrack.length; i++) {
    if (mainTrack[i][1] == startTime) {
      indexArray.push(i);
    }
  }
  var batch = mainTrack.slice(indexArray[0], indexArray[indexArray.length - 1] + 1);
  return batch;
}
于 2020-05-31T23:28:32.133 回答