近年来,DOS游戏经历了一波显著的复兴,无论是B站还是小红书,DOS游戏都有着不少流量。得益于PC架构的兼容性,在较新的电脑上运行DOS游戏目前不仅有DOSBox这样的模拟器,也有像SBEMU和VSBHDA这样面向AC97/HDAudio声卡的DOS驱动程序,我曾经在《SBEMU与VSBHDA:集成声卡DOS配置指南》详细的写过它们的用法。

而今天,我会打开DOS声音系统的另一个领域:MIDI音源。

听说过,没听过:DOS玩家的MIDI之困

正如我在《SBEMU与VSBHDA:集成声卡DOS配置指南》中提到的那样,在DOS时代,PC音频的事实标准是声霸卡(SoundBlaster)兼容,而声霸卡兼容的三个核心功能,分别是Yamaha OPL2/3兼容的FM合成功能、数字音频回放功能和15针游戏摇杆/MIDI接口功能。但此处的MIDI接口,仅仅是提供了一个电脑程序与电子乐器/音源模块(sound module,中文通常称作“MIDI音源”)通信的渠道而已,而真正要听到MIDI音乐,则通常需要额外购买MIDI子卡或外置MIDI音源。

因此大多数老玩家记忆中DOS游戏的“MIDI音乐”,实际上是指由声霸卡上OPL2/3 FM合成器所产生的,虽然FM音乐已经和Commodore 64的SID音源一样成为历史记忆的一部分,包括近年来新出现的Pocket 386等便携DOS电脑也内置了OPL3 FM合成器,但仍然有不少玩家会像我一样好奇,当年的MIDI音乐究竟是什么样的?

老式电脑MIDI音源的可选项

时至今日,除非使用模拟器,在实体DOS电脑上听到MIDI音乐仍然是最困难的操作之一,大多数情况下,你的选项只有如下几种:

选项一:使用台式电脑+带MIDI接口的独立或板载声卡+外置MIDI音源,这个选项是此前较为可行的方法,因为即使是较为平价的CMI8738声卡也带15针MIDI接口,只要有合适的接口适配器就能连接到MIDIPLUS miniEngine这类较为平价的现代音源上,但难点在于适配器的制作,由于声卡上的DB15接口使用的是TTL信号,而MIDI接口使用的是电流环(current loop)信号,导致该适配器不能简单地使用导线自制,而必须要用到光耦合器在内的更多器件。

ES1868 AudioDrive Data Sheet给出的PC声卡转MIDI电路示意

选项二:使用带有MIDI子卡的老声卡,由于声霸卡早期的营销资料的误导,这些卡虽然往往被称为“波表子卡”,但实际上是基于采样而非波表的合成器。由于它们当年的出货量就不多,因此被物以稀为贵的炒家们炒的很贵,完全没有性价比。

选项三:使用带有ISA插槽的台式电脑+SoundBlaster AWE32声卡+AWEUTIL驱动,但具体兼容情况各异。而且AWE32声卡的价格也已经被明显炒高。

选项四:使用SoftMPU+串口线+Roland SC-7/SC-55mkII/SC-55ST/SC-88或Yamaha TG100/TG300/MU等支持串口连接的老式音源,这种方案线路比较容易自制(参考SoftMPU Wiki),但支持串口直连的音源本身型号少,并且全部为早已停产的90年代型号,能不能买到、能以什么价格买到都很成问题。

选项五:使用SoftMPU+MPU-232串口MIDI适配器+普通MIDI音源,这种方式是目前笔记本电脑连接硬件MIDI音源较为容易的方式,不过MPU-232适配器本身比较贵,要27欧元,而且需要从国外发货,可能涉及到额外的运费。

SoftMPU未能解决的问题

复古游戏爱好者们一直都没有放弃在真实DOS游戏中重现MIDI音乐的努力,2013年出现了可以模拟MPU-401 MIDI协处理器的SoftMPU,并在第二年加入了对串口MIDI模块的支持。因此上面提到的选项四,其实是2010年代才出现的新事物,而选项五中能够让更多音源兼容串口的MPU-232则出现在2021年。但即使如此,由于MPU-232没有公开设计而且唯一的供应商在国外,SoftMPU使用的门槛仍然不低。

为什么实现串口 MIDI 如此困难?一方面是波特率的不匹配,标准的MIDI协议波特率是固定的31250bps(正好是1Mhz的32分之一),而串口PC UART的波特率必须是300的倍数,从1200、9600、38400一路到115200,却没有31250的选项。而在物理层上,则会遇到和选项一同样的问题,串口使用±12V电压驱动,而MIDI使用5V电流环,除非是像90年代那些老音源一样经过特殊设计,直接连接很容易损坏设备。

165元的答案:矽递XIAO MIDI合成器

而古董电脑室的宗旨之一就是让更多的玩家以合理的价格体验复古计算,为了让更多玩家在真实DOS电脑(包括Pocket 386)上体验硬件MIDI音源,我基于矽递XIAO MIDI合成器制作了一款最便宜的串口MIDI音源。

