Playing MIDI files to OPL2/3, EMU8000, or EMU10K1 on Linux/ALSA

Last modified: 2024-01-21 14:01

This page describes how to play MIDI (.MID) files on Linux/ALSA to certain sound card synths that do not have a MIDI interpreter.  Comparable results can be obtained with less trouble using a softsynth.

In sections below, the tags OPL2/3 EMU8000 EMU10K1 indicate to which of the synths the information applies.

Software needed

OPL2/3 The program sbiload from package alsa-tools.  It is bundled under the seq subdirectory, has its own configure script and can be built separately.

EMU8000 EMU10K1 The program asfxload from package awesfx.  (asfxload is for ALSA; sfxload is for OSS.)

OPL2/3 EMU8000 EMU10K1 The programs aplaymidi and alsamixer from package alsa-utils.

Kernel patches

The following two kernel bugs can result in avoidable "sfxload: no memory left" errors.

EMU8000 Miscount of soundfont memory

The EMU8000 driver in the Linux kernel for a long time had a bug that reduced the amount of soundfont memory by 512 KiB.  This bug prevented loading the nominally 4 MiB E-mu soundfont provided by Creative, 4GMGSMT.SF2 (4174814 B), into the on-board RAM of an AWE64 Gold.  The problem was corrected in kernel version 3.7.

EMU10K1 DMA zone addressing conflict

As described in detail here, the 32-bit PCI DMA zone that the kernel provides to the EMU10K1 driver is at a location that the EMU10K1 hardware cannot address.  As a result, the driver falls back to the 16 MiB ISA memory region, which is not always a problem but it does fill up.

The linked article includes a kernel patch to relocate the 32-bit PCI DMA zone as a workaround.  The relevant code has changed in more recent kernels so that the patch no longer applies.  Following is an equivalent patch for more recent kernels.

diff -ur linux-5.10.12/arch/x86/include/asm/dma.h linux-5.10.12-sblive/arch/x86/include/asm/dma.h
--- linux-5.10.12/arch/x86/include/asm/dma.h	2021-01-30 07:55:20.000000000 -0500
+++ linux-5.10.12-sblive/arch/x86/include/asm/dma.h	2021-01-31 10:35:41.265073281 -0500
@@ -74,7 +74,7 @@
 #define MAX_DMA_PFN   ((16UL * 1024 * 1024) >> PAGE_SHIFT)
 
 /* 4GB broken PCI/AGP hardware bus master zone */
-#define MAX_DMA32_PFN (1UL << (32 - PAGE_SHIFT))
+#define MAX_DMA32_PFN (1UL << (31 - PAGE_SHIFT))
 
 #ifdef CONFIG_X86_32
 /* The maximum address that we can perform a DMA transfer to on this platform */

Make sure kernel modules are loaded

OPL2/3 modprobe snd-opl3-synth

EMU8000 modprobe snd-emu8000-synth

EMU10K1 modprobe snd-emu10k1-synth

Make sure volume is up

In alsamixer, make sure the Synth volume is unmuted and set to 100 and that the Master volume is at some audible level.

Load a sound font

OPL2/3

Running sbiload with no options should initialize the sound correctly.  Do sbiload -v 1 to see evidence that it has loaded std.o3 and drums.o3 for OPL3 or std.sb and drums.sb for OPL2.

bash-4.1$ sbiload -v 1
Loading from /usr/local/sbiload-1.0.25/share/std.o3
Loaded instrument 000, bank 000: Acoustic Grand
Loaded instrument 001, bank 000: Bright Acoustic
...
Loading from /usr/local/sbiload-1.0.25/share/drums.o3
000: wrong instrument key!
001: wrong instrument key!
...
Loaded instrument 035, bank 128: Ac Bass Drum
Loaded instrument 036, bank 128: Bass Drum 1
...

You can argue pedantically that this is not really loading a sound font since it is FM synthesis and there are no samples.  Whatever, you have to load the thing before it will work.

