Ноты
Информация о нотах в MIDI-файлах обычно кодируется посредством событий NOTEON и NOTEOFF. Однако информация о музыкальной ноте не ограничивается началом и концом; эта информация помещается в типы Note и Notes. Эти две структуры играют центральную роль в работе JuliaMusic. Кроме того, все события нот в MIDITrack можно получить с помощью функции getnotes.
#
MIDI.Note — Type
Note(pitch, velocity, position, duration, channel = 0) <: AbstractNote
Изменяемая структура данных, описывающая музыкальную ноту. При объединении нескольких нот образуется структура Notes, которую возвращает функция getnotes.
Если канал channel ноты имеет значение 0 (по умолчанию), он не отображается.
Создать объект Note можно также с помощью следующего конструктора с именованными аргументами:
Note(pitch, position; velocity = 100, duration = 960, channel = 0)
Note(pitch_name::String; position = 0, velocity = 100, duration = 960, channel = 0)
Поля:
-
pitch::UInt8: высота тона, начиная с C-1 = 0; на каждый полутон добавляется единица. Используйте функцииname_to_pitchиpitch_to_namefor integer and string representations. -
velocity::UInt8: динамическая интенсивность. Не может быть больше 127 (0x7F). -
position::UInt: позиция с начала дорожки в абсолютном времени (в импульсах). -
duration::UInt: длительность в импульсах. -
channel::UInt8 = 0: канал дорожки, в котором воспроизводится нота. Не может быть больше 127 (0x7F).
#
MIDI.Notes — Type
Notes(note_vector, tpq = 960) -> Notes
Notes(notes_string::String, tpq::Int = 960) -> Notes
Структура данных, описывающая коллекцию музыкальных нот с указанием тиков на четверть ноты (чтобы нотам можно было приписать ритмическое значение).
Ноты можно инициализировать строкой; имена нот разделяются пробелами.
Notes("C2 F3 D#6")
Notes допускает итерацию и доступ посредством note_vector. Это устраняет необходимость в пользовательских функциях итерации или поиска. Например, получить ноту максимальной высоты можно так:
max_pitch, index_max = findmax(n -> n.pitch, notes)
max_pitch_note = notes[index_max]
#
MIDI.getnotes — Function
getnotes(midi::MIDIFile [, trackno])
Находит все события NoteOnEvent и NoteOffEvent в дорожке trackno midi (по умолчанию 1 или 2), которые соответствуют одному и тому же значению ноты (высоте тона), и преобразует их в тип данных Note. Есть особые случаи, когда NoteOffEvent фактически кодируется как NoteOnEvent с нулевой силой воспроизведения, однако функция getnotes учитывает это.
Обратите внимание, что первая дорожка midi обычно не содержит нот, поэтому функция по умолчанию использует дорожку 2.
getnotes(track::MIDITrack, tpq = 960)
Находит ноты непосредственно в track, также передавая количество импульсов на четвертную ноту.
Возвращает Notes{Note}, задавая количество импульсов на четвертную ноту в tpq. Определить экспортированное значение количества импульсов на четвертную ноту в исходном файле MIDIFile можно посредством midi.tpq.
Если у вас есть ноты, которые вы хотите добавить в дорожку, используйте следующий код:
#
MIDI.addnotes! — Function
addnotes!(track::MIDITrack, notes)
Добавляет заданные notes в заданный track, выполняя внутри все переводы из абсолютного времени в относительное.
Наконец, с помощью функции getnotnotes(track) можно получить все события TrackEvents, отличные от NOTEON и NOTEOFF.
Пример записи
using MIDI
C = Note(60, 96, 0, 192)
E = Note(64, 96, 48, 144)
G = Note(67, 96, 96, 96)
inc = 192
file = MIDIFile()
track = MIDITrack()
notes = Notes() # tpq автоматически устанавливается в значение 960
push!(notes, C)
push!(notes, E)
push!(notes, G)
# Ноты на одну октаву выше
C = Note(60 + 12, 96, C.position+inc, 192)
E = Note(64 + 12, 96, E.position+inc, 144)
G = Note(67 + 12, 96, G.position+inc, 96)
addnotes!(track, notes)
addtrackname!(track, "simple track")
push!(file.tracks, track)
save("test.mid", file)
Пример считывания
using MIDI
midi = load(testmidi())
MIDIFile (format=1, tpq=960) with tracks:
American Rock Beat 06 Tom
Drums
Bass
ORIGINAL
# Дорожка номер 3 — это квантованная басовая MIDI-дорожка.
bass = midi.tracks[3]
notes = getnotes(bass, midi.tpq)
println("Notes of track $(trackname(bass)):")
notes
177 Notes with tpq=960
Note A♯2 | vel = 95 | pos = 7680, dur = 690
Note A♯2 | vel = 71 | pos = 9280, dur = 308
Note G♯2 | vel = 52 | pos = 9600, dur = 668
Note G♯2 | vel = 58 | pos = 11200, dur = 338
Note G2 | vel = 71 | pos = 11520, dur = 701
Note G♯2 | vel = 83 | pos = 13120, dur = 281
Note G2 | vel = 73 | pos = 13440, dur = 855
⋮
Note F♯1 | vel = 73 | pos = 185280, dur = 878
Note F1 | vel = 85 | pos = 186240, dur = 964
Note A1 | vel = 88 | pos = 187200, dur = 904
Note A♯1 | vel = 81 | pos = 188160, dur = 900
Note B1 | vel = 77 | pos = 189120, dur = 945
Note C2 | vel = 83 | pos = 190080, dur = 847
Note F2 | vel = 90 | pos = 191040, dur = 713
Преобразования
#
MIDI.name_to_pitch — Function
name_to_pitch(name::String) -> Int
Возвращает значение высоты тона заданного имени ноты, которое может иметь вид capital_letter*sharp*octave, где:
-
capital_letter: от"A"до"G". -
sharp: один из символов"#""♯""b""♭"или"". -
octave: любое целое число (в виде строки); номер октавы (октава — это 12 нот). Если не указано, предполагается значение"5".
Можно определить, например, name_to_pitch("C4") === 60 (то есть строка "C4", представляющая ноту до первой октавы, соответствует высоте тона 60).
#
MIDI.pitch_to_name — Function
pitch_to_name(pitch; flat=false) -> String
Return the name of the pitch, e.g. F5, A♯3 etc. in modern notation given the pitch value in integer. When flat=true, accidentals are printed as flats, e.g. A♯3 is printed as B♭3.
Возвращает название тональности, например, F5, A♯3 и т.д. в современной нотации, учитывая значение тональности в целых числах. Если flat=true, то авариации печатаются как бемоли, например, A♯3 печатается как B♭3.
Напоминание: нота до первой октавы имеет высоту 60 и отображается как C4.
#
MusicManipulations.note_to_fundamental — Function
note_to_fundamental(note(s))
Возвращает String или Vector{String} с основной высотой нот (то есть без информации об октаве).
#
MIDI.hz_to_pitch — Function
hz_to_pitch(hz::Real, A4::Real = 440) -> pitch::Int
Функция, обратная pitch_to_hz.
#
MIDI.pitch_to_hz — Function
pitch_to_hz(pitch::Integer, A4::Real = 440) -> hz::Real
Возвращает значение частоты заданной миди-ноты, опционально задавая ссылку на середину A. См. https://en.wikipedia.org/wiki/Pianokeyfrequencies and https://librosa.org/doc/main/modules/librosa/core/convert.html#midito_hz.
NamedNote
Нота с определенным именем. Для этого типа требуется MusicManipulations.jl.
#
MusicManipulations.NamedNote — Type
NamedNote(name, velocity, position, duration, channel = 0) <: AbstractNote
Изменяемая структура данных, описывающая музыкальную ноту с определенным именем высоты тона. При объединении нескольких нот образуется структура Notes, которую возвращает функция getnotes.
Если канал channel ноты имеет значение 0 (по умолчанию), он не отображается.
Создать объект NamedNote можно также с помощью следующего конструктора с именованными аргументами:
NamedNote(pitch_name::String; position = 0, velocity = 100, duration = 960, channel = 0)
NamedNote(n::Note; pitch_name::String = "")
Notes{NamedNote} инициализируется на основе строки с именами высоты тона, разделенными пробелами.
NamedNotes(notes_string::String; tpq::Int = 960)
# NamedNotes("C#6 Db5 E4")
Преобразует NamedNote в Note:
Note(n::NamedNote)
Внимание! Для сравнения NamedNote используются атрибуты name_to_pitch(name), duration, position, channel, velocity. Поэтому:
NamedNote("Db5") == NamedNote("C#5")
# true
Поля:
-
name::String: имя высоты тона в верхнем регистре. -
velocity::UInt8: динамическая интенсивность. Не может быть больше 127 (0x7F). -
position::UInt: позиция с начала дорожки в абсолютном времени (в импульсах). -
duration::UInt: длительность в импульсах. -
channel::UInt8 = 0: канал дорожки, в котором воспроизводится нота. Не может быть больше 127 (0x7F).