音频引擎架构
Audio Engine Architecture
音频渲染软件和多数系统一样是分层的"栈":硬件 → 驱动 → 底层 API → 3D 音频引擎,功能集通常模仿录音棚的多通道调音台。每个 2D/3D 声音是一条语音 (voice),沿语音总线经过编解码、增益、预发送滤波、辅助发送分出干湿两路、混响、后发送滤波和声像,然后由主混音器合成多声道信号,再经主输出总线(预放、LFE 生成、EQ、压缩、主音量)送到扬声器。资产上分片段、音效提示 (cue)、声音库和流式声音;混音靠分组、闪避、总线预设与混音快照、实例限制和语音抢占(GEA4 卷 II 15.5)。
音频软硬件栈
(卷 II 15.5)
- 硬件:至少驱动数字或模拟输出;也可能提供编解码器、混音器、混响单元、效果器、波形合成器或 DSP 芯片等"加速",PC 上常叫声卡;
- 驱动层(PC):让操作系统支持不同厂商的声卡;
- 底层 API:屏蔽硬件和驱动细节;
- 3D 音频引擎:构建在以上之上。
功能集模仿多通道调音台:接收大量输入,滤波、均衡、加混响和效果,按设计师设定的相对音量混合,最后送到扬声器或多轨录音的各声道。音频栈同样要接收大量 2D/3D 声音,处理、混合、设定增益,最后平移到扬声器声道。与 运行时引擎分层架构 的整体分层一致。
音频处理图
每个 3D 声音要经过:合成干声 PCM → 距离衰减与混响(产生湿声) → 干湿两路各自声像定位 → 所有声音的多声道信号混合 → 经 DAC 与功放驱动模拟输出,或直接送 HDMI/S/PDIF。由于同时有很多声源,这条管线有很多实例同时在跑,所以也叫音频处理图 (audio processing graph)(卷 II 15.5.1)。
语音 (voice):通过音频图的每个 2D 或 3D 声音。术语来自合成器的波形发生器。系统能同时支持的最大语音数由音频图中独立并行通路的数量决定,受内存、硬件和算力限制,也叫复音数 (polyphony)(卷 II 15.5.2.1)。
2D 语音与 3D 的区别:2D 声音本来就是每个扬声器一路的多声道信号,不经过声像;可能已"烘焙"了混响,不用引擎混响。所以 2D 声音通常在主混音器之前才进入管线(卷 II 15.5.2.1)。
总线 (bus):音频图中组件之间的连接。在软件里只是描述"存在连接"的逻辑结构(卷 II 15.5.2.2)。
语音总线
单个 3D 语音的组件顺序如下图(对应 GEA 图 15.40):预发送滤波作用于干湿两路,辅助发送把信号一分为二,湿路经混响,后发送滤波只作用于干路,最后干湿各自声像定位。
flowchart LR
C["编解码器 Codec"] --> G["增益 Gain"] --> PRE["预发送滤波 Pre-Send Filter"]
PRE --> AUX{"辅助发送 Aux Send"}
AUX -->|"干声"| POST["后发送滤波 Post-Send Filter"] --> PD["声像 Pan 干"]
AUX -->|"湿声"| RV["混响 Reverb"] --> PW["声像 Pan 湿 可加宽聚焦"]
PD --> MM["主混音器"]
PW --> MM| 组件 | 作用(卷 II 15.5.3) |
|---|---|
| 编解码器 | 解析源格式、必要时解压,把片段转成音频图的"标准"格式裸 PCM 放上总线;也可以程序化合成,但游戏几乎都用预录片段 |
| 增益控制 | 除了录音电平和离线工具调整外,运行时动态调音量 |
| 辅助发送 | 来自调音台把信号送出去过效果器再回来的"aux send";在图中是分叉点,一路干声、一路湿声 |
| 混响 | 可以用卷积;实时卷积不可行(缺 DSP 硬件或预算不够)时用混响槽 (reverb tank):缓存若干延迟副本与原信号混合,模拟早期反射和晚期混响,再加滤波模拟干涉和高频衰减 |
| 预发送滤波 | 在分叉前,干湿都受影响;模拟声源处的现象,如戴防毒面具说话 |
| 后发送滤波 | 只作用于干声;模拟遮挡/阻挡造成的发闷。顽皮狗也用它实现随频率的大气吸收 |
| 声像 | 每条 3D 语音总线以两个或更多声像器结束:干声按真实位置平移;湿声可以用更宽的聚焦角,窄门口来声只有几度,大厅中央则可设 360°(所有扬声器等量) |
主混音器
每个声像器输出一条多声道总线;主混音器把它们混成一路多声道信号(卷 II 15.5.4)。可以在硬件中做(模拟或数字混音),也可以全在软件里做(只能数字混音)。
- 模拟混音:本质是求和电路,相加后再衰减回目标电压范围。
- 数字混音:输入 PCM 流可能采样率、位深不同,先统一格式再逐时间点相加,必要时调整总幅值。
- 采样深度转换:反量化成浮点,再按目标位深重新量化(量化细节见 GEA 13.8.2,本库对应页面为 动画压缩)。
- 采样率转换:原理上是转回模拟再重采样,但模拟方式引入噪声,实际总是直接在 PCM 上做数字算法。例如采样率翻倍时可以在相邻样本间插值插入新样本,但要注意避免引入走样。
主输出总线
(卷 II 15.5.5,图 15.41)
| 组件 | 作用 |
|---|---|
| 前置放大 (Pre-amp) | 整体增益微调 |
| LFE 生成器 | 声像只驱动主扬声器;它提取混合信号中最低频的部分驱动低音炮 |
| 均衡器 (EQ) | 把频谱分为 4 到几十个可独立调节的频段 |
| 压缩器 (Compressor) | 动态范围压缩 (DRC):自动压低最响部分和/或抬高最安静部分 |
| 主音量 | 控制整个游戏的音量 |
| 输出 | 各扬声器的线路电平模拟信号,或 HDMI/S/PDIF 数字多声道信号 |
总线的实现
- 模拟总线:并行导线,单声道需要信号线和地线两根;几乎瞬时传输,主要难点是电平和阻抗匹配(卷 II 15.5.6.1)。
- 数字总线:组件不可能严格同步,所以在输入和/或输出端用环形缓冲 (ring buffer):一个读者、一个写者,各持读头和写头,前进到末尾回绕,两者互不越过,因此读者不会读到未写数据,写者也不会覆盖正在读的数据。最简单的是编解码器和 DAC 共享同一个环形缓冲;跨进程共享需要操作系统把同一块物理内存映射进两个虚拟地址空间。不能共享内存时(如 PC 与插卡声卡),各自有缓冲,由 DMA 控制器(如 PS3 PPU 与 SPU 之间)或 PCIe 总线拷贝(卷 II 15.5.6.2)。单读单写环形缓冲的并发要点见 无锁编程与内存序,游戏代码里同结构的请求队列见 事件队列。
总线延迟:游戏周期性地往编解码器喂数据叫服务音频 (servicing the audio)。喂得太慢缓冲下溢,声音短暂中断;喂得太快缓冲上溢,数据包丢失,声音"跳"。缓冲大小决定延迟:缓冲小延迟低但 CPU 要更频繁地喂;缓冲大则相反。延迟用毫秒而不是字节衡量,因为字节数依格式和压缩而变(卷 II 15.5.6.3)。
- 专业音频要求约 0.5 ms;
- 游戏只需音画同步:60 FPS 下一帧 16.6 ms,音频延迟不超过 16 ms 即可;渲染双/三缓冲再加电视延迟,三缓冲 60 Hz 游戏能容忍 ms 甚至更多;
- PS3 的 DMA 控制器每 5.5 ms 运行一次,所以音频缓冲通常配成 5.5 ms 的整数倍。
资产管理
(卷 II 15.5.7)
- 片段 (clip):最基本的音频资产,有自己的局部时间线(类比动画片段),也叫声音缓冲。3D 用单声道,2D 或 3D 立体声源用多声道。
- 音效提示 (sound cue):片段集合 + 描述如何处理和播放的元数据,通常是游戏请求播放声音的主要方式;也是分工手段:音效设计师在离线工具里做 cue,程序只管在合适的事件里播放。cue 可以是 5.1 音乐的六个声道、供随机挑选的一组变体、按顺序播放的一组声音;指定单次或循环;可以带中断时才播放的可选片段(对白被打断时的喉塞音、机枪循环停止时的回声"尾巴")。元数据还可以包括 2D/3D、FO min/max 与衰减曲线、所属分组、特殊效果、滤波或 EQ。索尼 Scream 引擎(顽皮狗《神秘海域》《最后生还者》所用)里 cue 甚至能包含任意脚本代码。
- 播放 cue 的 API 通常可以指定 2D/3D、位置速度、循环与否、内存中还是流式、音量等,并返回声音句柄 (sound handle)。句柄通常是全局句柄表的索引而不是裸指针,所以声音自然结束时句柄可以自动"置空";也能用来做线程安全:一个线程停掉声音,其他线程持有的句柄自动失效。
- 声音库 (sound bank):片段太多太细,不能逐个管理,所以打包成粗粒度的库。有的启动时加载常驻(如主角的声音),有的按关卡动态加载卸载。例如《最后生还者》里雨声、流水和梁木吱嘎声只在波士顿倾斜大楼里加载。有些引擎允许库在内存中重定位,以消除不同大小的库反复加载卸载产生的碎片(见 自定义内存分配器 的内存整理与重定位)。整体加载策略与 资源管理器 相同。
- 流式声音:音乐和语音太长,只需当前时间点附近的数据。每个流式声音维护一个较小的环形缓冲,播放前预载一小段,边播边从磁盘补充,只要补得比消耗快就能无缝播放(I/O 见 引擎文件系统与异步文件读写)。
混音
把每个对象发出的每个声音都物理正确地播放,结果是一片嘈杂。好游戏与伟大游戏的区别在于混音:听到什么、听到多少、不听到什么。目标是真实沉浸、不刺耳、有效传达玩法和剧情信息、始终符合情绪基调(卷 II 15.5.8)。
- 分组 (group):先把各声音的相对音量设对(脚步比枪声小)。分组借自调音台的编组:软件里通常只是给 cue 分类(音乐、音效、武器、语音……),用一个值控制整类的增益,还能整类暂停、恢复、静音。有些引擎也真的把一组信号混成一路,Scream 里叫预主混 (pre-master submix),混合后的信号可以再过滤波等处理(卷 II 15.5.8.1)。
- 闪避 (ducking):临时压低某些声音让另一些更清楚,如角色说话时压低背景声。可以由某类声音的出现触发、由游戏事件或代码触发;通常通过分组实现,也可以把一路信号接到另一条语音总线上 DRC 的侧链 (side-chain) 输入,让前者越响后者被压得越狠(卷 II 15.5.8.2)。
- 总线预设与混音快照(Scream 的两种形式):总线预设是单条总线上组件的一组参数(例如模拟大厅、车内或小壁橱的混响设置,或主输出总线的 DRC 设置);混音快照是同样思路用于各组增益(卷 II 15.5.8.3)。
- 实例限制 (instance limiting):控制同时播放的声音数,例如 20 个 NPC 同时开枪只播最近的三四个。既防嘈杂,也因为语音数有硬上限(硬件编解码器数或软件的内存与算力)。可以按组限制:最多 4 把枪、3 个人说话、5 个其他音效、2 条重叠音乐(卷 II 15.5.8.4)。
- 优先级与语音抢占 (voice stealing):有些引擎支持大量甚至无限的虚拟语音:技术上仍在播放,但可以暂时静音或停止以释放资源,引擎动态决定哪些映射到"真实"语音。最简单的依据是 FO max:听者在其外就静音;也可以给 cue 或分组设优先级,低优先级先被抢占。还可以设最短播放时间、被抢占时淡出而不是硬切、临时标记为"不可抢占"(卷 II 15.5.8.4)。
- 游戏内过场的混音:正常游戏时听者在相机附近,所有计算都用真实位置。过场里相机常拉远,两个角色的远景对话按物理已经听不见。这时可以让听者脱离相机,人为放到角色附近。混过场更接近给电影混音,引擎要能"打破规则"(卷 II 15.5.8.5)。
音频库与引擎概览
(卷 II 15.5.9)
| 名称 | 要点(GEA) |
|---|---|
| Windows UAA / WASAPI | 早期 DirectSound + WDM + KMixer 下各声卡实现差异很大;Vista 起的通用音频架构 (UAA) 只标准化有限硬件功能,其余用软件实现,并让操作系统掌控最终混音,多个应用能共享声卡(DirectSound 时代游戏可以独占声卡)。由 WASAPI 实现,但它不是给游戏用的 |
| XAudio2 / X3DAudio | Xbox 360、Xbox One 和 Windows 上的底层高性能 API,取代 DirectAudio;支持可编程 DSP、子混音、多种格式和多速率处理;X3DAudio 是其上的 3D 渲染库。XACT 与 XNA 已不再支持 |
| Scream | 索尼的 3D 音频引擎,顽皮狗在 PS3/PS4/PS5 上使用;架构模仿完整调音台。顽皮狗在其上实现了随机遮挡建模和基于门户的环境音频系统 |
| ALSA | Linux 内核中对应 UAA 驱动模型的组件,取代 OSSv3 |
| QSA | QNX Neutrino 实时系统的驱动级音频 API;GEA 推荐其文档作为了解音频硬件概念的材料 |
| OpenAL | 刻意模仿 OpenGL 设计的跨平台 3D 音频 API;早期开源,现为授权软件;实现有 OpenAL Soft、AeonWave-OpenAL |
| AeonWave 4D | Adalin B.V. 的低成本 Windows/Linux 音频库 |
| FMOD Studio | "专业音频"风格的创作工具 + 运行时 3D 音频 API(Windows、Mac、iOS、Android) |
| Wwise | Audiokinetic 的 3D 音频引擎;不以调音台为模型,而是围绕游戏对象和事件组织 |
| Unreal Engine | 自带 3D 音频引擎和集成工具链 |
注:GEA 说 OpenAL"早期开源、现为授权软件",这只适用于 Creative 的参考实现。它列举的 OpenAL Soft 本身是开源的(LGPL 2 或更高版本,fork 自 openal.org 早期开源的 Windows 版本;见 kcat/openal-soft 仓库 README 与 COPYING)。
时效说明:上表是 GEA 写作时的情况(例如 FMOD 平台列表只列了四个),选型前应查各产品当前文档。UE5 当前的音频资产体系见 音频系统与 MetaSounds。
取舍
- 缓冲大小是延迟与 CPU 负担的直接取舍;游戏以"不超过渲染延迟"为界即可。
- 程序用 cue 和句柄、设计师管 cue 内容,是音频系统的基本分工;把播放请求做成异步、可合并的队列见 事件队列。
- 语音数总有上限,实例限制和抢占规则是混音设计的一部分,而不只是性能优化。
出处
- Game_Engine_Architecture_4th_Edtion_Volume_2_-_Jason_Gregory.pdf
- Jason Gregory《Game Engine Architecture》第 4 版(2026)卷 II 第 15 章 15.5 节