Tone.js中sampler.triggerAttackRelease()多次调用后无声问题求助
解决Tone.Sampler添加time/velocity参数后多次点击无声音的问题
问题根源
你遇到的问题是因为triggerAttackRelease方法的time参数传入了固定值0。Tone.js的time参数基于音频上下文的时间线,第一次点击时0对应音频上下文启动后的初始时间,是有效的;但后续点击时,音频上下文的时间已经推进,0这个时间点已成为“过去”,Tone.js会自动跳过所有落在过去的事件,导致没有声音输出。
而仅传递notes和duration时,time参数会使用默认值Tone.now()(当前音频上下文的实时时间),所以每次点击都会立即触发声音,不会出现失效问题。
修复方案
将time参数改为Tone.now()(表示立即触发),或者直接省略time参数(使用默认值),同时保留velocity参数即可:
修改后的核心代码
function playSample() { if (Tone.context.state !== 'running') { Tone.start(); } // 方案1:使用Tone.now()作为time参数,明确指定立即触发 sampler.triggerAttackRelease(["Eb4", "G4", "Bb4"], 4, Tone.now(), 0.1); // 方案2:省略time参数,直接传递velocity(参数顺序自动匹配) // sampler.triggerAttackRelease(["Eb4", "G4", "Bb4"], 4, undefined, 0.1); }
完整修复代码
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8" /> <title>Simple HTML</title> <meta name="viewport" content="width=device-width, initial-scale=1" /> <script src="https://unpkg.com/tone"></script> <script> const sampler = new Tone.Sampler({ urls: { C4: "C4.mp3", "D#4": "Ds4.mp3", "F#4": "Fs4.mp3", A4: "A4.mp3", }, release: 1, baseUrl: "https://tonejs.github.io/audio/salamander/", }).toDestination(); // 提前等待资源加载完成,避免每次点击重复判断 Tone.loaded().then(() => { console.log("Sampler资源加载完成"); }); function playSample() { if (Tone.context.state !== 'running') { Tone.start(); } sampler.triggerAttackRelease(["Eb4", "G4", "Bb4"], 4, Tone.now(), 0.1); } </script> </head> <body> <h1>Un accord répété, Demo</h1> <button onclick="playSample()">Click me to play sample note!</button> </body> </html>
额外优化说明
- 把
Tone.loaded().then()移到全局初始化阶段,不需要每次点击都执行资源加载判断,提升性能。 - 如果需要延迟触发声音,可以在
Tone.now()基础上加偏移值,比如Tone.now() + 1表示1秒后触发。
内容的提问来源于stack exchange,提问作者Frédéric Faure
相关产品推荐
相关产品推荐

