使用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
相关产品推荐
相关产品推荐

