ut-proj / undermidi

An Erlang/LFE MIDI soft real time server for live play of MIDI devices
BSD 2-Clause "Simplified" License
4 stars 1 forks source link
erlang generative-music hacktoberfest lfe lisp-flavoured-erlang midi music

undermidi

Build Status LFE Versions Erlang Versions

A set of OTP servers that faciliate live MIDI composition and performance

About

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.

Dependencies & Setup

This application assumes that the following are on your system:

Build & Run

The 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.

API

There are two ways to use this library:

  1. Stateless: Make direct calls to the undermidi wrappers for the MIDI Erlang NIF, passing device and channel with every call
  2. Stateful: Create a managed connection to the MIDI device, passing only the data you need to make music

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".

Stateful

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.

Notes

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.

Chords

Sequences

Stateless

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)

Notes

lfe> (um.note:play device channel 'C3)
lfe> (um.note:play device channel '(C3 C3 Eb3 C3 C3 Bb3 C3 C4))

Chords

Sequences

Licenses

undermidi: BSD 2-Clause

Sonic Pi's Erlang NIF: MIT

RtMIDI: MIT-like (optional notification)