Ноты
Информация о нотах в 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_name
for 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).