Engee documentation

Combining basic drum rhythms

The content of this page is also available on YouTube: https://youtu.be/Oog_aunpVms


Let’s say we have several basic drum rhythms that we want to freely combine randomly. For example:

Базовые барабанные ритмы

where the note mi means the right hand, and la means the left. These rhythms can be easily combined to fill a beat, for example, 5b -> 5b -> 3 -> 3 or 5a -> 4 -> 4 -> 3 and so on . They can also be combined to fill two bars, etc. Note that some sequences, such as 5a -> 4 -> 4 -> 3, They lead to a hand change: each time such a sequence is played, the "leading" hand changes. This will be important in the future.

The goal is to be able to play arbitrary sequences for arbitrary periods of time. How can I put this into practice? We use random_notes_sequence for faster creation of long 8-clock sequences using Julia.

Definition of Notes

First, you need to define instances of Notes that will correspond to these four basic rhythms.

using MusicManipulations, MusicVisualizations

tpq = 960 # количество импульсов на четвертную ноту
sixt = 240 # длительность шестнадцатой ноты
left = name_to_pitch("A5")
right = name_to_pitch("E6")
88

Reminder: Note(pitch, intensity, start, duration)

motif1 = [ # мотив 5a
Note(right, 100, 0, sixt),
Note(left, 50, sixt, sixt),
Note(right, 100, 2sixt, sixt),
Note(left, 50, 3sixt, sixt),
Note(left, 50, 4sixt, sixt)
]

motif2 = [ # мотив 5b
Note(right, 100, 0, sixt),
Note(left, 50, sixt, sixt),
Note(left, 50, 2sixt, sixt),
Note(right, 50, 3sixt, sixt),
Note(right, 50, 4sixt, sixt)
]

motif3 = [ # мотив 3
Note(right, 100, 0, sixt),
Note(left, 50, sixt, sixt),
Note(left, 50, 2sixt, sixt),
]

motif4 = [ # мотив 4
Note(right, 100, 0, sixt),
Note(left, 50, sixt, sixt),
Note(right, 50, 2sixt, sixt),
Note(right, 50, 3sixt, sixt),
]

motifs = Notes.([motif1, motif2, motif3, motif4], tpq)
4-element Vector{Notes{Note}}:
 Notes{Note} with 5 notes
 Notes{Note} with 5 notes
 Notes{Note} with 3 notes
 Notes{Note} with 4 notes

Now motifs stands for a set of note sequences from which random fragments can be taken. Let’s create sequences of 8 bars (that is, 32 quarter notes).:

q = tpq*32

notes, seq = random_notes_sequence(motifs, q)
notes
128 Notes with tpq=960
 Note E6  | vel = 100 | pos = 0, dur = 240
 Note A5  | vel = 50  | pos = 240, dur = 240
 Note E6  | vel = 100 | pos = 480, dur = 240
 Note A5  | vel = 50  | pos = 720, dur = 240
 Note A5  | vel = 50  | pos = 960, dur = 240
 Note E6  | vel = 100 | pos = 1200, dur = 240
 Note A5  | vel = 50  | pos = 1440, dur = 240
  ⋮
 Note E6  | vel = 100 | pos = 29040, dur = 240
 Note A5  | vel = 50  | pos = 29280, dur = 240
 Note A5  | vel = 50  | pos = 29520, dur = 240
 Note E6  | vel = 100 | pos = 29760, dur = 240
 Note A5  | vel = 50  | pos = 30000, dur = 240
 Note E6  | vel = 50  | pos = 30240, dur = 240
 Note E6  | vel = 50  | pos = 30480, dur = 240

Now, if necessary, they can be written to a MIDI file by simply calling save("drums_patterns.mid", notes). In addition, using https://musescore.org [MuseScore] The result can be visualized and printed. This interface provides a function musescore.

musescore("drums_patterns.png", notes)
Последовательность из 32 тактов

this is a pre-prepared version — your random sequence is likely to be different

It turned out well, but there is a problem: The sequence does not take into account the fact that when playing some rhythms (5b and 4), the leading hand changes. This problem is solved in the next section.

Adding alternating hands and lyrics

Note that random_note_sequence also returns the indexes of the motifs that were used to create the sequence.:

seq
30-element Vector{Int64}:
 1
 3
 1
 4
 4
 2
 2
 3
 3
 1
 ⋮
 2
 3
 2
 1
 1
 1
 3
 3
 4

With this information, we can add the correct "labels". To alternate hands, it is enough to replace the corresponding notes of mi with la and vice versa. Let’s define a number of structures like metadata.

accent1 = ("5a", false)
accent2 = ("5b", true)
accent3 = ("3", false)
accent4 = ("4", true)
accents = [accent1, accent2, accent3, accent4]
4-element Vector{Tuple{String, Bool}}:
 ("5a", 0)
 ("5b", 1)
 ("3", 0)
 ("4", 1)

The first element of each tuple is just the name of the rhythm, which will also be displayed in the score as the "lyrics". The second element of the tuple indicates whether the leading hand is changing for the rhythm.

The function that "reverses" the note label looks like this:

inverse!(n::Note) = (n.pitch = (n.pitch == left ? right : left));

The function that "counts" the duration of each beat to place the lyrics in the correct positions in the score looks like this:

note_length(s::String) = parse(Int, s[1]);

(Remember that sixth is the duration of the sixteenth note.) Now we initialize an empty object. MIDITrack and add all the events to it.

track = MIDITrack()
ℓ = 0
right_leads = true

for i in 1:length(seq)

    s = accents[seq[i]][1]
    le = MIDI.LyricEvent(0, MIDI.LYRICEV, s)
    addevent!(track, ℓ*sixt, le)

    if !right_leads # Обращаем ноты
        for j in ℓ+1:ℓ+note_length(s)
            inverse!(notes[j])
        end
    end

    global ℓ += note_length(s)

    change = accents[seq[i]][2]
    global right_leads = xor(right_leads, change)
end

addnotes!(track, notes)
notes
128 Notes with tpq=960
 Note E6  | vel = 100 | pos = 0, dur = 240
 Note A5  | vel = 50  | pos = 240, dur = 240
 Note E6  | vel = 100 | pos = 480, dur = 240
 Note A5  | vel = 50  | pos = 720, dur = 240
 Note A5  | vel = 50  | pos = 960, dur = 240
 Note E6  | vel = 100 | pos = 1200, dur = 240
 Note A5  | vel = 50  | pos = 1440, dur = 240
  ⋮
 Note A5  | vel = 100 | pos = 29040, dur = 240
 Note E6  | vel = 50  | pos = 29280, dur = 240
 Note E6  | vel = 50  | pos = 29520, dur = 240
 Note A5  | vel = 100 | pos = 29760, dur = 240
 Note E6  | vel = 50  | pos = 30000, dur = 240
 Note A5  | vel = 50  | pos = 30240, dur = 240
 Note A5  | vel = 50  | pos = 30480, dur = 240

Finally, for the purpose of visualization, we use the function again musescore by passing a MIDI file as input:

musescore("drums_patterns_with_names.png", MIDIFile(1, 960, [track]))
Правильная последовательность из 32 тактов