2.67ms里的声学炼金术:WASM实时卷积混响
English Abstract (Show HN)
This post demonstrates a high-performance WebAssembly SIMD-FFT convolver designed to beat strict Web Audio API frame budgets. Running a 3-second IR at 48kHz (128 samples / 2.67ms frame) requires ~37M FLOPs. A time-domain O(N²) calculation takes 4.6ms — blowing past the deadline and causing audio thread overload. By using WASM-SIMD with a partitioned overlap-add algorithm, I reduced the latency to 0.65ms, staying safely under the physical deadline. The embedded sandbox below lets you toggle between algorithms and acoustic spaces to see the difference in real time.
上篇我们造出了 0.15ms 的 SIMD FFT 引擎。今天把它开上赛道—— 用 2.67ms 的帧预算,在浏览器里伪造一座 3 秒尾音的史诗大教堂。
引擎已就位,赛道在哪里?
上一篇《128位向量暴力美学》里,我们把 FFT 从 JS 的 1.8ms 压到了 SIMD 的 0.15ms。 12 倍算力碾压,数字很漂亮。但一个问题始终悬着:FFT 造出来是干什么的?
大多数前端觉得 FFT 就是用来画频谱柱状图的。那是对 FFT 最大的误解。 FFT 的真正奥义,是快速卷积——把时域里 O(N²) 的不可能任务, 降维成频域里 O(N log N) 的工程问题。
而卷积,就是混响。
时域卷积的物理诅咒
什么是混响?一句话:混响就是卷积。 你把一段干声(Dry Signal)和房间的脉冲响应(Impulse Response)做卷积, 就得到了带有空间感的湿声(Wet Signal)。
一个 3 秒尾音的"史诗大教堂",脉冲响应有 144,000 个采样点(48kHz × 3s)。 AudioWorklet 每帧给你 128 个采样。时域卷积的运算量:
FLOPs = 2 × 128 × 144,000 = 36,864,000
约 36.9M 次浮点运算
在 8 GFLOPS 的标准算力下,这需要 4.6ms。 直接刺穿 2.67ms 的帧预算死线。线程爆音,音频断裂。 这不是优化问题,是 O(N²) 的物理诅咒—— IR 越长,计算量以平方级增长,没有任何微优化能救你。
小录音室(0.5s IR)勉强能苟活,大教堂直接崩盘。 这就是为什么浏览器里从来没有人做过实时大空间混响—— 直到我们搬出 FFT。
空间炼金术:Overlap-Add 快速卷积
时域卷积的致命伤是 O(N²)。但卷积定理告诉我们:时域的卷积等于频域的乘法。
把信号和 IR 都扔进 FFT,在频域里做一次极其廉价的逐元素相乘, 再 IFFT 回时域。复杂度瞬间从 O(N²) 降到 O(N log N)。
但工程上有个问题:IR 太长了。 3 秒的 IR 意味着 FFT size 要覆盖 144,000 + 128 - 1 = 144,127 个点。 直接做一次巨型 FFT 不现实。
答案是重叠相加法(Overlap-Add):
- 把长 IR 切成 128-frame 的小块
- 每块独立做 FFT → 频域乘法 → IFFT
- 把结果重叠相加,拼出完整卷积
每个子卷积都是一个小规模 FFT,SIMD 128 位向量一条指令算 4 个 float。 频域乘法的 FLOPs 极低——复数乘法不过是 4 次实数乘加。 最终延迟:0.65ms,稳稳压在帧预算内。
128位向量:频域里的最后加速
频域乘法看起来简单——复数乘以复数。但在 144,000 个采样点的 IR 面前, 简单乘几万次也不少。SIMD 的价值在这里体现:
v128 寄存器,一条指令,4 个 float 并行。复数乘法 (a+bi)(c+di) 需要 4 次实数运算, SIMD 把它打包成一条指令同时处理 4 组。 相当于把频域乘法的吞吐量直接翻 4 倍。
结合 Overlap-Add 的分块策略:
- 小录音室(0.5s IR):0.18ms
- 大型音乐厅(1.5s IR):0.35ms
- 史诗大教堂(3.0s IR):0.65ms
无论空间多大,延迟始终压在 1ms 以内。这就是 O(N log N) 对 O(N²) 的降维打击。不是微优化,是量级跃迁。
彩蛋:用 FLOPs 定律处决落后算法
下面的沙盒里,所有延迟数字都由 FLOPs 公式推导,不是随机数。 8 GFLOPS 的标准算力基准,剥离了设备差异,只留下算法复杂度的裸对决。
试着把声学空间从"小录音室"切到"史诗大教堂",看时域 O(N²) 如何刺穿 2.67ms 死线; 再切到 SIMD-FFT,看 O(N log N) 如何稳如磐石。
延迟数字基于物理推导:时域 FLOPs = 2 × BlockSize × IRLength, 频域 FLOPs = 3 × 5 × N × log₂(N) + 2N(含 SIMD 8x 加速), 基准算力 8 GFLOPS。你的设备实际性能可能不同,但复杂度鸿沟是数学事实。
本系列上一篇:128位向量暴力美学:WASM-SIMD 重构音频核心
更早一篇:逃离V8的引力:WASM零拷贝音频引擎