You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Tone.js的HTML播放按钮重复点击失效,求排查及修复方案

问题原因

你用的note.time是Tone.js里的绝对时间戳,对应Tone.Transport的全局时间线。第一次点击按钮时,这些时间点(0、0.5、1)还在未来,所以能正常触发音符;但第一次播放后,Transport的时间已经走到了1秒之后,第二次点击时,这些时间点早就过去了,自然不会再发声。

修复方法

有两种实用的修复思路:

思路1:基于当前时间计算相对偏移(推荐)

每次点击时,以当前的Tone时间为基准,给每个音符加上偏移量,确保音符都安排在未来:

<script src="https://unpkg.com/tone"></script>

<button id="tunebtn">Play Notes</button>

<script>
  let synth = new Tone.Synth().toDestination();
  let notes = [
    { note: "C4", duration: "8n" , offset: 0},
    { note: "D4", duration: "8n" , offset: 0.5},
    { note: "E4", duration: "8n", offset: 1}
  ];

  const playNotes = () => {
    // 获取当前的Tone时间,以此为基准安排音符
    const now = Tone.now();
    notes.forEach(note => {
      synth.triggerAttackRelease(note.note, note.duration, now + note.offset);
    });
  };

  document.getElementById("tunebtn").addEventListener("click", playNotes);
</script>

这里把原来的time字段改成offset,每次点击都用Tone.now()获取当前时间,加上偏移量,保证每次点击的音符都在当前时间之后触发,不会受之前的时间线影响。

思路2:重置Transport时间(仅适用于无其他调度任务的场景)

如果你的场景里不需要用Transport运行其他任务,也可以每次点击时重置全局时间线:

<script src="https://unpkg.com/tone"></script>

<button id="tunebtn">Play Notes</button>

<script>
  let synth = new Tone.Synth().toDestination();
  let notes = [
    { note: "C4", duration: "8n" , time: 0},
    { note: "D4", duration: "8n" , time: 0.5},
    { note: "E4", duration: "8n", time: 1}
  ];

  const playNotes = () => {
    // 重置Transport时间并重启
    Tone.Transport.stop();
    Tone.Transport.position = 0;
    Tone.Transport.start();
    notes.forEach(note => {
      synth.triggerAttackRelease(note.note, note.duration, note.time);
    });
  };

  document.getElementById("tunebtn").addEventListener("click", playNotes);
</script>

这种方法会打断全局时间线,如果你有其他基于Transport的调度任务,会受影响,所以仅推荐在简单场景下使用。


内容的提问来源于stack exchange,提问作者ElonTusk1312

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 03:09:25