Базовые структуры MIDI
Ввод-вывод MIDI
Для чтения и записи MIDI-файла можно использовать функции load и save. Они расширяют интерфейс FileIO. Их синтаксис следующий:
load(filename) -> midi::MIDIFile
Загрузите MIDI-файл, содержащийся в filename (он должен заканчиваться на .mid), и верните его как MIDIFile.
save(filename, data::MIDIFile)
Запишите MIDIFile как файл .mid в указанный объект filename.
save(filename, notes::Notes)
Создайте файл MIDIFile непосредственно из notes, используя формат 1, а затем сохраните его.
MIDIFile
#
MIDI.MIDIFile — Type
MIDIFile <: Any
Тип, представляющий файл с данными MIDI.
Поля
-
format::UInt16: формат файла. Может иметь значение 0, 1 или 2. -
tpq::Int16: временное деление дорожки, количество импульсов на четвертную ноту. -
tracks::Array{MIDITrack, 1}: массив содержащихся дорожек.
MIDITrack
Наиболее важное поле MIDIFile — tracks. Оно содержит столько дорожек, сколько пожелает пользователь. Дорожки содержат всю «музыкальную» информацию в виде «событий», о которых мы упоминали в разделе MIDI: минимальные необходимые знания.
#
MIDI.MIDITrack — Type
MIDITrack <: Any
Объект MIDITrack — это просто контейнер для TrackEvents, так как его единственное поле — events::Vector{TrackEvent}.
Фрагменты дорожки начинаются с четырех байтов, которые записываются как «MTrk», за которыми следуют длина дорожки в байтах (см. описание readvariablelength) и последовательность событий.
MIDITrack реализует функции isempty и empty!.
#
MIDI.TrackEvent — Type
TrackEvent <: Any
Абстрактный супертип для всех событий MIDI.
Все события дорожки начинаются со значения времени переменной длины (см. описание readvariablelength) и имеют поле dT, которое его содержит. Это число указывает, через сколько импульсов с момента последнего события происходит текущее событие.
Затем MIDIEvent возобновляется с сообщением MIDI-канала, определенным в constants.jl. Затем следуют 1 или 2 байта в зависимости от сообщения канала (см. описание MIDI.EVENTTYPETOLENGTH). Если допустимое сообщение канала не идентифицировано, используется предыдущее сообщение. После этого команда MIDI кодируется.
И MetaEvent, и SysexEvent возобновляются с определенного байта (см. описание constants.jl).
Сами события TrackEvent можно разделить на три типа.
abstract type MIDIEvent <: TrackEvent end
abstract type MetaEvent <: TrackEvent end
struct SysexEvent <: TrackEvent
dT::Int
data::Array{UInt8,1}
end
Различные MIDI- и метасобытия, встречающиеся в MIDI-файле, имеют собственные типы. Дополнительные сведения см. в разделах Метасобытия и MIDI-события ниже.
Метасобытия
#
MIDI.SequenceNumberEvent — Type
SequenceNumberEvent <: MetaEvent
Событие SequenceNumberEvent содержит номер последовательности в MIDI-файлах типов 0 и 1, или номер паттерна в MIDI-файлах типа 2.
Поля:
-
dT::Int: время дельты в импульсах. -
metatype::UInt8: байт метатипа события. -
number::Int: порядковый номер.
#
MIDI.TextEvent — Type
TextEvent <: MetaEvent
Событие TextEvent содержит текст в MIDI-файле.
Поля:
-
dT::Int: время дельты в импульсах. -
metatype::UInt8: байт метатипа события. -
text::String: текст события.
#
MIDI.CopyrightNoticeEvent — Type
CopyrightNoticeEvent <: MetaEvent
Событие CopyrightNoticeEvent содержит уведомление об авторских правах в MIDI-файле.
Поля:
-
dT::Int: время дельты в импульсах. -
metatype::UInt8: байт метатипа события. -
text::String: уведомление об авторских правах в тексте.
#
MIDI.TrackNameEvent — Type
TrackNameEvent <: MetaEvent
Событие TrackNameEvent содержит либо имя MIDI-последовательности (в файлах MIDI типа 0 или MIDI типа 2, или в первой дорожке файла MIDI типа 1), либо имя MIDI-дорожки (в других дорожках файла MIDI типа 1).
Поля:
-
dT::Int: время дельты в импульсах. -
metatype::UInt8: байт метатипа события. -
text::String: название дорожки в тексте.
#
MIDI.InstrumentNameEvent — Type
InstrumentNameEvent <: MetaEvent
Событие InstrumentNameEvent содержит имя инструмента, который будет использоваться в треке.
Поля:
-
dT::Int: время дельты в импульсах. -
metatype::UInt8: байт метатипа события. -
text::String: название инструмента в тексте.
#
MIDI.LyricEvent — Type
LyricEvent <: MetaEvent
Событие LyricEvent содержит текст песни (обычно слоги) в MIDI-файле.
Поля:
-
dT::Int: время дельты в импульсах. -
metatype::UInt8: байт метатипа события. -
text::String: текст песни.
#
MIDI.MarkerEvent — Type
MarkerEvent <: MetaEvent
Событие MarkerEvent содержит текст маркера.
Поля:
-
dT::Int: время дельты в импульсах. -
metatype::UInt8: байт метатипа события. -
text::String: текст маркера.
#
MIDI.CuePointEvent — Type
CuePointEvent <: MetaEvent
Событие CuePointEvent содержит реплику в MIDI-файле.
Поля:
-
dT::Int: время дельты в импульсах. -
metatype::UInt8: байт метатипа события. -
text::String: сигнал в тексте.
#
MIDI.MIDIChannelPrefixEvent — Type
MIDIChannelPrefixEvent <: MetaEvent
Событие MIDIChannelPrefixEvent содержит номер канала, на который отправляются следующие мета-сообщения.
Поля:
-
dT::Int: время дельты в импульсах. -
metatype::UInt8: байт метатипа события. -
channel::Int: номер канала.
#
MIDI.EndOfTrackEvent — Type
EndOfTrackEvent <: MetaEvent
Событие EndOfTrackEvent обозначает конец трека.
Поля:
-
dT::Int: время дельты в импульсах. -
metatype::UInt8: байт метатипа события.
#
MIDI.SetTempoEvent — Type
SetTempoEvent <: MetaEvent
Событие SetTempoEvent устанавливает темп MIDI-последовательности в микросекундах на четверть ноты.
Поля:
-
dT::Int: время дельты в импульсах. -
metatype::UInt8: байт метатипа события. -
tempo::Int: темп в микросекундах на четвертную ноту.
#
MIDI.TimeSignatureEvent — Type
TimeSignatureEvent <: MetaEvent
Событие TimeSignatureEvent содержит временную подпись MIDI-последовательности.
Поля:
-
dT::Int: время дельты в импульсах. -
metatype::UInt8: байт метатипа события. -
numerator::Int: числитель тактового размера. -
denominator::Int: знаменатель тактового размера. -
clockticks::Int: количество импульсов MIDI-часов за один отсчет метронома. -
notated32nd_notes::Int: количество тридцать вторых нот на долю.
#
MIDI.KeySignatureEvent — Type
KeySignatureEvent <: MetaEvent
Событие KeySignatureEvent содержит ключевую подпись и шкалу MIDI-файла.
Поля:
-
dT::Int: время дельты в импульсах. -
metatype::UInt8: байт метатипа события. -
semitones::Int: количество бемолей или диезов. -
scale::Int: тональность MIDI-файла; 0, если тональность мажорная, 1, если тональность минорная.
MIDI-события
#
MIDI.NoteOffEvent — Type
NoteOffEvent <: MIDIEvent
Событие NoteOffEvent информирует MIDI-устройство об освобождении ноты.
Поля:
-
dT::Int: время дельты в импульсах. -
status::UInt8: байт статуса события. -
note::Int: нота, которую следует перестать воспроизводить. -
velocity::Int: сила воспроизведения ноты.
#
MIDI.NoteOnEvent — Type
NoteOnEvent <: MIDIEvent
Событие NoteOnEvent сообщает MIDI-устройству о необходимости сыграть ноту. Событие NoteOnEvent с скоростью 0 действует как NoteOffEvent.
Поля:
-
dT::Int: время дельты в импульсах. -
status::UInt8: байт статуса события. -
note::Int: нота, которую следует начать воспроизводить. -
velocity::Int: сила воспроизведения ноты.
#
MIDI.AftertouchEvent — Type
AftertouchEvent <: MIDIEvent
Событие AftertouchEvent информирует MIDI-устройство о том, что на ноту было оказано давление.
Поля:
-
dT::Int: время дельты в импульсах. -
status::UInt8: байт статуса события. -
note::Int: нота, к которой применяется давление. -
pressure::Int: величина применяемого давления.
#
MIDI.ControlChangeEvent — Type
ControlChangeEvent <: MIDIEvent
Событие ControlChangeEvent информирует MIDI-устройство об изменении значения контроллера.
Поля:
-
dT::Int: время дельты в импульсах. -
status::UInt8: байт статуса события. -
controller::Int: номер контроллера. -
value::Int: значение, полученное контроллером.
#
MIDI.ProgramChangeEvent — Type
ProgramChangeEvent <: MIDIEvent
Событие ProgramChangeEvent информирует MIDI-устройство о выборе номера программы в определенном канале.
Поля:
-
dT::Int: время дельты в импульсах. -
status::UInt8: байт статуса события. -
program::Int: номер новой программы.
#
MIDI.ChannelPressureEvent — Type
ChannelPressureEvent <: MIDIEvent
Событие ChannelPressureEvent информирует MIDI-устройство о необходимости применить давление к определенному каналу.
Поля:
-
dT::Int: время дельты в импульсах. -
status::UInt8: байт статуса события. -
pressure::Int: величина применяемого давления.
#
MIDI.PitchBendEvent — Type
PitchBendEvent <: MIDIEvent
Событие PitchBendEvent информирует MIDI-устройство об изменении высоты тона в определенном канале.
Поля:
-
dT::Int: время дельты в импульсах. -
status::UInt8: байт статуса события. -
pitch::Int: значение изменения высоты тона.
Вспомогательные функции
#
MIDI.qpm — Function
qpm(midi)
Возвращает исходное значение QPM (количество четвертных нот в минуту), с которым был экспортирован файл MIDIFile. Это значение является постоянным и не меняется даже при возникновении события изменения темпа. Если значение не найдено, возвращается 120. Чтобы получить список QPM с течением времени, используйте функцию tempochanges.
#
MIDI.bpm — Function
bpm(midi)
Возвращает BPM, в который был экспортирован заданный MIDIFile. Возвращает QPM, если он не найден.
#
MIDI.ms_per_tick — Function
ms_per_tick(tpq, qpm)
ms_per_tick(midi::MIDIFile)
Возвращает количество миллисекунд, которое составляет один тик, исходя из количества четвертных нот в минуту qpm и тиков на четверть ноты tpq.
#
MIDI.addevent! — Function
addevent!(track::MIDITrack, time::Int, event::TrackEvent)
Добавляет событие в track в заданное время time. time указывается в абсолютном времени, а не в относительном.
Чтобы добавить несколько событий за один раз, используйте вместо этого функцию addevents!.
#
MIDI.addevents! — Function
addevents!(track::MIDITrack, times, events)
Добавляет заданные события events в указанную дорожку track в указанные моменты времени times с внутренним преобразованием абсолютного времени в относительное.
Использование этой функции эффективнее, чем цикл по отдельным вызовам addevent!.
#
MIDI.trackname — Function
trackname(track::MIDI.MIDITrack)
Возвращает название дорожки track в виде строки, находя TrackNameEvent.
Если такого события нет, возвращается сообщение "No track name found".
#
MIDI.addtrackname! — Function
addtrackname!(track::MIDI.MIDITrack, name::String)
Добавляет название для дорожки track, присоединяя TrackNameEvent к началу track.
#
MIDI.findtextevents — Function
findtextevents(eventtype, track)
Находит все текстовые события, указанные в поле по eventtype в track. В качестве eventtype могут быть указаны TextEvent, LyricEvent, MarkerEvent, что позволит найти соответствующие мета-события.
Для удобства эта функция не возвращает сами события. Вместо этого она возвращает три вектора: первый — это строки событий, второй — индексы событий в track, а третий — абсолютная позиция событий (от начала track).
Примечание. Распространенные редакторы музыкальных партитур, такие как MuseScore, GuitarPro и т. д., не экспортируют тексты песен и текстовую информацию при экспорте MIDI-файлов.
Примечание. Cubase может считывать события маркеров, а MuseScore — события текстов песен. На данный момент нам не известен ни один редактор, который мог бы считывать текстовые события.
#
MIDI.tempochanges — Function
tempochanges(midi)
Возвращает вектор кортежей (position, tempo) для всех темповых событий в данном MIDIFile, где position - абсолютное время (от начала файла) в тиках, а tempo - четверть ноты в минуту. Возвращает [(0, 120.0)], если темповые события отсутствуют.
Низкоуровневый API
В этом разделе демонстрируется низкоуровневый API, который позволяет считывать байты из файла и преобразовывать их в структуры Julia.
#
MIDI.readvariablelength — Function
readvariablelength(f::IO)
Числа переменной длины в MIDI-файлах представлены в виде последовательности байтов. Если первый бит равен 0, то перед нами последний байт в последовательности. Остальные 7 бит указывают на номер.
Другие полезные функции, которые не экспортируются:
writeevent
readMIDIevent
readmetaevent
readsysexevent
get_abs_pos
Наконец, сведения о типах сообщений, типах событий и т. д. см. в файле MIDI/src/constants.jl.
MIDI: минимальные необходимые знания
Этот раздел представляет собой краткий курс по формату MIDI. Дополнительные сведения см. на странице в Википедии, в официальных спецификациях MIDI и в подробном руководстве на сайте recordingblogs.com.
MIDI-файл обычно состоит из частей, называемых дорожками, которые воспроизводятся одновременно. Каждая дорожка может иметь 16 различных каналов с номерами от 0 до 15. Каждый канал можно рассматривать как отдельный инструмент, хотя на протяжении дорожки этот инструмент может меняться. Дорожка содержит события. Есть три типа событий: MIDI-события, метасобытия и эксклюзивные системные события (SYSEX). Время наступления каждого события отсчитывается с момента последнего события (dT) в импульсах. Количество импульсов на четвертную ноту указывается в параметре tpq MIDI-файла (MIDIFile.tpq, см. описание MIDIFile).
-
События MIDI связаны как с самими нотами, так и со звуковой текстурой, например способом воспроизведения ноты или перемещением колеса высоты тона.
-
Метасобытия связаны с добавлением текста об авторских правах, сведений об авторстве, название дорожек и т. д.
-
События SYSEX служат для передачи произвольных данных. Их содержимое зависит от предполагаемого получателя.