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

Базовые структуры MIDI

Файлы MIDI загружаются на диск или с диска и преобразуются в структуру Julia MIDIFile, которая содержит объекты MIDITrack.

Ввод-вывод 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

MIDIFile <: Any

Тип, представляющий файл с данными MIDI.

Поля

  • format::UInt16: формат файла. Может иметь значение 0, 1 или 2.

  • tpq::Int16: временное деление дорожки, количество импульсов на четвертную ноту.

  • tracks::Array{MIDITrack, 1}: массив содержащихся дорожек.

MIDITrack

Наиболее важное поле MIDIFile — tracks. Оно содержит столько дорожек, сколько пожелает пользователь. Дорожки содержат всю «музыкальную» информацию в виде «событий», о которых мы упоминали в разделе MIDI: минимальные необходимые знания.

MIDITrack <: Any

Объект MIDITrack — это просто контейнер для TrackEvents, так как его единственное поле — events::Vector{TrackEvent}.

Фрагменты дорожки начинаются с четырех байтов, которые записываются как «MTrk», за которыми следуют длина дорожки в байтах (см. описание readvariablelength) и последовательность событий.

MIDITrack реализует функции isempty и empty!.

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-события ниже.

Обычно наиболее важная информация MIDITrack содержится в нотах. По этой причине существуют специальные функции getnotes и addnotes!, которые описываются на странице Ноты.

Метасобытия

SequenceNumberEvent <: MetaEvent

Событие SequenceNumberEvent содержит номер последовательности в MIDI-файлах типов 0 и 1, или номер паттерна в MIDI-файлах типа 2.

Поля:

  • dT::Int: время дельты в импульсах.

  • metatype::UInt8: байт метатипа события.

  • number::Int: порядковый номер.

TextEvent <: MetaEvent

Событие TextEvent содержит текст в MIDI-файле.

Поля:

  • dT::Int: время дельты в импульсах.

  • metatype::UInt8: байт метатипа события.

  • text::String: текст события.

CopyrightNoticeEvent <: MetaEvent

Событие CopyrightNoticeEvent содержит уведомление об авторских правах в MIDI-файле.

Поля:

  • dT::Int: время дельты в импульсах.

  • metatype::UInt8: байт метатипа события.

  • text::String: уведомление об авторских правах в тексте.

TrackNameEvent <: MetaEvent

Событие TrackNameEvent содержит либо имя MIDI-последовательности (в файлах MIDI типа 0 или MIDI типа 2, или в первой дорожке файла MIDI типа 1), либо имя MIDI-дорожки (в других дорожках файла MIDI типа 1).

Поля:

  • dT::Int: время дельты в импульсах.

  • metatype::UInt8: байт метатипа события.

  • text::String: название дорожки в тексте.

InstrumentNameEvent <: MetaEvent

Событие InstrumentNameEvent содержит имя инструмента, который будет использоваться в треке.

Поля:

  • dT::Int: время дельты в импульсах.

  • metatype::UInt8: байт метатипа события.

  • text::String: название инструмента в тексте.

LyricEvent <: MetaEvent

Событие LyricEvent содержит текст песни (обычно слоги) в MIDI-файле.

Поля:

  • dT::Int: время дельты в импульсах.

  • metatype::UInt8: байт метатипа события.

  • text::String: текст песни.

MarkerEvent <: MetaEvent

Событие MarkerEvent содержит текст маркера.

Поля:

  • dT::Int: время дельты в импульсах.

  • metatype::UInt8: байт метатипа события.

  • text::String: текст маркера.

CuePointEvent <: MetaEvent

Событие CuePointEvent содержит реплику в MIDI-файле.

Поля:

  • dT::Int: время дельты в импульсах.

  • metatype::UInt8: байт метатипа события.

  • text::String: сигнал в тексте.

MIDIChannelPrefixEvent <: MetaEvent

Событие MIDIChannelPrefixEvent содержит номер канала, на который отправляются следующие мета-сообщения.

Поля:

  • dT::Int: время дельты в импульсах.

  • metatype::UInt8: байт метатипа события.

  • channel::Int: номер канала.

EndOfTrackEvent <: MetaEvent

Событие EndOfTrackEvent обозначает конец трека.

Поля:

  • dT::Int: время дельты в импульсах.

  • metatype::UInt8: байт метатипа события.

SetTempoEvent <: MetaEvent

Событие SetTempoEvent устанавливает темп MIDI-последовательности в микросекундах на четверть ноты.

Поля:

  • dT::Int: время дельты в импульсах.

  • metatype::UInt8: байт метатипа события.

  • tempo::Int: темп в микросекундах на четвертную ноту.

TimeSignatureEvent <: MetaEvent

Событие TimeSignatureEvent содержит временную подпись MIDI-последовательности.

Поля:

  • dT::Int: время дельты в импульсах.

  • metatype::UInt8: байт метатипа события.

  • numerator::Int: числитель тактового размера.

  • denominator::Int: знаменатель тактового размера.

  • clockticks::Int: количество импульсов MIDI-часов за один отсчет метронома.

  • notated32nd_notes::Int: количество тридцать вторых нот на долю.

KeySignatureEvent <: MetaEvent

Событие KeySignatureEvent содержит ключевую подпись и шкалу MIDI-файла.

