OPL2LPT: an AdLib sound card for the parallel port
Vincent Bernat
The AdLib sound card[1] was the first popular sound card for IBM PC—before that, we were pampered by the sound of the PC speaker. Connected to an 8-bit ISA slot, it is powered by a Yamaha YM3812[2] chip, also known as OPL2. This chip can drive 9 sound channels whose characteristics can be fine-tuned through 244 write-only registers.

I had one but I am unable to locate it anymore. Models on eBay are quite rare and expensive. It is possible to build one yourself (either Sergey’s one[4] or this faithful reproduction[5]). However, you still need an ISA port. The limitless imagination of some hackers can still help here. For example, you can combine Sergey’s Xi 8088 processor board[6], with his ISA 8-bit backplane[7], his Super VGA card[8], and his XT-CF-Lite card[9] to get your very own modernish IBM PC compatible. Alternatively, you can look at the AdLib sound card on a parallel port[10] from Raphaël Assénat.
The OPL2LPT sound card#
Recently, the 8-Bit Guy[11] released a video about an AdLib sound card for the parallel port[12], the OPL2LPT[13]. While current motherboards don’t have a parallel port anymore, it’s easy to add a PCI-Express one[14]. I bought a pre-soldered OPL2LPT and a few days later, it was in my milk box:

Update (2018-03)
You can also buy a 3D-printed enclosure for the OPL2LPT. After
writing this article, I have been offered one:

