Документация Engee

Построение нотной диаграммы

С помощью MusicVisualizations можно строить диаграмму на основе Notes, похожую на «отпечатки клавиш» в таких программах DAW, как Cubase. Для этого служит функция noteplotter, которая использует PyPlot.

noteplotter(notes::Notes; kwargs...)

Строит диаграмму на основе notes в виде «отпечатков клавиш», где:

  • по оси X отмечается положение нот;

  • по оси Y отмечается «высота тона» или «значение» ноты (см. ниже);

  • цвет обозначает силу воспроизведения нот.

Затем возвращаются значения по оси Y.

Именованные аргументы

  • st = (notes[1].position ÷ notes.tpq) * notes.tpq: время, с которого начинает строиться диаграмма.

  • fi = st + 16notes.tpq: время завершения построения диаграммы; по умолчанию 16 четвертных нот, то есть четыре такта. Если диаграмма должна строиться до последней ноты, укажите Inf.

  • ax = (PyPlot.figure(); PyPlot.gca()): ось, по которой строится диаграмма.

  • cmap = "viridis": цветовая карта, используемая для силы воспроизведения.

  • grid = 0:0.25:1: сетка, которая отрисовывается вместе с нотами (по умолчанию шестнадцатые ноты). Чтобы не наносить линии сетки, укажите nothing.

  • names: словарь, в котором со значениями по оси Y сопоставляются имена. По умолчанию используется функция pitch_to_name вместе с эвристикой, позволяющей присваивать имена только 7 нотам.

  • plotnote! Функция с аргументами вызова plotnote!(ax, note, cmap) (где cmap — экземпляр цветовой карты, а не строка), которая фактически строит диаграмму нот. По умолчанию отрисовываются «отпечатки клавиш».

Аргумент plotnote! позволяет настраивать тип диаграммы. Предполагается, что функция отображает ноту на заданной оси и возвращает «значение» ноты. Пример использования, например для построения диаграммы нот для ударных, см. в официальной документации.


Ноты для фортепиано

using MusicVisualizations, PyPlot
# MusicVisualizations для удобства повторно экспортирует MusicManipulations

# загружаем выступление группы (с метрономом)
midi = readMIDIFile(joinpath(@__DIR__, "mfi_grapevine_1.mid"))

grid = 0:1//4:1
piano = getnotes(midi, 4)
819 Notes with tpq=960
 Note F4  | vel = 99  | pos = 8981, dur = 1217
 Note A4  | vel = 99  | pos = 8981, dur = 1275
 Note D5  | vel = 97  | pos = 8990, dur = 1314
 Note D3  | vel = 97  | pos = 9004, dur = 1772
 Note D4  | vel = 81  | pos = 9015, dur = 1287
 Note F4  | vel = 84  | pos = 10496, dur = 130
 Note A4  | vel = 87  | pos = 10504, dur = 175
  ⋮
 Note E5  | vel = 87  | pos = 310837, dur = 114
 Note F5  | vel = 81  | pos = 311276, dur = 233
 Note G4  | vel = 82  | pos = 311284, dur = 196
 Note B4  | vel = 58  | pos = 311286, dur = 197
 Note G4  | vel = 92  | pos = 311739, dur = 197
 Note E5  | vel = 99  | pos = 311744, dur = 181
 Note B4  | vel = 56  | pos = 311782, dur = 104
noteplotter(piano; st = 15300, grid = grid)
pianoroll

Ноты для ударных

Преимущество функции noteplotter в том, что ее можно полностью настраивать с помощью аргумента plotnote!. В этом разделе мы покажем пример того, как можно использовать noteplotter для отображения нот для ударных в барабанной нотации, как это делается в области GM Map в Cubase.

Сначала нужно определить специальную функцию для plotnote!. Так как длительность нот в данном случае не имеет значения, мы можем просто указать их на диаграмме в виде точек. Кроме того, мы можем использовать разные символы для разных партий барабанов, например кружки для малого и большого барабанов и крестики для хай-хэта и тарелок.

function plotdrumnote!(ax, note, cmap)
    p = note.pitch
    if p == 0x24 # «бочка»
        v, m = 1, "o"
    elseif p ∈ (0x26, 0x28) # малый барабан
        v, m = 3, "o"
    elseif p ∈ (0x16, 0x1a) # ребро хай-хэта
        v, m = 5, "X"
    elseif p ∈ (0x2e, 0x2a) # мембрана хай-хэта
        v, m = 5, "x"
    elseif p == 0x35 # звенящая райд-тарелка
        v, m = 6, "D"
    elseif p == 0x33 # мембрана райд-тарелки
        v, m = 6, "x"
    elseif p == 0x3b # ребро райд-тарелки
        v, m = 6, "X"
    elseif p ∈ (0x30, 0x32) # бочка 1
        v, m = 4, "s"
    elseif p ∈ (0x2b, 0x3a) # бочка 3
        v, m = 2, "s"
    elseif p ∈ (0x31, 0x37, 0x34, 0x39)
        v, m = 7, "X"
    elseif p == 0x2c # педаль хай-хэта
        v, m = 1, "x"
    else
        error("Unknown pitch $(UInt8(p))")
    end
    ax.scatter(note.position, v, marker = m, s = 250,
        color = cmap(min(note.velocity, 127)/127))
    return v
end
plotdrumnote! (generic function with 1 method)

(Обратите внимание, что указанная выше функция настроена вручную для конкретной электронной ударной установки.)

Чтобы диаграмму было удобнее читать, можно использовать собственные имена для нот:

TD50_PLOT = Dict(
    1 => "kick",
    3 => "snare",
    5 => "hihat",
    6 => "ride",
    4 => "tom1",
    2 => "tom3",
    7 => "crash",
)
Dict{Int64, String} with 7 entries:
  5 => "hihat"
  4 => "tom1"
  6 => "ride"
  7 => "crash"
  2 => "tom3"
  3 => "snare"
  1 => "kick"

В итоге диаграмма нот для ударных может выглядеть так:

drums = getnotes(midi, 3)
drums = translate(drums, -300) # постоянная задержка

noteplotter(drums; st = 15300, grid = grid,
                   names=TD50_PLOT, plotnote! = plotdrumnote!)
drumroll