最近看到一个很适合游戏开发者关注的小项目:AIRE。它不是通用播放器,也不是 DAW 级音频工作站,而是一个更贴近游戏和交互式应用需求的实时音频引擎。
项目作者是在业余时间开发 2D 游戏时遇到问题:现有音频库要么太底层,要么只解决“把声音播出来”,但游戏里真正麻烦的是运行时控制、声音状态切换、低延迟混音、合成音效,以及后续的空间音频和环境声学。于是作者干脆自己做了 AIRE。
为什么游戏音频不只是播放文件
做普通媒体播放,核心问题是解码、缓冲和稳定输出。但交互式应用不一样。游戏里的声音往往要跟随玩家输入、角色位置、动画状态和场景变化实时改变:
- 角色走近瀑布时,水声要逐渐变大
- 子弹从左侧飞过时,声像要随位置变化
- 菜单音效要短促、清晰,并且不能有爆音
- 背景音乐要能暂停、恢复、淡出、切换
- 技能、碰撞、拾取物等音效可能在同一帧同时触发
这类需求要求音频系统有一个可靠的实时控制面。调用方不应该直接阻塞音频线程,也不应该在音频回调里做文件 IO、锁等待或复杂分配。AIRE 的价值就在这里:它试图把“播放声音”和“实时控制声音”放进同一个简单模型里。
当前定位
AIRE 的 crate 描述是:面向游戏和交互式应用的实时音频引擎。它用 Rust 编写,底层依赖 cpal 打开系统默认输出设备,并在音频线程里驱动混音器。
从公开文档和源码看,它的核心抽象非常直接:
Engine:打开输出设备,启动音频流,负责把控制命令送到音频线程Sound:把一个音频源包装成可播放声音,附带音量、声像和效果链SoundHandle:声音加入引擎后返回的控制句柄,可从其他线程暂停、恢复、停止或修改参数Source:音频源 trait,可以是文件、振荡器,也可以是你自定义的动态音源Effect:DSP 效果 trait,用于在缓冲区上处理立体声采样FileSource:文件音频源Oscillator:内置振荡器音源Adsr:ADSR 音量包络效果
这套 API 看起来不复杂,但刚好覆盖了游戏音频里最常见的一层:先把声音作为资源或信号创建出来,再交给引擎播放,之后通过句柄实时控制。
文件播放:从资源音频开始
AIRE 支持加载常见音频文件作为声音源。按照项目介绍,目标覆盖 WAV、OGG、FLAC 和 MP3,并支持对大型音频文件进行磁盘流式播放,这对背景音乐、长环境音、语音等资源很重要。
需要注意一个版本细节:我核对到的 aire 0.2.0 发布文档和 crates.io 源码里,FileSource 明确列出的格式是 WAV、OGG 和 FLAC,并且当前实现会把文件解码到内存中,如果文件采样率和设备采样率不同,会在加载阶段重采样。也就是说,MP3 和真正的磁盘流式播放更可能是 GitHub 主分支或后续版本里的进展,实际接入时建议以仓库当前 README、源码和发布版本为准。
即便只看 0.2.0,这个能力也已经能覆盖不少游戏场景。WAV 适合短音效,OGG/FLAC 适合压缩后的音乐或环境音。AIRE 会把单声道复制到左右声道,立体声则按交错采样读取;如果素材采样率和输出设备不一致,它会通过 rubato 做重采样,避免播放速度或音高出错。
实时控制:音量、声像、暂停、恢复、停止
交互式音频最重要的不是“开始播放”,而是播放之后还能不能稳定控制。
AIRE 的做法是:调用 Engine::add_sound 后拿到一个 SoundHandle,后续通过这个 handle 发送控制命令。比如:
let engine = aire::Engine::new()?;
let rate = engine.sample_rate();
let source = aire::FileSource::new("music.ogg", rate)?.looping();
let handle = engine.add_sound(aire::Sound::new(source, 0.0, 0.5, rate))?;
handle.set_volume(-6.0)?;
handle.set_pan(0.8)?;
handle.pause()?;
handle.resume()?;
handle.stop()?;
这里的音量使用分贝,0.0 表示 unity gain,-6.0 就是降低 6 dB。声像范围是 0.0 到 1.0,左声道到右声道,中间值 0.5 表示居中。
源码里还有一个细节值得注意:音量和声像变化会做平滑处理,暂停和停止也不是硬切,而是进入淡出状态。这样可以避免常见的 click/pop 爆音。对游戏来说,这种小处理很关键,因为音效触发和停止非常频繁,硬切很容易在耳机里变成刺耳的瞬态。
合成能力:不只播放采样
AIRE 内置了振荡器,这意味着它不只是播放已有音频文件,也可以直接合成声音。
Oscillator 支持六种波形:
- Sine
- Saw
- SawDown
- Triangle
- Square
- Pulse
这些波形不是简单的 naive waveform。源码中可以看到 saw、square、pulse 等波形使用了 PolyBLEP,triangle 使用了 PolyBLAMP 修正,目标是降低带限之外的混叠。对合成音效来说,这很实用。比如 UI beep、激光、提示音、低频脉冲、复古风格音效,都可以不依赖外部素材直接生成。
示例上也很简单:
let rate = engine.sample_rate();
let osc = aire::Oscillator::new(aire::Waveform::Saw, 220.0, rate)
.amplitude(-9.0)
.duration(300);
engine.add_sound(aire::Sound::new(osc, 0.0, 0.5, rate))?;
如果没有设置 duration,振荡器可以持续运行;设置 duration 后,则按毫秒控制播放时长。Pulse 还可以调整 pulse width,用于做更尖锐或更偏复古的声音。
ADSR:让音效有形状
只生成一个固定音量的波形还不够,真正像“声音”的东西通常需要包络。AIRE 内置了 ADSR envelope:
- Attack:从静音爬升到峰值
- Decay:从峰值下降到 sustain 音量
- Sustain:保持一段时间
- Release:逐渐释放到静音
这对合成音效很关键。同样一个方波,如果 attack 很短、release 很短,就像一个提示音;如果 attack 慢、release 长,就更像氛围音或能量充能声。
AIRE 的 Sound 支持效果链,Adsr 是一个 Effect。这也意味着开发者可以实现自己的效果,比如低通滤波、延迟、失真、压缩、混响前级,甚至游戏状态驱动的自定义 DSP。
线程模型:控制线程和音频线程分离
实时音频最怕阻塞。音频线程需要稳定地按设备要求填充 buffer,一旦卡住就会出现爆音、断裂或延迟。
AIRE 在结构上把控制侧和音频侧分开。应用线程调用 handle 方法时,不是直接改音频线程里的状态,而是把命令发送到一个有界队列里。音频回调每次运行时尝试接收命令,然后在混音器里应用:添加声音、暂停、恢复、停止、设置音量、设置声像。
这个模型有几个好处:
- 游戏逻辑线程可以安全地控制声音
- 音频线程不需要等待普通锁
- 命令队列满时能返回明确错误
- API 不要求调用方理解音频回调内部细节
这也是它比“简单播放库”更像引擎的地方。AIRE 关心的不只是声源,还关心声源如何在实时系统里被控制。
混音方式
AIRE 的 mixer 会维护一组正在播放的 Sound,每次填充输出 buffer 时:
- 清空输出缓冲区
- 逐个让声音源填充 scratch buffer
- 应用效果链、音量、声像和平滑状态
- 把声音累加到主输出
- 对输出做简单 clamp,限制在
-1.0..1.0 - 移除已经结束的声音
这是一种很朴素、可理解的游戏音频混音结构。它还不是 Wwise、FMOD 那种完整音频中间件,但对于小型 2D 游戏、工具、实验性互动应用,已经有一个清晰的基础。
后续方向:从播放声音到理解场景
作者提到的路线很有意思:AIRE 未来不只是“播放声音”,而是希望进一步理解运行环境。
第一步大概率会是 2D 空间音频。对 2D 游戏来说,这通常包括:
- 根据声源和监听者距离调整音量
- 根据左右相对位置调整 pan
- 支持衰减曲线,比如线性、平方反比、自定义曲线
- 支持最大听距和最小距离
- 支持跟随实体移动的声音
补齐这层之后,AIRE 就能从“你手动设置 pan 和 volume”升级为“你告诉它声源和玩家的位置,它自动算出听感”。
再往后,动态声学和混响会更有想象空间。比如室内外切换、洞穴混响、水下低通、墙体遮挡、远距离声音模糊、不同材质反射等。对 2D 游戏来说,不一定需要复杂的物理声学模拟,但只要能根据区域、遮挡和场景标签调整滤波与混响,就已经能明显提升沉浸感。
适合什么项目
AIRE 目前更适合这些场景:
- Rust 写的 2D 游戏
- 小型互动装置或工具
- 想自己掌控音频系统,而不是接入大型中间件
- 需要运行时控制音量、声像、暂停和停止
- 想用代码直接合成一部分音效
- 愿意接受早期项目 API 继续变化
如果你正在做大型商业游戏,需要成熟编辑器、事件系统、bank 管理、复杂路由、平台认证和美术音频工作流,Wwise/FMOD 仍然更合适。AIRE 的优势不是“大而全”,而是轻量、Rust 原生、抽象直接,并且从一开始就把实时控制放在设计中心。
简单总结
AIRE 值得关注的点,不在于它现在已经覆盖了所有音频能力,而在于它的方向很清楚:为交互式应用做一个可控、可扩展、实时友好的音频基础层。
它现在已经具备文件播放、循环、音量和声像控制、暂停恢复停止、振荡器合成、ADSR 包络、自定义 source/effect、音频线程命令通信等能力。后续如果能把 2D 空间音频、流式播放、更多格式和基础环境效果打磨稳定,就会成为 Rust 游戏生态里一个很实用的声音引擎选择。
项目地址:https://github.com/Breijen/aire
参考: