ACM 卷积
ACM 卷积在 CPU 上运行 FMOD 的分段混响。共享输入的批次变换一路干信号,应用浮点或半精度浮点的冲激响应分段,并把湿结果重叠相加。
仓库笔记截至 2026年10月10日
它补上的缺陷
Subnautica: Below Zero 可能以噼啪声开始,然后沉寂,数分钟后再恢复。到达主机设备的 PCM 含有非有限浮点。对 FMOD 的 DSP 回调所做的内存内跟踪表明,有限的音频进入卷积混响,离开的却是垃圾。HLE 函数 sceAcm_ConvReverb_SharedInput、批提交和 sceAcmBatchWait 在没有写出输出的情况下返回成功。
FMOD 随后把那块未写过的湿缓冲区混进图里。NaN 扩散到后面的效果。AudioOut 的净化把它们换成静音,却无法修复已被污染的滤波器历史。第二个错误让对初始批标识符 -1 的等待成功。FMOD 把失败的初始等待当作“还没有上一块湿缓冲区”,并且只在真正完成的作业之后才混音。
分段卷积
描述符布局与在 FMOD 的 ACM 后端里观察到的布局一致。冲激响应分段是交错的复数 bin。一块含 B 个 bin 的块属于长度为 2B 的变换。输入、输出和重叠缓冲区彼此分开,并且是平面的。只接受观察到的、偏移为零的 float32 和 float16 频谱布局。
一批在 CPU 上运行。输入历史跨颗粒、也跨环回绕保留,重叠被带进下一个输出颗粒。多个输出可以共享同一次输入变换和同一次历史推进。单声道输入可以供给不止一个声道。逆变换是归一化的。对一个实数冲激分段做独立逆变换,能量落在补零块的前半,这确认了频谱符号。游戏所使用的打包冲激省略了奈奎斯特 bin。
等待、限制与复测
构建者把指针数组和增益捕获进一条有界的命令记录。PCM 本身在批次开始时读取。等待只对这个上下文实际完成的批次成功。销毁上下文会释放历史。无效边界、未知的命令编码和不受支持的布局返回错误。
独立的 ACM FFT、IFFT 和声像器操作没有实现。声道上限为 8,输出上限为 32,块上限为 1024。历史存储是有界的。在已签名的运行程序上,90 个每秒一次的 PCM 快照不含非有限采样,峰值为 0.1255,第一次高于 0.001 的音频出现在 11.03 秒。维护者确认了声音。这些采样是一次探测,不是游戏发出的每一个采样。
已经实现的部分
- 面向 FMOD 共享输入和共享 IR 混响批次的分段 FFT 卷积。
- float32 和 float16 复数频谱、重叠相加,以及跨颗粒的历史。
- 等待只对那个上下文已完成的批次成功。初始的 -1 标识符会失败。
- Subnautica 复测上的有限 PCM,噼啪声和随后的沉寂已经消失。
尚未实现的部分
- 独立的 ACM FFT、IFFT 和声像器调用尚未实现。
- 非零频谱偏移和未测量的路由布局会被拒绝。
- 卷积在 CPU 上运行。没有 GPU FFT 路径。
相关机制
这些页面说明什么