Поля:

  • dT::Int: время дельты в импульсах.

  • metatype::UInt8: байт метатипа события.

  • semitones::Int: количество бемолей или диезов.

  • scale::Int: тональность MIDI-файла; 0, если тональность мажорная, 1, если тональность минорная.

MIDI-события

NoteOffEvent <: MIDIEvent

Событие NoteOffEvent информирует MIDI-устройство об освобождении ноты.

Поля:

  • dT::Int: время дельты в импульсах.

  • status::UInt8: байт статуса события.

  • note::Int: нота, которую следует перестать воспроизводить.

  • velocity::Int: сила воспроизведения ноты.

NoteOnEvent <: MIDIEvent

Событие NoteOnEvent сообщает MIDI-устройству о необходимости сыграть ноту. Событие NoteOnEvent с скоростью 0 действует как NoteOffEvent.

Поля:

  • dT::Int: время дельты в импульсах.

  • status::UInt8: байт статуса события.

  • note::Int: нота, которую следует начать воспроизводить.

  • velocity::Int: сила воспроизведения ноты.

AftertouchEvent <: MIDIEvent

Событие AftertouchEvent информирует MIDI-устройство о том, что на ноту было оказано давление.

Поля:

  • dT::Int: время дельты в импульсах.

  • status::UInt8: байт статуса события.

  • note::Int: нота, к которой применяется давление.

  • pressure::Int: величина применяемого давления.

ControlChangeEvent <: MIDIEvent

Событие ControlChangeEvent информирует MIDI-устройство об изменении значения контроллера.

Поля:

  • dT::Int: время дельты в импульсах.

  • status::UInt8: байт статуса события.

  • controller::Int: номер контроллера.

  • value::Int: значение, полученное контроллером.

ProgramChangeEvent <: MIDIEvent

Событие ProgramChangeEvent информирует MIDI-устройство о выборе номера программы в определенном канале.

Поля:

  • dT::Int: время дельты в импульсах.

  • status::UInt8: байт статуса события.

  • program::Int: номер новой программы.

ChannelPressureEvent <: MIDIEvent

Событие ChannelPressureEvent информирует MIDI-устройство о необходимости применить давление к определенному каналу.

Поля:

  • dT::Int: время дельты в импульсах.

  • status::UInt8: байт статуса события.

  • pressure::Int: величина применяемого давления.

PitchBendEvent <: MIDIEvent

Событие PitchBendEvent информирует MIDI-устройство об изменении высоты тона в определенном канале.

Поля:

  • dT::Int: время дельты в импульсах.

  • status::UInt8: байт статуса события.

  • pitch::Int: значение изменения высоты тона.

Вспомогательные функции

qpm(midi)

Возвращает исходное значение QPM (количество четвертных нот в минуту), с которым был экспортирован файл MIDIFile. Это значение является постоянным и не меняется даже при возникновении события изменения темпа. Если значение не найдено, возвращается 120. Чтобы получить список QPM с течением времени, используйте функцию tempochanges.

bpm(midi)

Возвращает BPM, в который был экспортирован заданный MIDIFile. Возвращает QPM, если он не найден.

ms_per_tick(tpq, qpm)
ms_per_tick(midi::MIDIFile)

Возвращает количество миллисекунд, которое составляет один тик, исходя из количества четвертных нот в минуту qpm и тиков на четверть ноты tpq.

addevent!(track::MIDITrack, time::Int, event::TrackEvent)

Добавляет событие в track в заданное время time. time указывается в абсолютном времени, а не в относительном.

Чтобы добавить несколько событий за один раз, используйте вместо этого функцию addevents!.

addevents!(track::MIDITrack, times, events)

Добавляет заданные события events в указанную дорожку track в указанные моменты времени times с внутренним преобразованием абсолютного времени в относительное.

Использование этой функции эффективнее, чем цикл по отдельным вызовам addevent!.

trackname(track::MIDI.MIDITrack)

Возвращает название дорожки track в виде строки, находя TrackNameEvent.

Если такого события нет, возвращается сообщение "No track name found".

addtrackname!(track::MIDI.MIDITrack, name::String)

Добавляет название для дорожки track, присоединяя TrackNameEvent к началу track.

findtextevents(eventtype, track)

Находит все текстовые события, указанные в поле по eventtype в track. В качестве eventtype могут быть указаны TextEvent, LyricEvent, MarkerEvent, что позволит найти соответствующие мета-события.

Для удобства эта функция не возвращает сами события. Вместо этого она возвращает три вектора: первый — это строки событий, второй — индексы событий в track, а третий — абсолютная позиция событий (от начала track).

Примечание. Распространенные редакторы музыкальных партитур, такие как MuseScore, GuitarPro и т. д., не экспортируют тексты песен и текстовую информацию при экспорте MIDI-файлов.

Примечание. Cubase может считывать события маркеров, а MuseScore — события текстов песен. На данный момент нам не известен ни один редактор, который мог бы считывать текстовые события.

tempochanges(midi)

Возвращает вектор кортежей (position, tempo) для всех темповых событий в данном MIDIFile, где position - абсолютное время (от начала файла) в тиках, а tempo - четверть ноты в минуту. Возвращает [(0, 120.0)], если темповые события отсутствуют.

Низкоуровневый API

В этом разделе демонстрируется низкоуровневый API, который позволяет считывать байты из файла и преобразовывать их в структуры Julia.

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 служат для передачи произвольных данных. Их содержимое зависит от предполагаемого получателя.