Amiga 上的零 CPU Atari 音乐仿真
Amiga 上的零 CPU Atari 音乐仿真
在 Amiga demo scene 中追求世界纪录往往是一场优化之战。当开发者 Leonard (z303) 发现他的 'sin-dots' 纪录被 Amiga 传奇人物 Hannibal 打破时,挑战不仅仅在于绘制更多的点——而是在于如何以一种极具风格化的方式来实现。为了回应关于他是“Atari 程序员”的调侃,Leonard 着手在 Amiga 上播放 Atari 音乐,同时将硬件推向新的 sin-dots 纪录。
然而,技术壁垒挡住了去路:仿真 Atari YM2149 音频芯片是极其消耗 CPU 的。准确还原现代 Atari 效果——例如 SID voices 和 Digidrums——可能会消耗 Motorola 68000 高达 50% 的帧时间,导致没有余力进行打破图形纪录所需的繁重计算。
解决方案需要一种范式转移:将仿真从 CPU 转移到 Amiga 的定制硬件上。
硬件差异:YM2149 vs. PAULA
为了实现零 CPU 播放,Leonard 必须弥合两种截然不同的音频哲学之间的鸿沟:
- YM2149 (Atari ST): 一个相对简单的芯片,能够生成三个方波声部,一个伪随机噪声生成器,以及一个基础的硬件音量包络。
- PAULA (Amiga): 一个复杂的 PCM 采样播放芯片。它没有对方波或噪声的原生支持;相反,它以可变速率和音量从内存中播放四个独立的 8-bit 有符号 PCM 采样。
第一次尝试:简单的方波
最初的方法非常直接:将单个周期的方波存储为 PCM 采样并使用 PAULA 进行循环播放。为了避免完整音乐驱动程序的开销,使用了一个 PC 工具来为每一帧 (50 Hz) 预计算 PAULA 状态,将 Atari 的周期和音量值转换为 PAULA 兼容的值。
虽然这对于像 Buggy Boy 这样的早期 Atari 游戏有效,但结果却很“平淡”。它缺乏 80 年代后期 Atari 配乐中特有的那种激进、扫频的音色,特别是像 Jochen Hippel (MadMax) 这样的音乐家所创作的音色。
解码“MadMax Buzzer"
高级 Atari 音乐的丰富音色来自于对 YM2149 音量包络的巧妙误用。音乐家们并没有使用包络来调制音量(这是其设计初衷),而是将包络 作为 声源。
通过将包络频率设置得足够高以达到可听范围,并将其与一个略微失谐的方波结合,就可以创建一个复杂的、移动的波形。当方波信号为 0 时,输出为 0;当它为 1 时,输出为包络的三角形形状的当前值。这创造了标志性的“buzzer”效果。
使用 PAULA 仿真调制
为了在 Amiga 上复制这种效果,Leonard 探索了 PAULA 芯片的一个冷门功能: “attached” 声部模式。在这种模式下,一个 PAULA 声部可以调制另一个声部的周期或音量。
由于 YM2149 有三个声部,而 PAULA 有四个,计划是使用三个声部用于方波,第四个作为音量调制器。然而,第一个原型失败了。通过使用 Audacity 调试波形,Leonard 发现调制器包络过于粗糙。因为 attached 声部模式每两个输出采样点之间仅提供一个音量值,所以包络平滑的三角形形状因低分辨率的“阶梯”而丢失了。
“灵光一现”的时刻
突破来自于调制器和采样点的角色反转。Leonard 没有使用低分辨率的调制器来创建三角形包络,而是使用高分辨率的 PCM 采样来表示三角形波,并将低分辨率的调制器用于方波。
因为方波只在两个状态(开启和关闭)之间切换,所以它不需要高分辨率。这种反转成功地以高保真度复制了 MadMax buzzer 效果。
实现真正的零 CPU 负载
即使使用了优化的 PAULA 设置,每帧更新寄存器仍然会消耗一些 CPU 周期。为了达到绝对零,Leonard 求助于了 COPPER,Amiga 的专用协处理器。
COPPER 可以向任何定制芯片寄存器写入立即数,并等待特定的屏幕位置,同时与 68000 CPU 并行运行。通过预生成一系列自链式 COPPER 列表——每一帧对应一个列表——音乐播放完全由硬件处理。
结果
通过将音乐仿真完全卸载到 PAULA 和 COPPER 芯片上,Motorola 68000 被完全释放出来专注于图形。这使得 Leonard 不仅能播放复杂的 Atari 音乐,而且还打破了之前的 sin-dots 纪录,将点数从 6,682 增加到了 7,210 dots。
这个项目是硬件利用的典范,证明了系统最强大的功能往往可以通过以设计者从未预想的方式使用其组件来实现。