在播放传输时安排 ToneJS 事件

Scheduling ToneJS events while transport is playing

我的 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,
    duration: 0.1,
    velocity: 1
  },
  {
    timing: 0.75,
    sameAsLast: false,
    duration: 0.1,
    velocity: 1
  },
  {
    timing: 1,
    sameAsLast: false,
    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>

当我点击替换第 3 个音符按钮时,它删除了旧事件,这很好,但是当它在其中安排新事件时,它与旧第 3 个音符所在的位置不同步。

解决此问题的一种方法是停止传输,然后单击以替换第 3 个音符,然后再次单击播放,但我希望能够在传输仍在播放时执行此操作。我哪里错了?

这里有一个 fiddle 来演示这个问题:

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

修复它现在的结构方式非常尴尬。问题是你添加的每个音符都在它自己的循环中,每当你调用 scheduleRepeat 时它就会开始......你将不得不纠正原始循环和新循环之间的偏移量,这似乎有点棘手。

我建议您只调用 scheduleRepeat 一次,让回调读取您存储的笔记列表。这样你就可以只替换或改变其中一个音符,下次它就会被改变,你就不会有任何时间问题。我认为这意味着在您的笔记架构中包含音调。