createAnalyser节点必须连接有效音频源才能工作,其frequencyBinCount由只读的fftSize决定,getByteFrequencyData需传入匹配长度的Uint8Array,且须确保AudioContext处于running状态。

createAnalyser 节点必须接在音频源之后,不能直接用
AudioContext.createAnalyser() 本身不产生或接收音频,它只是个“监听器”——必须显式把音频数据流(比如 AudioBufferSourceNode、MediaStreamAudioSourceNode 或 OscillatorNode)通过 connect() 接到它上面,否则 analyser.frequencyBinCount 会是 0,getByteFrequencyData() 始终返回全 0 数组。
常见错误:只调用 context.createAnalyser() 就以为能拿到频谱,没连节点、没启动源、没触发播放,结果 canvas 画出来永远是平的。
- 必须先有有效音频源(哪怕只是
oscillator.start()发个正弦波) - 必须执行
source.connect(analyser),再analyser.connect(context.destination)(否则声音也听不见) - 若源是
AudioBufferSourceNode,注意它是一次性节点,播放完就断开,需重新创建或用循环
frequencyBinCount 是只读属性,实际大小由 FFT size 决定
analyser.frequencyBinCount 看起来像可配置项,其实它是只读的,值恒等于 analyser.fftSize / 2。真正能设的是 analyser.fftSize,且只能是 2 的幂次,范围通常是 32–32768(浏览器实现有差异,Chrome 最大支持 32768,Safari 可能只到 2048)。
选太小(如 32):频谱粗糙,几十个频点根本分不清人声和鼓点;选太大(如 32768):计算开销高,getByteFrequencyData() 调用变慢,canvas 刷新卡顿。
立即学习“前端免费学习笔记(深入)”;
- 可视化常用
analyser.fftSize = 256(128 个频点)或512(256 个频点)平衡精度与性能 - 设置后立即生效,无需重启节点或重连
- 修改
fftSize会清空内部缓冲区,之前的数据不可恢复
getByteFrequencyData 需要传入 Uint8Array,且长度必须匹配
analyser.getByteFrequencyData() 不返回新数组,而是把结果写入你传入的 Uint8Array。如果数组长度小于 analyser.frequencyBinCount,多余频点被丢弃;如果更大,超出部分留空(不报错但浪费内存)。
典型错误:用 new Array(analyser.frequencyBinCount) 或 new Float32Array(),导致静默失败——它只接受 Uint8Array,且要求类型严格匹配。
- 正确做法:
const freqs = new Uint8Array(analyser.frequencyBinCount); - 每次绘制前都得调用
analyser.getByteFrequencyData(freqs),它不是自动更新的 - 数值范围是 0–255,0 表示该频段无声,255 表示当前帧最大能量(对数压缩后)
canvas 绘制频谱时要注意 requestAnimationFrame 时机
频谱数据不是实时连续的——getByteFrequencyData() 拿到的是上一个音频处理周期(通常 128 或 256 样本)的 FFT 结果。如果 canvas 渲染频率远高于音频处理块率(比如 60fps vs 44.1kHz/128 ≈ 344Hz),会反复画同一帧数据,看起来“卡住”或跳变。
更稳的做法是把绘制逻辑放在 requestAnimationFrame 里,但别盲目高频调用;或者监听 audioContext.onstatechange 防止 context 暂停后还拼命读数据。
- 推荐每帧只调用一次
getByteFrequencyData(),避免重复读取同一块 FFT 缓冲 - 如果源已停止且
audioContext.state === 'suspended',getByteFrequencyData()会返回全 0,此时应暂停绘制 - 移动端尤其注意:iOS Safari 默认 suspend context,需用户手势触发
audioContext.resume()
audioContext.state 是 "running",再查 analyser.fftSize 和 freqs.length 是否一致,比调 canvas 颜色重要得多。



















