Home

Awesome

omkamra.sequencer-midi

Clojars Project

An omkamra.sequencer target for MIDI applications.

This target cannot be used on its own: its main purpose is to provide a set of common helpers for higher level targets which want to interface with actual MIDI devices.

It provides the following features:

These elements make it possible to encode musical phrases as pattern expressions:

[:bind {:root :f#3
        :scale :major
        :channel 0
        :vel 100
        :dur 2
        :step 1/2}
 [:program 33]
 (for [i (range 7)]
   [:seq
    [:degree i]
    [:bind {:oct [:add 1] :vel [:sub 30]} [:degree i]]])
 [:degree 7]
 [:wait 4]
 [:all-sounds-off]]

This pattern would play the seven degrees of the F# major scale starting in octave 3 on MIDI channel 0 using program 33, followed by the root note of the scale one octave higher.

Each note has a duration of 2 beats, i.e. the note-off MIDI message is scheduled two beats after the note-on. The :step value is 1/2, this means each note will advance the pattern offset by 1/2 beats.

Each of the seven scale degrees is played twice: first without transposition, then one octave higher and with a velocity decreased by 30.

After the scale and the finishing note the pattern waits 4 steps - this equals 2 beats as the value of the :step binding is 1/2 - and finally turns all sounds off.

Music description language

To ease the encoding of musical phrases, this target provides a compiler for a text-based music description language which can be embedded into patterns as Clojure strings.

The language provides the following building blocks:

Example inputResulting pattern expressionEffect
b2[:bank 2]set bank of current channel to 2
p4[:program 4]set program of current channel to 4
m60[:note 60]play MIDI note 60
c-5[:note 60]play MIDI note 60
c#5[:note 61]play MIDI note 61
b-4[:note 59]play MIDI note 59
3[:degree 3]play 3rd degree of current scale
-5[:degree -5]play 2nd degree of current scale one octave lower (assuming a scale of 7 notes)
,[:wait 1]wait 1 step
,4[:wait 4]wait 4 steps
,1/2[:wait 1/2]wait half step
,/3[:wait 1/3]wait 1/3 step
%4[:wait -4]wait until pattern offset reaches next multiple of 4 steps

These building blocks can be aggregated into larger units using the following syntax:

Example inputResulting pattern expressionEffect
(0 2 4)[:seq [:degree 0] [:degree 2] [:degree 4]]play the three degrees in succession
{0 2 4}[:mix1 [:degree 0] [:degree 2] [:degree 4]]play the three degrees in parallel, advance the pattern by the length of the first one

Both simple building blocks and aggregates can be ornamented with various binding modifiers:

Example inputResulting pattern expressionEffect
2c5[:bind {:channel 5} [:degree 2]]play degree 2 on MIDI channel 5
{3 4}~2[:bind {:dur 2} [:mix1 [:degree 3] [:degree 4]]]play degrees 3 and 4 simultaneously with duration 2
1~[:bind {:dur nil} [:degree 1]]play degree 1 with no duration (i.e. without a note-off)
0./4[:bind {:step [:mul 1/4]} [:degree 0]play degree 0 and advance the pattern offset by 1/4th of the current step
(5^ 5)c5[:bind {:channel 5} [:seq [:bind {:oct [:add 1]} [:degree 5]] [:degree 5]]]play degree 5 first one octave higher, then without transposition on channel 5
(5_3 5)v70[:bind {:vel 70} [:seq [:bind {:oct [:sub 3]} [:degree 5]] [:degree 5]]]play degree 5 first three octaves lower, then without transposition with velocity 70
6v-30[:bind {:vel [:sub 30]} [:degree 6]]play degree 6 with velocity decreased by 30
0#1[:bind {:semi [:add 1]} [:degree 0]]play degree 0 raised by one semitone
0b2[:bind {:semi [:sub 1]} [:degree 0]]play degree 0 lowered by two semitones
{0 2 4}&(minor)[:bind {:scale :minor} [:mix1 [:degree 0] [:degree 2] [:degree 4]]]play a minor triad
{0 2 4}>2[:bind {:mode 2} [:mix1 [:degree 0] [:degree 2] [:degree 4]]]play a triad in mode 2 (Phrygian if we are in a major scale)
2@3[:bind {:root [:degree->key 3]} [:degree 2]]]play the 2nd degree of the scale starting at the 3rd degree of the current scale

Aggregate modifiers can be placed either after the aggregate (as shown in the examples above) or interspersed with the aggregate elements:

Alternative 1Alternative 2Alternative 3
(0 2 4)c3(c3 0 2 4)(0 c3 2 4)
{0 2 4}.2~3{0 2 4 .2 ~3}{0 2 .2 4}~3

The location of the modifiers does not matter: they are all collected and put into the map of the :bind expression which encloses the group.

Pattern expressions parsed from a string are always wrapped in a :seq form, so there is no need to use parentheses around the top-level group.

License

Copyright © 2021 Balázs Ruzsa

This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0.

This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version, with the GNU Classpath Exception which is available at https://www.gnu.org/software/classpath/license.html.