A set of OTP servers that faciliate live MIDI composition and performance
undermidi supports two use cases, both of which utilise the Erlang term MIDI message formats defined in midilib:
Note that the calls made to midilib use the midibin
module for binary MIDI messages, which in turn uses the Erlang MIDI NIF provided by the Sonic Pi project.
Update: This use of an Erlang NIF is new in 0.3.0! As part of that change, we made significant and breaking changes to the undermidi
API.
This application assumes that the following are on your system:
git
cmake
, GNU make
, OS-specific dev libraries that support MIDIThe required sources for buidling the Erlang NIF will be downloaded and compiled, and then the Erlang and LFE for undermidi will be compiled, all with the following:
$ rebar3 compile
Then start the LFE REPL with prefined options for undermidi:
$ rebar3 as undermidi repl
IMPORTANT!!: the command given above automatically starts undermidi. If you do not use that command, you will need to manually start undermidi. Not doing so will result in many commands causing a segmentation fault of the Erlang VM due to the MIDI NIF not being initialised!
If you find yourself tiring of typing the above command, you can use the simple bash script that does the same:
$ ./priv/scripts/run.sh
Once the LFE REPL is ready, you can start the app:
(undermidi@local)lfe> (undermidi:start)
Note that, depending upon the configured log level, you may see a fair amount of output.
There are two ways to use this library:
Each of these are demonstrated below. The stateful approach is preferred and encouraged, as it makes code easier to read and helps one organise workflows when coding for multiple MIDI devices at once.
The midilib
code used by undermidi utilises the same means as the Erlang NIF for referencing MIDI devices: their system names. The full set known by the system can be displayed with the following:
lfe> (undermidi:list-devices)
inputs
1. network_session_1
2. core_midi_general
3. core_midi_keyboards
4. komplete_kontrol_s88_mk2_port_1
5. komplete_kontrol_s88_mk2_port_2
6. komplete_kontrol_daw_-_1
7. model_15
8. model_d
outputs
1. network_session_1
2. core_midi_general
3. core_midi_keyboards
4. komplete_kontrol_s88_mk2_port_1
5. komplete_kontrol_s88_mk2_port_2
6. komplete_kontrol_daw_-_1
7. model_15
8. model_d
ok
The output of this display function will vary, depending upon system and connected/configured MIDI devices.
We'll use one of these names in the examples below, Moog's "model_15"
.
Get a managed MIDI device connection:
lfe> (set `#(ok ,d) (undermidi.devices:new "model_15"))
#(ok #Pid<0.1140.0>)
Note that the name may be passed as either an atom or a string (list), but that the name used by the NIF is a string, and as such, undermidi ensures a name passed as an atom is converted when calling new
.
The undermidi
project represents notes as a data structure of pitch, velocity, and duration. However, it provides some defaults to make that a little easier to work with, as well as a means of easily referencing MIDI pitch values using note names.
Play a single note:
lfe> (undermidi:play-note d 'C3)
Play a series of notes:
lfe> (undermidi:play-notes d '(C3 C3 Eb3 C3 C3 Bb3 C3 C4))
The play-notes
function also accepts optional arguments for changing the time between the notes as well as the ability to repeat the series.
Some variables for the MIDI device and the MIDI channel we're going to use for most calls:
lfe> (set device "")
lfe> (set channel 1)
lfe> (um.note:play device channel 'C3)
lfe> (um.note:play device channel '(C3 C3 Eb3 C3 C3 Bb3 C3 C4))
undermidi: BSD 2-Clause
Sonic Pi's Erlang NIF: MIT
RtMIDI: MIT-like (optional notification)