I have a fork of Euterpea2 to explore algorithmic music manipulation and rendering. The library is able to render WAV or MIDI files, and that’s fine most of the time, as I will feed them to a DAW. However, there are times when I’d rather render a MIDI event sequence immediately to a MIDI controller or use a live MIDI sequencer.
Since I don’t always have access to a physical MIDI controller or sequencer,
I tend to use a MIDI software synthesizer instead. Debian provides at least
two options: timidity
and fluidsynth
. Both require a
MIDI GM to do their thing and,
thanks to standardization, one can easily use the Sound Blaster SoundFont.
Building Euterpea2 from source
Assuming you use Debian 11 or newer, in order to build Euterpea2 from source you’ll need:
Install a few supporting libraries
# apt install libportmidi-dev libasound2-dev
Clone Euterpea2 as you would clone any other Github repo
$ git clone https://github.com/Euterpea/Euterpea2.git Cloning into 'Euterpea2'... remote: Enumerating objects: 493, done. remote: Counting objects: 100% (104/104), done. remote: Compressing objects: 100% (18/18), done. remote: Total 493 (delta 90), reused 86 (delta 86), pack-reused 389 (from 1) Receiving objects: 100% (493/493), 19.05 MiB | 11.76 MiB/s, done. Resolving deltas: 100% (214/214), done.
I prefer
stack
rather thancabal
because of reasons. Upstream maintainers have never accepted my patches to supportstack
. If you likecabal
better, figure it out. If you want to usestack
, you’ll need$ cd Euterpea2 $ cat >> stack.yaml resolver: lts-22.43 packages: - . extra-deps: - PortMidi-0.2.0.0 ^D $ stack build
Direct MIDI playback using timidity
I tend to use timidity
for simple tests or when using a system that
does not have a kernel compiled for real-time scheduling.
Install
timidity
and the SoundFont GM# apt install timidity fluid-soundfont-gm
Check that
timitidy
is configured to use the SoundFont GM.$ grep source /etc/timidity/timidity.cfg #source /etc/timidity/freepats.cfg source /etc/timidity/fluidr3_gm.cfg #source /etc/timidity/fluidr3_gs.cfg
Start
timidiy
on a terminal$ timidity -iA --sequencer-ports=1 -Os Requested buffer size 32768, fragment size 8192 ALSA pcm 'default' set buffer size 32768, period size 8192 bytes TiMidity starting in ALSA server mode Opening sequencer port: 128:0
it will sit there forever waiting. These particular options launch
timidity
as a single-port ALSA Sequencer (meaning it can receive MIDI events over the ALSA API) and output ALSA waveforms (meaning it will use the GM to synthesize sound via ALSA).On a different terminal, start an Euterpea2 REPL session and use Euterpea2’s
devices
functions to figure out if the single output sequencer is available$ cd Euterpea2/ $ stack repl (...) ghci> devices Input devices: InputDeviceID 1 Midi Through Port-0 Output devices: OutputDeviceID 0 Midi Through Port-0 OutputDeviceID 2 TiMidity port 0
Use it
> playDev 2 $ forever $ canon wn (trio rrryb) ghci
and you should hear music.
What do you mean you don’t have functions
canon
,trio
, andrrryb
that make a cello, a viola, and a violin play a whole note delayed canon of «Row, row, row, your boat»?Once you’re done, just interrupt
timidity
.
Direct MIDI playback with fluidsynth
fluidsynth
can be used for simple tests as well, sure. But, it uses less CPU
than timidity
and peforms better for complex MIDI compositions, when
running on a system that does have a kernel compiled for real-time scheduling.
Install
fluidsynth
and the SoundFont GM# apt install fluidsynth fluid-soundfont-gm
Start
fluidsynth
on a terminal$ fluidsynth -si -a alsa /usr/share/sounds/sf2/FluidR3_GM.sf2 FluidSynth runtime version 2.1.7 Copyright (C) 2000-2021 Peter Hanappe and others. Distributed under the LGPL license. SoundFont(R) is a registered trademark of E-mu Systems, Inc.
it will sit there forever waiting. These particular options launch
fluidsynth
as a non-interactive server, that will output to ALSA waveform (meaning it will use the GM to synthesize sound via ALSA).On a different terminal, start an Euterpea2 REPL session and use Euterpea2’s
devices
function to figure out if the single output sequencer is available$ cd Euterpea2/ $ stack repl (...) ghci> devices Input devices: InputDeviceID 1 Midi Through Port-0 Output devices: OutputDeviceID 0 Midi Through Port-0 OutputDeviceID 2 Synth input port (94506:0)
Use it
> playDev 2 $ forever $ canon wn (trio rrryb) ghci
and you should hear music live.
Once you’re done, just interrupt
fluidsynth
.
You can have fluidsynth
running permanently as a daemon accessible
to your user only. This is useful if your system is never going to be
connected to an actual MIDI sequencer, you have CPU cores to spare, and
plan on doing live MIDI-to-sound sequencing (from Euterpea2 or a DAW).
In that case:
Modify
/etc/default/fluidsynth
to set the service’s configuration$ cat /etc/default/fluidsynth # Mandatory parameters (uncomment and edit) SOUND_FONT=/usr/share/sounds/sf2/FluidR3_GM.sf2 # Additional optional parameters (may be useful, see 'man fluidsynth' for further info) OTHER_OPTS='-a alsa -m alsa_seq -r 48000'
Enable and start the
fluidsynth
service for your user$ systemctl --user enable fluidsynth.service Created symlink /home/emhn/.config/systemd/user/multi-user.target.wants/fluidsynth.service → /usr/lib/systemd/user/fluidsynth.service. $ systemctl --user start fluidsynth.service $ systemctl --user status fluidsynth.service ● fluidsynth.service - FluidSynth Daemon Loaded: loaded (/usr/lib/systemd/user/fluidsynth.service; enabled; vendor preset: enab> Active: active (running) since Mon 2024-12-23 16:08:19 PST; 54s ago Docs: man:fluidsynth(1) Main PID: 97095 (fluidsynth) Tasks: 6 (limit: 18553) Memory: 186.1M CPU: 8.477s CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/fluidsynth.service └─97095 /usr/bin/fluidsynth -is -a alsa -m alsa_seq -r 48000 /usr/share/sounds> Dec 23 16:08:18 trillian systemd[2994]: Starting FluidSynth Daemon... Dec 23 16:08:19 trillian systemd[2994]: Started FluidSynth Daemon.
and the rest works all the same.
Bonus track
I open PerfectPiano on my Android Phone, then plug to the system using an USB-C cable. Swipe down and tap «USB Preferences», select «MIDI». And then…
> devices
ghci
Input devices:
InputDeviceID 1 Midi Through Port-0
InputDeviceID 3 Pixel 8 Pro MIDI 1
Output devices:
OutputDeviceID 0 Midi Through Port-0
OutputDeviceID 2 Pixel 8 Pro MIDI 1
It should be as easy on vendor locked-in devices, I reckon.