play midi on linux
playing midi on windows is easy; windows has a built-in synth: microsoft gs wavetable synth, so you can play a midi file by opening it with windows media player; it often sounds garbage, but at least you can hear something; likewise, you can plug in a midi keyboard and start a foolproof e-piano software, bam, your music is there;
the same job is more complicated on linux; you need to understand a few concepts and combine several programs to turn midi into sound;
linux sound system
i believe you can google a few good articles about the linux sound system; but here i just want to keep things at their simplest: alsa and fluidsynth;
alsa
alsa stands for advanced linux sound architecture; it provides linux sound card drivers and an api to use them; therefore, an application can make sound using alsa library; one can think of alsa as the root of all sounds on linux;
fluidsynth
with alsa, playing audio file is a matter of reading data from the file and sending them to alsa, which will then drive the sound card; but a midi file does not contain audio data; as you can imagine, we need a program to convert midi data into audio data: this is called a synth;
a widely-used synth on linux is fluidsynth; it has a gui named qsynth;
play a midi file
with alsa and fluidsynth, we can play a midi file; if you dont have a midi file
at hand, freemidi is a good place to get one; wlog, lets name it a.mid
;
to play this file, run:
$ fluidsynth -a alsa FluidR3_GM.sf2 a.mid
FluidR3_GM.sf2
is a soundfont file; a soundfont is basically a bank of sounds
arranged by midi notes; this specific soundfont comes from fluidsynth itself; if
you dont like those sounds, you can search online and try another one;
play a midi keyboard: fluidsynth
we can also play a midi keyboard with alsa and fluidsynth; now we need to run fluidsynth in server mode and route midi data from keyboard to it;
first, we find the address of the midi keyboard using alsa utility amidi
:
$ amidi -l
Dir Device Name
IO hw:1,0,0 WTF-MIDI-Keyboard
second, we start fluidsynth server with the midi keyboard device address:
$ fluidsynth -s -a alsa -m alsa_raw -o midi.alsa.device=hw:1,0,0 FluidR3_GM.sf2
play a midi keyboard: qsynth
we can do the same using qsynth, a gui front-end of fluidsynth;
-
click
Setup...
; -
change settings:
-
click
Restart
to apply changes;
if playing midi file and midi keyboard are all you want, you can stop reading now; below we will cover some additional topics;
alsa sequencer
in the above example, we were using alsa_raw
as the midi driver to get input
from the midi keyboard; we need to specify the keyboard address when starting
the synth so that it knows where to fetch midi data; this static configuration
is inflexible: what if we have multiple midi keyboards? what if midi keyboards
come and go?
alsa sequencer comes to solve this problem; it can send midi events between clients; this helps build a midi patch-bay; it features a subscription model so that multiple clients can send data to the same application at the same time, and the routing can be changed dynamically;
here is an example of playing midi keyboard using alsa sequencer:
-
start fluidsynth in server mode, using midi driver
alsa_seq
:$ fluidsynth -s -a alsa -m alsa_seq FluidR3_GM.sf2
-
find the port number of the synth:
$ aconnect -o client 128: 'FLUID Synth (12345)' [type=user,pid=12345] 0 'Synth input port (12345:0)'
-
find the port number of the midi keyboard:
$ aconnect -i client 20: 'WTF-MIDI-Keyboard' [type=kernel,card=1] 0 'WTF-MIDI-Keyboard MIDI 1'
-
connect midi keyboard (sender) to synth (receiver):
$ aconnect 20:0 128:0
if you have multiple midi keyboards you can connect them all to the same synth; for example:
$ aconnect 21:0 128:0 $ aconnect 22:0 128:0 $ aconnect 23:0 128:0
-
the midi keyboard should work now;
-
to check connected pairs:
$ aconnect -l
to disconnect a pair:
$ aconnect -d 20:0 128:0
as you can see, alsa sequencer supports dynamic configuration very well; in the above example we were routing data from a midi keyboard to a synth, but we can route data from any sender to any receiver, such as between two applications;
here are examples of playing midi file using alsa sequencer:
-
to play a midi file:
$ aplaymidi -p 128:0 a.mid
-
to record a midi file:
$ arecordmidi -p 20:0 a.mid
jack
many linux sound articles will mention jack: what is it?
jack is a sound server providing real-time, low-latency connections for audio and midi data between applications that support its api; it can use alsa as the back-end for hardware communication, and therefore sits at a higher level than alsa in the linux audio stack;
since jack can route both audio and midi data, there are jack-audio and jack-midi; jack-midi and alsa sequencer do similar jobs, but jack-midi has better timing and can often be used as replacement for alsa sequencer;
our jack example is still about playing a midi keyboard:
-
start jack:
$ jackd -d alsa -r 44100 -p 128 -X raw
-r
sets sample rate;-p
sets period;-X
sets which alsa midi system to provide access to; it has 3 options:-
none:
this is the default option when you dont add
-X
in the command line; in this case jack doesnt use alsa midi devices; this means you cant connect to physical midi ports and cant route data to or from them;since we want to read midi data from keyboard, we cant use this option;
-
raw:
jack converts raw alsa midi devices into jack midi ports; this often means jack exclusively owns these midi devices, and you cannot connect to them from other applications;
-
seq:
jack converts alsa sequencer ports into jack midi ports; the alsa sequencer ports are still usable as well as the jack midi ports;
in short, we recommend using
-X raw
, and will explain the difference between-X raw
and-X seq
in following examples; -
-
start fluidsynth using jack for both midi and audio:
$ fluidsynth -s -a jack -m jack -j FluidR3_GM.sf2
-a
sets audio driver;-m
sets midi driver;-j
attempts to connect jack outputs to physical ports, so we dont have to do it manually; -
find jack midi ports that need to be connected:
we use
jack_lsp
to list jack ports, with aliases and properties:$ jack_lsp -Ap ... system:midi_capture_2 alsa_pcm:WTF-MIDI-Keyboard/midi_playback_1 WTF-MIDI-Keyboard:midi/playback_1 properties: output,physical,terminal, system:midi_playback_2 alsa_pcm:WTF-MIDI-Keyboard/midi_capture_1 WTF-MIDI-Keyboard:midi/capture_1 properties: input,physical,terminal, ... fluidsynth:left properties: output, fluidsynth:right properties: output, fluidsynth:midi_00 properties: input,terminal, ...
from this list, it is clear that the pair to connect is:
(system:midi_capture_2, fluidsynth:midi_00)
-
connect sender to receiver:
$ jack_connect system:midi_capture_2 fluidsynth:midi_00
this completes the steps and our keyboard should work now;
raw
vs seq
to show the difference between -X raw
and -X seq
, we use this script to run
a comparison:
$ jackd -d alsa -r 44100 -p 128 -X [raw|seq]
$ fluidsynth -s -a jack -m alsa_seq -j FluidR3_GM.sf2
this script starts a fluidsynth instance exposing alsa sequencer midi ports; we then try to connect our keyboard to this fluidsynth instance, using either jack ports or alsa sequencer ports (port names and numbers may vary);
-
case
raw
:we cannot connect using jack ports, because the fluidsynth doesnt have an input jack port:
-
the fluidsynth is using
alsa_seq
driver, which creates alsa sequencer ports, not jack ports; -
jack with
-X raw
creates jack ports for physical alsa midi devices, not alsa sequencer ports;
we can only try to connect using alsa sequencer ports:
$ aconnect 20:0 128:0 Connection failed (Resource temporarily unavailable)
this is because jack with
-X raw
(exclusively) grabs the physical alsa midi devices, making them unavailable to other connections; -
-
case
seq
:connection using jack ports works:
$ jack_connect system:midi_capture_2 system:midi_playback_4
because jack creates jack ports for fluidsynth mapped to its alsa sequencer ports;
connection using alsa sequencer ports also works:
$ aconnect 20:0 129:0
because the fluidsynth alsa sequencer ports are still working there;
question: if -X seq
works when -X raw
doesnt, why is -X raw
recommended?
answer: because the jack midi developers have a dream where it is the normal case for jack to exclusively control the sound system; in general, it is recommended to grant exclusive access to the audio system to one program, minimizing interference from other similar programs; alsa sequencer is one of those; another example is pulseaudio; pulseaudio is actually not bad, but is not designed for low latency audio; in fact we recommend you kill pulseaudio while running jack, but jack seems to be auto suspending pulseaudio already;
qjackctl
jack has a gui front-end qjackctl, which is able to control jack server and manage connections; it features a graphical patch-bay that allows easy rewire;
we recommend install qjackctl-0.6.0
or above; there is a subtle client name
bug in qjackctl-0.5.5
that can make graphical wiring unfunctioning;
using qjackctl, we can make midi keyboard work with jack easily:
-
run qjackctl;
-
click
Setup...
and change settings; -
click
Start
to start jack server; -
start fluidsynth or qsynth, setting both midi and audio driver to jack;
-
click
Graph
to wire jack ports;qjackctl arranges jack ports into clients; to route midi or audio data from one port to another, you simply click the source port and drag it to the destination port; by default, jack midi ports are red and jack audio ports are green; the patch-bay graph clearly shows the wiring;
a client name bug
in qjackctl-0.5.5
, a qsynth
client can be shown as two nodes with the same
name; when users try to connect a system
midi-out port to a qsynth
midi-in
port by dragging, qjackctl
will find the wrong node and cancels the wiring;
the bug may or may not exist in other versions; however, in qjackctl-0.6.0
it
doesnt show up because there is only one qsynth
node;
fedora 29 users: download
qjackctl-0.6.0-1.fc29.x86_64.rpm
(mirror);
troubleshooting
jack fails to create realtime thread during start
-
add yourself to
audio
group:$ usermod -a -G audio {username}
-
create or edit
/etc/security/limits.d/95-jack.conf
:@audio - rtprio 95 @audio - memlock unlimited @jackuser - rtprio 95 @jackuser - memlock unlimited
-
reboot for these changes to take effect;
vmpk doesnt work with jack
no, it doesnt work with jack any more; it once did, but then at some version it switched to a different library which doesnt support jack; this message is from one of its developers; i forgot where i read this, though;
links
-
a very good article briefing useful concepts, charts and tools about the linux midi system;
-
Demystifying JACK – A Beginners Guide to Getting Started with JACK
a well-written introduction of jack;
-
has some important and meaningful questions;
-
get started with your usb midi keyboards;
-
the alsa sequencer interface;
-
GNU/Linux for beginners: How Audio Works
for linux audio beginner;