在播放过程中安排ToneJS事件

问题描述

我的Tone JS应用程序中有4个音符正在播放,并且在传输过程中,我想将第3个音符更改为其他音符。这是我的代码

JS:

import { Transport,start,Sampler } from "tone";

const notesToPlay = [
  {
    timing: 0.25,sameAsLast: false,duration: 0.1,veLocity: 1
  },{
    timing: 0.5,sameAsLast: true,{
    timing: 0.75,{
    timing: 1,duration: 0.2,veLocity: 1
  }
];

var eventIds = [];

(function () {
  function playSynth() {
    Transport.start();
    start();
  }

  const sampler = new Sampler({
    urls: {
      A1: "A1.mp3",A2: "A2.mp3"
    },baseUrl: "https://tonejs.github.io/audio/casio/",onload: () => {
      loadNotes();
    }
  }).toDestination();

  function loadNotes() {
    notesToPlay.forEach((n) => {
      const eventId = Transport.scheduleRepeat((time) => {
        sampler.triggerAttackRelease(
          ["A1"],n.duration,n.timing + time,n.veLocity
        );
      },4);

      eventIds.push(eventId);
    });
  }

  document.getElementById("play").addEventListener("click",function () {
    playSynth();
  });

  document.getElementById("stop").addEventListener("click",function () {
    Transport.stop();
  });

  document.getElementById("replace").addEventListener("click",function () {
    const arrayIdxToReplace = 2;
    Transport.clear(eventIds[arrayIdxToReplace]);
    const note = notesToPlay[arrayIdxToReplace];
    Transport.scheduleRepeat((time) => {
      sampler.triggerAttackRelease(
        ["D1"],note.duration,note.timing + time,note.veLocity
      );
    },4);
  });
})();

HTML:

<div id="app">
  <button id="play">play me</button>
  <button id="stop">stop</button>
  <button id="replace">Replace 3rd note</button>
</div>

当我单击“替换三音符”按钮时,它将删除旧的事件,这很好,但是在安排新事件时,它与旧三音符的位置不同步。

一种解决方法是停止传输,然后单击以替换第三音符,然后再次单击弹奏,但是我希望能够在传输仍在播放时执行此操作。我去哪儿了?

以下是演示该问题的小提琴:

https://codesandbox.io/s/tonejs-forked-fxhzm?file=/src/index.js:0-1643

解决方法

要修复现在的结构,这很尴尬。麻烦的是,您添加的每个音符都在其自己的循环中,该循环在您每次调用scheduleRepeat时开始……您必须校正原始循环与新循环之间的偏移,这似乎有些棘手。

我建议您只调用一次scheduleRepeat,并让回调函数读取您已存储的笔记列表。这样,您只需替换或更改其中一个便笺,下次便会对其进行更改,并且不会出现任何计时问题。我认为这意味着在音符模式中包括音高。