createGain 是 Web Audio API 中控制音量最直接的节点,但必须显式连接到音频图谱(如源→gainNode→destination),且 gain 属性需用 setValueAtTime 等调度方法避免咔哒声;多音源需独立 GainNode,主增益后建议加压缩器防削波。

createGain 是 Web Audio API 中控制音量最直接、最常用的节点,但它不是“设置一个值就完事”的简单开关——它必须嵌入音频节点图谱(audio graph)中,且其 gain 属性的调度方式直接影响听感是否自然。
GainNode 必须显式连接进音频图谱才能生效
很多人写完 const gainNode = audioCtx.createGain() 就直接改 gainNode.gain.value,但没连入图谱,音量完全不会变。Web Audio 的信号流是单向、显式连接的,断开即静音。
- 正确顺序:源节点 →
gainNode→audioCtx.destination - 常见错误:漏掉
gainNode.connect(audioCtx.destination),或误写成source.connect(audioCtx.destination)绕过增益节点 - 媒体元素源(如
<audio>)需用createMediaElementSource()包装,不能直接调audio.volume—— 后者只影响 HTML5 原生音量,不走 Web Audio 图谱
gain.value 直接赋值 vs. 调度方法的区别
gainNode.gain 是一个 AudioParam,支持立即赋值和时间调度。人耳对响度变化极其敏感,突变会引发“咔哒声”(click),尤其在静音/非静音切换时。
-
gainNode.gain.value = 0.3:立即生效,适合初始化或 UI 拖动结束后的最终值 -
setValueAtTime(0, ctx.currentTime)+exponentialRampToValueAtTime(1, ctx.currentTime + 1):平滑淡入,推荐用于启停、音量过渡;exponential比linear更符合人耳对响度的感知曲线 - 避免
gainNode.gain.setValueAtTime(0.001, t)后立刻设回1:微小非零值仍可能触发削波或底噪,静音请用0
多个音源共用或独立控制音量的连接模式
一个 GainNode 只能控制它上游节点的输出。想分别调两个音轨音量,就得为每个源配一个 GainNode;想统一控制总音量,再加一级“主增益”节点。
立即学习“前端免费学习笔记(深入)”;
- 双音轨独立调节:源A →
gainNodeA→ 合并器;源B →gainNodeB→ 合并器 → 主增益 →destination - 合并器用
createChannelMerger(2)或直接多路connect()到同一目标(如gainNodeA.connect(dest)和gainNodeB.connect(dest))均可,后者更轻量 - 注意:多个源同时连到
destination会叠加幅度,若未限幅,容易过载削波(clipping),建议主增益节点放在最后统一压限
移动端自动播放限制与上下文启动时机
所有现代移动端浏览器要求用户手势(如 click、touchstart)触发 audioCtx.resume(),否则 createGain() 节点虽可创建,但整个图谱无信号流,调节无效。
- 典型错误:页面加载完立即
audioCtx = new AudioContext(),但未监听用户交互就调gainNode.gain.value - 修复方式:在按钮
click回调里先执行audioCtx.state === 'suspended' && audioCtx.resume(),再连接节点、设置增益 - 后续调节(如拖动音量条)无需重复
resume(),只要上下文已激活即可
真正容易被忽略的是:GainNode 本身不处理削波,它只是放大或衰减信号。当 gain.value > 1 且输入信号峰值已接近 ±1,输出就会截断失真。实际项目中,应在主增益后加一层 createDynamicsCompressor() 或手动做峰值检测,而不是只盯着 gain 值调来调去。



















