一块深色播放器,左上角是播放和静音两枚圆钮,中间是一张黑白手部照片。按下播放,画面立刻开始随音乐崩坏:红绿蓝三个通道分别朝不同方向平移,边缘泛出青红重影;画面里不时有小方块被整块搬到别处;横向的扫描线一条条错位抖动。音乐安静时画面几乎复原,鼓点砸下来的瞬间撕裂最凶——因为所有强度参数都取自实时频谱能量。
它不是滤镜也不是视频,而是每一帧都在直接读写 Canvas 的像素数组。所以换一张图、换一段音乐,效果照样成立,且完全在浏览器里现算。键盘上按 1、2、3 还能单独触发三种故障,方便调试和演示。
这套音频故障视觉的四个组成部分
频谱分析器提供“强度”。音频节点接进分析器后,每帧取一次频域数据,对低频区间求平均得到一个能量值,方块数量、通道偏移量、扫描线触发概率全部由它推导——所以画面是真的在跟着音乐动,而不是循环播放一段固定动画。
RGB 分离靠索引偏移。取出整幅图的像素数组后,把红、绿、蓝三个分量分别写到偏移若干像素的位置上,就得到经典的三色错位重影,代价只有一次遍历。
方块搬运用的是取图贴图。随机框一小块像素读出来,再贴到另一个随机位置,两行调用完成,做出“数据错位”的观感。
扫描线的位移量来自对应频段。每条线的偏移不是随机数,而是取该行序号对应的频率值换算得来,于是高频丰富的段落线条抖得更细碎。
三个让故障看起来“像真的”的做法
其一,每帧先重绘底图再叠故障。如果在上一帧的结果上继续撕裂,几秒钟就会糊成一团噪点。源码的顺序是:清空、画原图、加通道错位、加方块、加扫描线。这样每一帧的破坏都是从干净底图出发的,强度可以随音乐上下起伏,也能真正“恢复”。
其二,强度用了指数放大。方块与故障次数并不是能量的线性映射,而是这种写法:
const boxCount = Math.ceil((levelAvg / 110) ** (levelAvg / 110));
底数和指数同时随能量增长,结果就是:安静段落几乎为 1,稍有起伏时缓慢增加,能量冲高时急剧爆发。听感上的“炸开”正需要这种非线性——用线性映射会显得平淡,用阈值开关又太生硬。
其三,不是每帧都重画。循环里有一个计数器,隔几帧才真正执行一次绘制。这既降低了像素操作的开销(读写整幅图像数据是这类效果最重的部分),也让故障有“卡帧感”,反而更贴近真实信号损坏的样子。同时还判断了首个频段是否为零,避免在静音或未开始播放时空转。
拿到源码后能改什么
换底图最简单:替换图片路径即可,脚本里绘制底图时按画布宽度等比铺开。建议选对比强、结构清晰的图,细节太碎的照片撕裂后会看不出形状。
换音乐同样只改一个音频源路径。注意浏览器的自动播放策略——必须由用户点击后才能出声,所以播放按钮不能省。若音频跨域,还需要服务端允许跨域读取,否则分析器拿不到数据,画面就不会动。
调节口味有几个直接的入口:三种故障各自的随机范围(方块大小、搬运距离)、扫描线的触发阈值、能量映射里的两个除数。想要更克制的效果,把方块函数关掉、只留通道错位,会很适合做背景;想要更狂暴,把扫描线阈值调低即可。播放与静音按钮的样式是纯 CSS 画的三角形与方块,改颜色和尺寸不需要图标文件。
运行提示:读写像素需要画布未被跨域数据污染,因此必须用本地服务器打开,直接双击 index.html 会因安全限制导致取像素失败。音频需用户点击后才会播放,这是浏览器策略而非缺陷。建议使用近两年版本的 Chrome、Edge、Firefox 或 Safari。详细运行方法请参见压缩包内的帮助文档。
关于这个音频可视化特效的常见问题
可以换成自己的背景图和音乐吗?
可以,两者都是单独的路径引用,替换即可。图片建议放在同目录下,避免跨域导致画布被污染而无法读取像素。
能不能改成麦克风输入实时可视化?
能。把音频源从媒体元素换成麦克风流即可,分析器与绘制部分完全不用改。注意麦克风需要用户授权且页面须在安全上下文中。
手机上能用吗?
能显示,但整幅像素读写在移动端开销偏高,画布较大时会掉帧。建议移动端缩小画布尺寸、提高隔帧间隔,或只保留通道错位这一种故障。
画面完全不动是怎么回事?
先确认音频是否真的在播放且未静音;再确认是否通过服务器访问;如果音频来自其他域名,还要确认对方允许跨域读取——这三点中任意一条不满足,分析器都拿不到有效数据。
它适合放在什么地方
这种视觉语言天生属于音乐与潮流领域:单曲或专辑的宣传页、电子音乐现场的大屏背景、播客站点的播放器区块、赛博朋克风格的活动落地页。也可以剥离音频部分,只保留故障绘制,做成鼠标悬停触发的图片特效。频谱取值、通道错位、方块搬运与扫描线抖动的完整实现都在源码里,注释清晰,下载后可查看。