Комбинирование базовых барабанных ритмов
Содержимое этой страницы также доступно на YouTube: https://youtu.be/Oog_aunpVms |
Предположим, у нас есть несколько базовых барабанных ритмов, которые мы хотим свободно комбинировать случайным образом. Например:
где нота ми означает правую руку, а ля — левую. Эти ритмы можно легко комбинировать для заполнения такта, например 5b -> 5b -> 3 -> 3
или 5a -> 4 -> 4 -> 3
и т. д. Их также можно комбинировать для заполнения двух тактов и т. д. Обратите внимание, что некоторые последовательности, например 5a -> 4 -> 4 -> 3
, приводят к чередованию рук: при каждом воспроизведении такой последовательности «ведущая» рука меняется. Это будет важно в дальнейшем.
Цель состоит в том, чтобы иметь возможность воспроизводить произвольные последовательности в течение произвольных периодов времени. Как опробовать это на практике? Мы используем random_notes_sequence
для более быстрого создания длинных 8-тактовых последовательностей с помощью Julia.
Определение Notes
Сначала нужно определить экземпляры Notes
, которые будут соответствовать этим четырем базовым ритмам.
using MusicManipulations, MusicVisualizations
tpq = 960 # количество импульсов на четвертную ноту
sixt = 240 # длительность шестнадцатой ноты
left = name_to_pitch("A5")
right = name_to_pitch("E6")
88
Напоминание: 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
Теперь motifs
обозначает набор последовательностей нот, из которого можно брать случайные фрагменты. Давайте создадим последовательности длиной в 8 тактов (то есть 32 четвертные ноты):
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
Теперь при необходимости их можно записать в файл MIDI, просто вызвав save("drums_patterns.mid", notes)
. Кроме того, с помощью MuseScore можно визуализировать и напечатать результат. Этот интерфейс предоставляет функция musescore
.
musescore("drums_patterns.png", notes)

Это предварительно подготовленный вариант — ваша случайная последовательность, скорее всего, будет другой
Получилось неплохо, но есть проблема: В последовательности не учитывается тот факт, что при воспроизведении некоторых ритмов (5b
и 4
) ведущая рука меняется. Эта проблема решается в следующем разделе.
Добавление чередования рук и текста песни
Обратите внимание, что random_note_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
С помощью этой информации мы можем добавить правильные «метки». Для чередования рук достаточно заменить соответствующие ноты ми на ля и наоборот. Определим ряд структур наподобие метаданных.
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)
Первый элемент каждого кортежа — это просто название ритма, которое также будет отображаться в партитуре как «текст песни». Второй элемент кортежа обозначает, меняется ли для ритма ведущая рука.
Функция, которая «обращает» метку ноты, выглядит следующим образом:
inverse!(n::Note) = (n.pitch = (n.pitch == left ? right : left));
Функция, которая «подсчитывает» длительность каждого ритма для размещения текста песни в правильных позициях в партитуре, выглядит так:
note_length(s::String) = parse(Int, s[1]);
(Помните, что sixt
— это длительность шестнадцатой ноты.) Теперь мы инициализируем пустой объект MIDITrack
и добавим в него все события.
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
Наконец, с целью визуализации мы снова используем функцию musescore
, передав файл MIDI в качестве входных данных:
musescore("drums_patterns_with_names.png", MIDIFile(1, 960, [track]))

Разве не здорово, что даже текст песни можно отобразить так легко?