Update (2018-07)
The OPL3LPT[15] is now available. It features a similar design but with an OPL3 chip.
The expected mode of operation for such a device is to plug it into an ISA parallel port (accessible through I/O port 0x378), load a DOS driver[16] to intercept calls to AdLib’s address, and run some AdLib-compatible game. While correctly supported by Linux, the PCI-Express parallel port doesn’t operate like an ISA one. QEMU[17] comes with a parallel port emulation but, due to timing issues[18], cannot correctly drive the OPL2LPT. However, VirtualBox[19] emulation is good enough.1
On Linux, the OPL2LPT can be programmed almost like an actual AdLib[20]. The following code writes a value to a register:
static void lpt_write(uint8_t data, uint8_t ctrl) {
ieee1284_write_data(port, data);
ieee1284_write_control(port, (ctrl | C1284_NINIT) ^ C1284_INVERTED);
ieee1284_write_control(port, ctrl ^ C1284_INVERTED);
ieee1284_write_control(port, (ctrl | C1284_NINIT) ^ C1284_INVERTED);
}
void opl_write(uint8_t reg, uint8_t value) {
lpt_write(reg, C1284_NSELECTIN | C1284_NSTROBE);
usleep(4); // 3.3 microseconds
lpt_write(value, C1284_NSELECTIN);
usleep(23);
}
To “natively” use the OPL2LPT, I have modified the following applications:
- ScummVM[21], an emulator for classic point-and-click adventure games, including many LucasArts games—patch[22]2
- QEMU[17], a quick generic emulator—patch[23] with a minimal emulation for timers and hard-coded sleep delays 🙄
- DOSBox[24], an x86 emulator bundled with DOS—patch[25] with a complete emulation for timers and a dedicated working thread3
You can compare the results in the following video, with the introduction of Indiana Jones and the Last Crusade[26], released in 1989:4
- 0:00, DOSBox with an emulated PC speaker
- 0:58, DOSBox with an emulated AdLib
- 1:51, VirtualBox with the OPL2LPT (on an emulated parallel port)
- 2:42, patched ScummVM with the OPL2LPT (native)
- 3:33, patched QEMU with the OPL2LPT (native)
- 4:24, patched DOSBox with the OPL2LPT (native)
- 5:17, patched DOSBox with an improved OPL3 emulator (Nuked OPL3[27])
- 6:10, ScummVM with the CD track (FM Towns[28] version)
I let you judge how good each option is! There are two ways to buy an
OPL2LPT OPL3LPT: in Europe, from Serdashop[15]
or in North America, from The 8-Bit Guy[30].
Addendum#
Indiana Jones and the Fate of Atlantis#
Here is another video featuring Indiana Jones and the Fate of Atlantis[31], released in 1992, running in DOSBox with the OPL2LPT. It’s the second game using the iMUSE[32] sound system: music is synchronized with actions and transitions are done seamlessly. Quite a feat at the time!
Monkey Island 2#
The first game featuring iMUSE is Monkey Island 2[33], released in 1991. The video below displays the first minutes of the game, running in DOSBox with the OPL2LPT.
Notably, at 5:33, when Guybrush is in Woodtick, a small town on Scabb Island, the music plays around a variation of a basic theme with a different instrument for each place without any interruption.
How the videos were recorded#
With a VGA adapter, many games use Mode 13h[34], a 256-color mode with a 320×200 resolution. On a 4:3 display, this mode doesn’t feature square pixels: they are stretched vertically by a factor of 1.2.
The above videos were recorded with FFmpeg[35] (and edited with Blender[36]). It packs a lot of useful filters[37] making it easy to automate video capture. Here is an example:
FONT="font=Monkey Island 1991 refined:
fontcolor=OrangeRed:
fontsize=16:
x=w-text_w-10"
ffmpeg -y \
-thread_queue_size 64 \
-f x11grab -draw_mouse 0 -r 30 -s 640x400 -i :0+844,102 \
-thread_queue_size 64 \
-f pulse -ac 1 -i default \
-filter_complex "[0:v]pad=854:400:0:0,
drawtext=${FONT}:y= 10:text=Indiana Jones 3,
drawtext=${FONT}:y= 34:text=Intro,
drawtext=${FONT}:y=100:text=DOSBox,
drawtext=${FONT}:y=124:text=VGA,
drawtext=${FONT}:y=148:text=PC speaker,
scale=854:480:flags=neighbor[game];
[1:a]volumedetect;
[1:a]showwaves=s=214x100:colors=OrangeRed:scale=lin[waves];
[1:a]showcqt=s=214x100[spectrum];
[waves][spectrum]vstack[vis];
[game][vis]overlay=x=640:y=280" \
-pix_fmt yuv420p -c:v libx264 -qp 0 -preset ultrafast \
indy3-dosbox-pcspkr.mkv
The interesting part is the filter argument. The input video
is padded[38] from 640×400 to 854×400 as a first step to a
16:9 aspect ratio.5 Using The Secret Font of Monkey
Island[39], some text[40] is added to the right of
the video. The result is then scaled[41] to 854×480 to get
the final aspect ratio while stretching pixels to the expected 1.2
factor. The video up to this point is sent to a stream named
game. As a second step, from the input audio, we build two
visualizations: a waveform[42] and a
spectrum[43]. They are stacked
vertically[44] and the result is a stream named vis. The
last step is to overlay[45] the visualization stream
over the gameplay stream.
- https://en.wikipedia.org/wiki/Ad_Lib,_Inc.#AdLib_Music_Synthesizer_Card_(1987)
- https://en.wikipedia.org/wiki/Yamaha_YM3812
- https://monotech.fwscart.com/AdLib_OPL2_Sound_Card/p6083514_19478748.aspx
- https://github.com/skiselev/isa-opl2
- https://tubetime.us/index.php/2016/07/22/a-reproduction-adlib-sound-card/
- https://github.com/skiselev/xi_8088
- https://github.com/skiselev/isa8_backplane
- https://github.com/skiselev/isa-super-vga
- https://github.com/skiselev/xt-cf-lite-v4
- https://www.raphnet.net/electronique/adlib/adlib_en.php
- https://www.the8bitguy.com/
- https://www.youtube.com/watch?v=z3DU2mNBa6M
- https://serdashop.com/products/opl2lpt
- https://www.amazon.fr/dp/B00YE0QATW/
- https://serdashop.com/products/opl3lpt
- https://github.com/pdewacht/adlipt/tree/master/adlipt
- https://www.qemu.org/
- https://github.com/pdewacht/adlipt/issues/3
- https://www.virtualbox.org/
- http://shipbrook.net/jeff/sb.html
- https://www.scummvm.org/
- https://github.com/scummvm/scummvm/pull/1137
- https://patchwork.ozlabs.org/project/qemu-devel/patch/20180218144021.11641-1-vincent@bernat.im/
- https://www.dosbox.com/
- https://github.com/vincentbernat/dosbox/compare/feature/opl2lpt
- https://en.wikipedia.org/wiki/Indiana_Jones_and_the_Last_Crusade:_The_Graphic_Adventure
- https://sourceforge.net/p/dosbox/patches/270/
- https://en.wikipedia.org/wiki/FM_Towns
- https://en.wikipedia.org/wiki/Minitel
- https://web.archive.org/web/2018/https://www.the8bitguy.com/product/opl3lpt-ad-lib-compatible-parallel-sound-card/
- https://en.wikipedia.org/wiki/Indiana_jones_and_the_fate_of_atlantis
- https://en.wikipedia.org/wiki/IMUSE
- https://en.wikipedia.org/wiki/Monkey_Island_2:_LeChuck%27s_Revenge
- https://en.wikipedia.org/wiki/Mode_13h
- https://ffmpeg.org/
- https://www.blender.org/
- https://ffmpeg.org/ffmpeg-filters.html
- https://ffmpeg.org/ffmpeg-filters.html#pad-1
- https://www.ptless.org/sfomi/
- https://ffmpeg.org/ffmpeg-filters.html#drawtext
- https://ffmpeg.org/ffmpeg-filters.html#scale
- https://ffmpeg.org/ffmpeg-filters.html#showwaves
- https://ffmpeg.org/ffmpeg-filters.html#showcqt
- https://ffmpeg.org/ffmpeg-filters.html#vstack
- https://ffmpeg.org/ffmpeg-filters.html#overlay
- https://stackoverflow.com/questions/30789367/ffmpeg-how-to-convert-vertical-video-with-black-sides-to-video-169-with-blur