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-devClone 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
stackrather thancabalbecause of reasons. Upstream maintainers have never accepted my patches to supportstack. If you likecabalbetter, 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
timidityand the SoundFont GM# apt install timidity fluid-soundfont-gmCheck that
timitidyis 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.cfgStart
timidiyon 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:0it will sit there forever waiting. These particular options launch
timidityas 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
devicesfunctions 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 0Use it
ghci> playDev 2 $ forever $ canon wn (trio rrryb)and you should hear music.
What do you mean you don’t have functions
canon,trio, andrrrybthat 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
fluidsynthand the SoundFont GM# apt install fluidsynth fluid-soundfont-gmStart
fluidsynthon 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
fluidsynthas 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
devicesfunction 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
ghci> playDev 2 $ forever $ canon wn (trio rrryb)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/fluidsynthto 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
fluidsynthservice 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…
ghci> devices
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 1It should be as easy on vendor locked-in devices, I reckon.