如何让Web Audio API底鼓合成器按钮每次点击都从头发声?
Web Audio API底鼓合成器重复触发问题解决
问题描述
使用Web Audio API构建底鼓合成器时,按钮触发函数可生成带音高和增益扫频的正弦波,但按钮仅能生效一次,再次点击无法从头播放声音。尝试将osc.start()放入自定义函数中失败,因为振荡器的.start()方法无法被多次调用。
原代码:
const audioCtx = new AudioContext(); // Initiate Audio Context const osc = audioCtx.createOscillator(); // Create An Oscillator const volume = audioCtx.createGain(); // Create A Gain osc.type = "sine"; // Set the type of the waveform osc.frequency.value = 440; // Set the frequency value of the oscillator osc.start(); // Start playing the oscillator osc.connect(volume); // Set the destination of the oscillator function generateKick() { volume.gain.value = 1; osc.frequency.setTargetAtTime(22, 0, 0.1) volume.gain.setTargetAtTime(0, audioCtx.currentTime, 0.1); volume.connect(audioCtx.destination); }
解决方案
Web Audio API中的振荡器节点(OscillatorNode)是一次性的,调用start()后无法再次启动。解决核心是每次触发声音时创建新的振荡器和增益节点,具体修改如下:
const audioCtx = new AudioContext(); // 初始化音频上下文 function generateKick() { // 每次点击都创建新的振荡器和增益节点 const osc = audioCtx.createOscillator(); const volume = audioCtx.createGain(); osc.type = "sine"; osc.frequency.value = 440; // 初始频率 // 构建音频节点链:振荡器 → 增益 → 系统输出 osc.connect(volume); volume.connect(audioCtx.destination); // 设置初始增益 volume.gain.value = 1; // 音高扫频:从当前时间开始,0.1秒内降到22Hz osc.frequency.setTargetAtTime(22, audioCtx.currentTime, 0.1); // 增益淡出:从当前时间开始,0.1秒内衰减至0 volume.gain.setTargetAtTime(0, audioCtx.currentTime, 0.1); // 启动振荡器 osc.start(); // 0.2秒后停止振荡器(确保扫频和淡出完成) osc.stop(audioCtx.currentTime + 0.2); // 振荡器停止后断开连接,释放资源 osc.onended = () => { osc.disconnect(); volume.disconnect(); }; }
关键说明
- 一次性节点特性:振荡器节点无法重复启动,因此每次触发必须创建新实例。
- 资源管理:通过
stop()指定停止时间,并在onended事件中断开节点连接,避免不必要的内存占用。 - 节点链重建:每次触发时重新连接振荡器、增益和输出节点,确保声音正确路由。
内容的提问来源于stack exchange,提问作者Alp Seyrekbasan
相关产品推荐
相关产品推荐

