Web Audio API 中 GainNode 与 BiquadFilterNode 需串联构成处理链:多个 BiquadFilterNode 分频段(如低/中/高)用 peaking 模式独立调节 frequency/Q/gain,GainNode 用于整体增益微调;所有节点必须共享同一 AudioContext,滑块需映射为 dB 值并用 setValueAtTime() 实时更新,避免 suspended 状态与 iOS 调度限制导致的失效。
GainNode 和 BiquadFilterNode 怎么配合用纯 HTML 无法实现音频均衡器,必须靠 JavaScript 驱动 Web Audio API。核心是用多个 BiquadFilterNode 分频段调节(比如低频 100Hz、中频 1kHz、高频 10kHz),再用 GainNode 做增益微调;所有节点串成一条链,最后连到 destination。
常见错误是把多个 BiquadFilterNode 并联后直接求和——Web Audio 不支持隐式混音,并联必须显式用 ChannelMergerNode 或多个 connect() 到同一个目标(但会叠加相位,易失真)。
type: "peaking" 模式,它允许独立调 frequency、Q(带宽)、gain(dB 增益)Q 值别设太高(>2 就容易啸叫),尤其在 2–4kHz 人声区AudioContext 实例,否则时间线不同步,拖动滑块时有咔哒声BiquadFilterNode.gain 实时更新用 <input type="range"> 最直接,但要注意:滑块默认值域是 0–100,而 gain 是 dB 值(典型范围 -24 到 +12),必须做线性映射。直接写 filter.gain.value = slider.value 会导致增益爆炸或静音。
示例映射逻辑:
立即学习“前端免费学习笔记(深入)”;
const slider = document.getElementById('bass-slider');const bassFilter = audioCtx.createBiquadFilter();bassFilter.type = 'peaking';bassFilter.frequency.value = 100;<p>slider.addEventListener('input', () => {// 把 0–100 映射到 -24dB ~ +12dBconst dB = (slider.value / 100) * 36 - 24;bassFilter.gain.setValueAtTime(dB, audioCtx.currentTime);});
setValueAtTime() 而非直接赋值 .value,避免音频线程冲突导致跳变linearRampToValueAtTime(),但响应延迟 >20ms 会影响实时感min/max 属性建议设为 0/100,用 JS 映射比改 HTML 属性更可控start() 报错 “InvalidStateError: Cannot call start()”这是 Web Audio 最常见的权限陷阱:iOS Safari 和新版 Chrome 要求音频上下文必须由用户手势(如 click、touchstart)触发才能进入“运行态”。单纯页面加载完就 new AudioContext(),上下文初始是 suspended 状态。
audioCtx.resume(),且仅调一次load 回调里自动 resume —— 用户没点过页面,依然失败audioCtx.state === 'suspended',并在用户交互后恢复,而不是依赖 onstatechange(有延迟)<audio> 元素加载文件,记得设 preload="auto",否则 decodeAudioData 可能因未加载完成而 resolve 空数据iOS WebKit 对 Web Audio 的调度更保守,尤其在后台标签页或低电量模式下,AudioContext 可能被节流甚至暂停。另外,iOS 不支持 MediaElementAudioSourceNode 的实时重连(比如换歌后重新 connect() 到同一滤波链会断)。
input 事件里频繁创建/销毁 BiquadFilterNode,复用节点并只更新 gain、frequency
touchmove + { passive: false } 才能阻止默认滚动行为,否则滑块拖拽会被截断BiquadFilterNode,iOS Safari 在低端机型上会出现明显延迟,建议合并相邻频段或用 ConvolverNode 加载预设 FIR 滤波器currentTime 做定时逻辑——iOS 的 audioCtx.currentTime 在后台可能停滞均衡器真正的复杂点不在算法,而在音频上下文生命周期管理与跨端输入事件调度的耦合。一个滑块背后,其实是用户交互、音频线程、系统电源策略三者的实时博弈。