XIAO MIDI合成器淘宝售价只要165元

矽递XIAO MIDI合成器原本是为创客DIY市场设计的一款音乐模块,组合了XIAO ESP32-C3单片机和Dream SAM2695声音合成芯片,SAM2695是2014年新推出的,兼容General MIDI标准的合成器芯片,它被使用在包括MIDIPLUS miniEngine这样的平价独立MIDI音源上,也被Serdaco Dreamblaster S2、Lotharek Sam-Wave等海外开发的MIDI子卡所使用,其声音质量被DOS Days网站列入“最佳质量”一组。

而兼容串口的秘密就藏在ESP32-C3单片机里:如果我们以PC常见的波特率从SoftMPU接收MIDI指令,再以31250bps的MIDI标准波特率发送给声音合成芯片,不就可以得到一只串口MIDI音源吗?

DIYElectroMusic.com去年已经做了一些有趣的实验,但他的工作主要是将USB串口传来的MIDI信号输出到外部乐器,而我做的工作则反过来,是要在单片机上额外打开一个实体串口,再将MIDI信号传输给内置SAM2695芯片。

好在XIAO ESP32-C3提供成熟的Arduino开发环境,我的Arduino Sketch在diyelectromusic的版本上稍作改动,只要单个文件刷入单片机即可:

我的Arduino Sketch:https://gist.github.com/pengan1987/24ca07184eaa83e06faa8df79a5a9eb4
XIAO MIDI 合成器入门指南:https://wiki.seeedstudio.com/cn/xiao_midi_synthesizer/
Seeed Studio XIAO ESP32C3 入门指南:https://wiki.seeedstudio.com/cn/XIAO_ESP32C3_Getting_Started/

我的Sketch使用D9、D10针脚作为TTL串口的接收(RX)和发送(RX)针脚,为了和老式电脑的RS232串口通信,还需要一个RS232-TTL转换器,在淘宝上通常只需要几块钱。

连接好的合成器模块如图,XIAO MIDI合成器有内置喇叭,也可以通过3.5mm接口外接音箱,但自带的外壳可能会导致部分音频线无法完全插进音频接口,只有一个声道出声的情况,遇到这种情况可以拆掉外壳再试一下。

连接到然后就可以将合成器模块连接到PC串口了,而在使用的时候,不要忘了还需要通过USB给合成器模块供电。

在SoftMPU里将COM1串口映射到原本MPU-401的330端口

softmpu /mpu:330 /output:com1

之后就可以试验各种DOS游戏了!我自己测试了《Silpheed》、《沙丘II》、《波斯王子》都可以正常演奏音乐。

由于代码的限制,SoftMPU对32位增强模式游戏的兼容性不佳,比如《Doom》就通常要打过补丁的版本配合SER38400.COM程序,或者使用SBEMU的/mcom参数将MPU-401重定向到串口,可以参考

Vogons上Cloudschatze关于MPU-232的讨论:https://www.vogons.org/viewtopic.php?t=81178&start=20

VCFED论坛上Cloudschatze提供的串口MIDI游戏补丁: https://forum.vcfed.org/index.php?threads/a-trick-up-its-sleeve-midi-with-the-tandy-pssj.71478/

Vogons上关于SBEMU串口MPU-401支持的帖子:https://www.vogons.org/viewtopic.php?p=1222845

更改串口波特率,支持更多老式软硬件

虽然SoftMPU使用固定的38400bps和MIDI模块通信已经能够支持大部分DOS程序,但偶尔也会遇到部分原生支持串口MIDI的程序使用其他波特率的情况,比如DOS下的MIDI播放软件DOSMid,就使用MODE命令指定的串口速率,而DOS自带的MODE命令最高的波特率是19200bps,例如

MODE COM1:19200,N,8,1
dosmid/com1 music.mid

但由于波特率不对应,此时DOSMid程序就无法直接和XIAO MIDI合成器通信了,一个办法是使用SER38400.COM程序将串口的通信速率调整至38400bps,另一个办法则可以更改Arduino Sketch中Serial1的通信速率来让XIAO MIDI合成器接受指定的波特率,例如

// MySerial1 is the TTL serial on pin 9/10
// Change MySerial1 baud to 19200 for DOSMid
// MySerial1.begin(38400, SERIAL_8N1, 9, 10);
MySerial1.begin(19200, SERIAL_8N1, 9, 10);

由于波特率可调,XIAO MIDI合成器可以和你想到的几乎所有老式电脑或者单片机通信。

它还可以兼容现代电脑!

这个项目其实很大一部分衍生自基于Arduino制作各类MIDI的实践,因此它也兼容Hairless MIDI<->Serial Bridge,可以直接使用现代电脑通过XIAO ESP32C3的USB串口与SAM2695合成器芯片通信,而让XIAO MIDI合成器成为一个同样适用于现代电脑的USB硬件音源。