EMU8000 EMU10K1

Asfxload is used to load an .SF2 or .SBK soundfont file.  For ISA cards the soundfont goes in on-board RAM, while for PCI cards it goes in the 32-bit PCI DMA zone of main memory.

The first attempt to load a soundfont often fails this way:

bash-4.3$ asfxload -i -M 8MBGMSFX.SF2
No Emux synth hwdep device is found

The problem magically goes away if you first enumerate the devices with aplaymidi:

bash-4.3$ aplaymidi -l
 Port    Client name                      Port name
 24:0    SB Live! 5.1                     EMU10K1 MPU-401 (UART)
 25:0    Emu10k1 WaveTable                Emu10k1 Port 0
 25:1    Emu10k1 WaveTable                Emu10k1 Port 1
 25:2    Emu10k1 WaveTable                Emu10k1 Port 2
 25:3    Emu10k1 WaveTable                Emu10k1 Port 3
bash-4.3$ asfxload -i -M 8MBGMSFX.SF2
DRAM memory left = 123833 kB

Attempts to load sound fonts larger than the available RAM or the apparent hard limit of 128 MiB (131072 KiB) fail with "sfxload: no memory left."

EMU8000 Using the ROM soundfont

AWE cards come with a 1 MiB sample ROM.  To use it, you have to asfxload SYNTHGM.SBK (provided in SB16/SFBANK of an installation of Creative's DOS drivers).  It doesn't consume any RAM.  The resulting sound is cheesier than with the larger soundfonts.

bash-4.3$ asfxload -i -M SYNTHGM.SBK

On EMU10K1 cards, which lack the sample ROM, the command will succeed but no music will play.

Play that funky music

Play a .MID file to the OPL2/3 FM port or any of the WaveTable ports listed by aplaymidi -l.

OPL2/3 Sound Blaster 16 with only an OPL3.
bash-4.3$ aplaymidi -l
 Port    Client name                      Port name
 16:0    Sound Blaster 16                 Sound Blaster 16 MIDI
 17:0    OPL3 FM synth                    OPL3 FM Port
bash-4.3$ aplaymidi -p 17:0 I_Got_You.mid

Don't get your hopes up.  It sounds like this.

OPL2/3 EMU8000 AWE with both an EMU8000 synth and an OPL3 clone.
bash-4.3$ aplaymidi -l
 Port    Client name                      Port name
 16:0    Sound Blaster 16                 Sound Blaster 16 MIDI
 17:0    Emu8000 WaveTable                Emu8000 Port 0
 17:1    Emu8000 WaveTable                Emu8000 Port 1
 17:2    Emu8000 WaveTable                Emu8000 Port 2
 17:3    Emu8000 WaveTable                Emu8000 Port 3
 18:0    OPL3 FM synth                    OPL3 FM Port
bash-4.3$ aplaymidi -p 17:0 I_Got_You.mid
bash-4.3$ aplaymidi -p 18:0 I_Got_You.mid
EMU10K1 Live! with only an EMU10K1 synth.  (OPL3 in DOS and Windows was emulated, very poorly, by the drivers.)
bash-4.3$ aplaymidi -l
 Port    Client name                      Port name
 24:0    SB Live! 5.1                     EMU10K1 MPU-401 (UART)
 25:0    Emu10k1 WaveTable                Emu10k1 Port 0
 25:1    Emu10k1 WaveTable                Emu10k1 Port 1
 25:2    Emu10k1 WaveTable                Emu10k1 Port 2
 25:3    Emu10k1 WaveTable                Emu10k1 Port 3
bash-4.3$ aplaymidi -p 25:0 I_Got_You.mid

Other resources


ISA sound cards
PCI sound cards
Playing MIDI files to OPL3, GUS, EMU8000, ES137x, or EMU10K1 on baremetal DOS
KB
Home