Події MIDI

Подія MIDI це пакет даних, який визначає якесь музичне дію, таке як натискання або відпускання клавіші Перший байт пакета 6aйm cmamyca, визначальний тип події і, у відповідних випадках, канал B байтах статусу старший біт завжди встановлений в 1 Решта байти даних, в яких старший біт ніколи не встановлюється Ця відмінна особливість вельми важлива

B табл 222 наводиться зведена інформація за повідомленнями MIDI, в фай-

лах Standard MIDI Зауважте, що події з кодами від 0x80 до 0xEF використовують молодші чотири біти для завдання каналу Події 0xF0, 0xF7 і 0xFF мають спеціальне призначення, яке я поясню пізніше Також зверніть увагу на те, що ці події неідентичні тим, що застосовуються в канальному протоколі MIDI B Зокрема, канальний протокол по-іншому використовує події 0xF7 і 0xFF і визначає кілька інших байтів статусу для подій з кодами вище 0xF0

Угоди з нумерації

За традицією канали MIDI нумеруються від 1 до 16, а інструменти MIDI від 1

до 128 Однак числові коди, відповідно, варіюються в діапазоні від 0 до

15 і від 0 до 127

При взаємних перетвореннях численних кодів і умовних значень мови

MIDI потрібно додати або відняти одиницю

Наведу конкретний приклад: подія MIDI 0xC0 0x00 вибирає інструмент

1 (НЕ 0) на каналі 1 (НЕ 0) Аналогічним чином, для вибору інструменту 128 на каналі 16 ви посилаєте подія 0xCF 0xFF

Статус виконання

Щоб зробити канальний протокол більш ефективним, в MIDI застосовується технологія, звана статусом виконання B відповідності з нею повторювані байти статусу пропускаються Якщо при читанні файлів MIDI ви бачите байт даних на тому місці, де чекали зустріти байт статусу, ви заново використовуєте попереднє значення статусу

Наведу конкретний приклад Шістнадцяткові значення 0x90 0x3C 0x40

формують подія включення для ноти 0x3C (середнє До) з середнім значенням

Таблиця 222 Коди подій MIDI, використовувані в файлах Standard MIDI

Код Опис

(Шістнадцятковий)

8c nn vv                                 Вимкнення ноти nn зі швидкістю vv на каналі з

9c nn vv                                 Включення ноти nn зі швидкістю vv на каналі з

Ac nn vv Поліфонічний ключ впливу послекасания

На w змінює вплив (зазвичай вібрато) на ноту nn (Яка вже програється) на каналі з

Bc mm ss                              Міняє режим каналу з з mm на vv

Cc ii Зміна програми

Вибирає звучання інструменту ii для каналу з

Dc vv                                     Змінює вплив на каналі

Змінює на і / вплив для всіх нот, що програються на каналі з

Ec ff cc Регулятор зміни висоти тону

Змінює висоту всіх нот, що програються на каналі з

по визначеному співвідношенню ft містить молодші 7 біт,

cc старший біт

F0 довжина даних Системне ексклюзивне повідомлення (SOX) Довжина ціле значення змінної довжини, визначальне довжину наступних даних

F7 довжина даних Спеціальне системне ексклюзивне повідомлення

Довжина ціле значення змінної довжини, визначальне довжину наступних даних

FF tt довжина даних Метасобитіе типу tt

Довжина ціле значення змінної довжини, визначальне довжину наступних даних

швидкості Якщо наступна подія починається з 0x40, то, оскільки це байт даних, ви заново використовуєте значення статусу 0x90 Це відповідає ще одній події включення ноти Пропуск загальних значень статусу дозволяє обробляти акорди швидше Даний метод широко використовується у файлах формату Standard MIDI, так як дозволяє економити місце на диску

Щоб зробити метод безперервного статусу ще більш ефективним, прийнято угоду про те, що подія включення ноти зі швидкістю 0 ідентично події вимикання ноти зі стандартною швидкістю 64 Таким чином, для управління довгим ланцюжком нот на одному каналі потрібно всього два байти на подію

Управління подіями MIDI

Особливістю записаних у форматі MIDI даних є притаманна їм залежність синхронізації від того, як дані зчитуються B Зокрема, файли MIDI часто зберігаються як кілька незалежних доріжок Хоча події на кожній доріжці знаходяться в хронологічному порядку, що програється потік подій являє собою комбінацію всіх цих доріжок K того ж події на одній доріжці (Такі як зміни темпу) впливають на відтворення подій на інших доріжках

B результаті перш ніж програвати файл першого типу, необхідно вважати в память всі події C цією метою я пропоную використовувати один звязаний список подій MIDI

Лістинг 226 Змінні списку подій MIDI

private:

MidiEvent * _events / / Список всіх подій у пісні

MidiEvent * _currentEvent / / Оброблюване поточну подію

Більшість подій складається з байта статусу і пари байтів даних Крім того, необхідно зберігати величину затримки і номер доріжки, на якій сталася подія

Деякі спеціальні події MIDI можуть містити довільні обсяги даних, тому я описав додаткову структуру, призначену для зберігання таких даних у разі потреби

Лістинг 227 Структура події MIDI

struct MidiExtendedEventData {

long length AudioByte *data

/ / Конструктор і деструктор

MidiExtendedEventData() { data = 0 }

~MidiExtendedEventData() { if (data) delete [] data }

}

struct MidiEvent { MidiEvent *next

unsigned long delay / / Затримка

/ / Щодо попереднього події

unsigned char track / / Кількість доріжок

/ / Для цієї події

unsigned char status / / Байт статусу події unsigned char data [2] / / Дані події MIDI MidiExtendedEventData * metaData / / Область для довгих

/ / Даних типу системних

/ / Повідомлень і тд

MidiEvent () {/ / Конструктор

next = 0

metaData = 0

delay = track = status = 0

}

~ MidiEvent () {/ / Деструктор if (metaData)

delete metaData

}

}

Читання подій MIDI

Більшість подій MIDI має фіксовану довжину Наприклад, активизирующее ноту завжди має два байти даних, наступних за байтом статусу Щоб спростити процедуру читання більшості подій, я пропоную використовувати невелику таблицю Для роботи з безперервним статусом застосовується pLastEvent, який вказує на останнє лічену з цієї доріжки подія

Лістинг 228 Читання події MIDI

{ static const char eventLength[] = {

2, 2,

2, 2,

2,

2, 2,

2,

2,

2,

2,

2, 2,

2,

2,

2,

//

0x80

0x8F

2, 2,

2, 2,

2,

2, 2,

2,

2,

2,

2,

2, 2,

2,

2,

2,

//

0x90

0x9F

2, 2,

2, 2,

2,

2, 2,

2,

2,

2,

2,

2, 2,

2,

2,

2,

//

0xA0

0xAF

2, 2,

2, 2,

2,

2, 2,

2,

2,

2,

2,

2, 2,

2,

2,

2,

//

0xB0

0xBF

1, 1,

1, 1,

1,

1, 1,

1,

1,

1,

1,

1, 1,

1,

1,

1,

//

0xC0

0xCF

1, 1,

1, 1,

1,

1, 1,

1,

1,

1,

1,

1, 1,

1,

1,

1,

//

0xD0

0xDF

2, 2,

2, 2,

2,

2, 2,

2,

2,

2,

2,

2, 2,

2,

2,

2,

//

0xE0

0xEF

0, 0,

2, 1,

0,

0, 0,

0,

0,

0,

0,

0, 0,

0,

0,

0,

//

0xF0

0xFF

}

int sizeRead

pEvent-> delay = ReadVarInt (_stream, & sizeRead) bytesRemaining = sizeRead / / Враховуємо дельта-час, int dataRead = 0 / / Кількість прочитаних на

/ / Поточний момент байтів

int byte = _streamget()

bytesRemaining – / / Враховуємо цей байт

if (byte> = 0x80) {/ / Це новий статус

pEvent-&gtstatus = byte

} Else {/ / Безперервний статус

pEvent-> status = pLastEvent-> status / / Заново використовуємо

/ / Попереднє

/ / Значення статусу

pEvent-> data [dataRead + +] = byte / / Це перший байт даних

}

while(dataRead &lt eventLength[pEvent-&gtstatus 0x80]) { pEvent-&gtdata[dataRead++] = _streamget() bytesRemaining–

}

}

Ексклюзивні системні повідомлення

Подія 0xF0 використовується для передачі ряду спеціальних команд, званихексклюзивними системними повідомленнями(System-Exclusive messages або sysex events) Їх загальний формат наведено в табл 223

Ці події обробляються в файлах Standard MIDI не так, як в канальному протоколі B файлі Standard MIDI, як показано в табл 222, за статусним значенням 0xF0 слід поле довжини і відповідну кількість даних B результаті ексклюзивне системне повідомлення може містити будь-яку кількість байтів

При використанні в канальному протоколі поле довжини відсутня Ознакою кінця області даних є поява наступного статусного значення У всіх байтів в ексклюзивному повідомленні старший біт буде очищений Також відзначимо, що для даних повідомлень метод безперервного статусу непридатний

B MIDI-файлі подія 0xF7 являє собою засіб організації переходів, завдяки яким ми можемо включати у файл будь двійкові дані Внутрішня структура аналогічна структурі системного ексклюзивного повідомлення 0xF0 При посилці файлу MIDI на синтезатор в останній повинна скидатися область даних події 0xF7 Сам статусний байт 0xF7 не передається Це зручно, якщо ви працюєте з синтезаторами, які предявляють вимоги по синхронізації ексклюзивних повідомлень Ha таких синтезаторах ми можемо використовувати одна подія 0xF0 для зберігання першій частині даного

Таблиця 223 Формат системного ексклюзивного повідомлення

Байти Опис

1 Статусний байт 0xF0 (початок ексклюзивного системного повідомлення SOX)

m            Довжина наступних даних (тільки у файлі MIDI), що зберігається як ціле змінної довжини

1-3 Ідентифікатор виробника

Якщо перший байт дорівнює нулю, це 3-байтний ідентифікатор в іншому випадку –

однобайтное 0x7D зарезервовано для експериментального

використання, 0x7E застосовується для стандартних повідомлень не в реальному часі, 0x7F для стандартних повідомлень в реальному часі

n             Байти даних

Як і у всіх подіях MIDI, всі байти даних в системному ексклюзивному повідомленні (включаючи описаний вище ідентифікатор виробника) мають встановлений в нуль старший біт

1 Статусний байт 0xF7 (кінець ексклюзивного системного повідомлення EOX)

Хоча будь статусний байт, за винятком подій реального часу, зазначає кінець системного ексклюзивного повідомлення, рекомендується включати значення

0xF7 після кожного такого повідомлення

повідомлення і події 0xF7 для збереження наступних порцій даних з підходящими затримками між частинами Через те що події 0xF7 проявляють сильну системну залежність, вони досить рідко використовуються в файлах Standard MIDI

B канальному протоколі статусне значення 0xF7 не має асоційованих даних і не виробляє ніякої дії Воно, за традицією, використовується для позначки кінця системного ексклюзивного повідомлення, хоча будь-яке статусне значення могло б застосовуватися в подібних цілях B файли MIDI прийнято включати байт 0xF7 як останній ексклюзивного повідомлення 0xF0 Якщо ж повідомлення розбите на кілька подій файлу MIDI з використанням механізму переходу

0xF7, цей завершальний байт 0xF7 включається тільки останнім подія

Лістинг 229 Читання ексклюзивного системного повідомлення MIDI

/ / Читаємо ексклюзивне повідомлення з потоку _stream:

/ / * Записуємо подія в структуру pEvent

/ / * Відповідним чином зменшуємо значення змінної

// bytesRemaining

if (  (pEvent-&gtstatus == 0xF0)

|| (pEvent-&gtstatus == 0xF7) ) {

int sizeRead

unsigned long msgLength = ReadVarInt(_stream,&ampsizeRead)

bytesRemaining-= sizeRead

pEvent-&gtmetaData = new MidiExtendedEventData

pEvent-&gtmetaData-&gtlength = msgLength

pEvent-&gtmetaData-&gtdata = new AudioByte[msgLength]

_streamread(reinterpret_cast&ltchar *&gt(pEvent-&gtmetaData-&gtdata) , msgLength)

bytesRemaining-= msgLength

}

Метасобитія

Музична партитура це не просто список синхронізованих нот Файли MIDI повинні також містити інформацію про ключі (абсолютній висоті звукоряду), тональностях і про авторські правах Для запису такої інформації у файлах Standard MIDI використовуються спеціальніметасобитія(Meta events) Безліч метасобитій знаходиться на початку доріжки, хоча вони здатні зявлятися в будь-якому місці Наприклад, багато композиції змінюють тональність в середині фрагмента, тому по файлу може бути розподілено безліч метасобитій зміни тональності

За існуючою угодою, у файлі першого типу перший доріжка зарезервована спеціально для певних метасобитій Наприклад, інформація про тональність, розмір та темпі зберігається тільки на першій доріжці Багато інших метасобитія, в тому числі що задають імя доріжки та її порядковий номер, можуть розміщуватися тільки на початку доріжки Метасобитія не використовуються в канальному протоколі MIDl (хоча ексклюзивні повідомлення були додані в сполучний протокол для дублювання багатьох з цих можливостей)

Спосіб зберігання метасобитій всередині файлу дуже схожий на спосіб зберігання ексклюзивних повідомлень Метасобитіе починається не з одного байта 0xF0 або

0xF7, а з 0xFF і байта типу, за якими йдуть довжина і дані

Лістинг 2210 Читання метасобитія MIDI

/ / Читаємо метасобитіе з потоку _stream:

/ / * Записуємо подія в структуру pEvent

/ / * Відповідним чином зменшуємо значення змінної

// bytesRemaining

if (pEvent-&gtstatus == 0xFF) {

pEvent-> data [0] = _streamget () / / Тип метасобитія

bytesRemaining -= 1

int sizeRead

unsigned long msgLength = ReadVarInt(_stream,&ampsizeRead)

bytesRemaining -= sizeRead

pEvent-&gtmetaData = new MidiExtendedEventData

pEvent-&gtmetaData-&gtlength = msgLength

pEvent-&gtmetaData-&gtdata = new AudioByte[msgLength+l]

_streamread(reinterpret_cast&ltchar *&gt(pEvent-&gtmetaData-&gtdata), msgLength) ,·

bytesRemaining -= msgLength

pEvent-> metaData-> data [msgLength] = 0 / / Додаємо нуль-

/ / Термінатор

}

Метасобитіе порядкового номера доріжки (тип 0)

Це метасобитіе містить 2-байтное (16-бітове) значення, яке використовується деякими системами для визначення та вибору музичних послідовностей B файлі нульового або першого типу воно завжди зявляється на початку першої доріжки B файлі другого типу, що містить найчастіше безліч незалежних послідовностей, може виникнути на початку будь доріжки

Текстові метасобитія (типи від 1до 15)

Метасобитія зі значенням типу від 1 до 15 використовуються для зберігання текстових коментарів Як і будь-які інші вони зберігаються у файлі у вигляді 0xFF type len data (тип довжина дані) B табл 224 перераховуються певні нині текстові метасобитія

Лістинг 2211 Перегляд метасобитія

if(pEvent-&gtdata[0] == 3) {

/ / Доріжка ..

cerr &lt&lt &quotTrack &quot &lt&lt static_cast&ltint&gt(pEvent-&gttrack) &lt&lt &quot: "

cerr &lt&lt reinterpret_cast&ltchar *&gt(pEvent-&gtmetaData-&gtdata) &lt&lt &quot\n"

} else if (pEvent-&gtdata[0] &lt 16) {

const char *textPrefix[] = { &quot&quot,

/ / Коментар: Авторські права: Назва доріжки:

&quotComment: &quot, &quotCopyright: &quot, &quotTrack Name: &quot,

Таблиця 224 Текстові метасобитія

Метасобитіе Опис

1 Коментар

2 Повідомлення про авторські права

3 Назва доріжки

4 Назва інструменту

5 Текст пісні

6 Маркер

7 Місце репліки

8-15 Не визначено

/ / Назва інструменту Слова: Маркер: Instrument Name, Lyric:, Marker:,

/ / Місце репліки: Текст: ..

&quotCue Point: &quot, &quotText: &quot, &quotText: &quot, &quotText: &quot,

&quotText: &quot, &quotText: &quot, &quotText: &quot, &quotText: &quot, &quotText: &quot}

cerr &lt&lt textPrefix[ pEvent-&gtdata[0] ]

cerr &lt&lt reinterpret_cast&ltchar *&gt(pEvent-&gtmetaData-&gtdata) &lt&lt &quot\n"

}

Метасобитіе кінця доріжки (тип 47)

Метасобитіе типу 47 позначає кінець доріжки MIDI і не містить даних

Можливо, спочатку вам буде не зовсім зрозуміло, навіщо потрібно спеціальна подія для позначки кінця потоку MIDI Реальна мета події кінця доріжки зберігати значення затримки Деякі файли MIDI, особливо призначені для циклічного програвання, повинні містити паузу в кінці твору Єдиний спосіб гарантувати паузу після закінчення останньої ноти додати ще одна подія Хоча не грає ролі те, яка подія ми використовуємо (з такою ж легкістю це може бути і даремна програма, і зміна режиму), для подібних цілей спеціально призначене метасобитіе кінця доріжки

Метасобитіе завдання темпу (тип 81)

Метасобитіе типу 81 задає швидкість відтворення Тема MIDI визначає тривалість тика в одиницях, рівних довжинічверті ноти MIDl Дані це три байта, які визначають кількість мікросекунд на чверть ноти MIDI (Дивись нижче інформацію по синхронізації MIDI)

Музичний розмір (тип 88)

Метасобитіе завдання музичного розміру містить чотири байти Перші два визначають музичний розмір, наприклад, 3/4 або 6/8 Чисельник зберігається безпосередньо, знаменник як ступінь двійки Наприклад, розмір 6/8 представляється двома байтами: 6 і 3 (23 = 8) Третій байт визначає кількість тактових імпульсів MIDI на один клацання метронома Тактовий імпульс MIDI

становить 1/24 чверті ноти MIDI, а тривалість чверті ноти MIDI визначається в метасобитіях завдання темпу Четвертий байт визначає спосіб запису музики Чверть ноти MIDI може не відповідати чверті ноти в традиційному позначенні вона позначає кількість записуваних тридцять другого часткою ноти в однієї чверті ноти MIDI

Метасобитіе завдання тональності (тип 89)

Перший байт показує кількість діезів (якщо значення позитивне) або бемолів (якщо значення негативне), другий показує, чи маємо ми справу з мажорної (0) або з мінорної (1) тональністю До мажор, наприклад, буде представлено як 0 0

Секвенсорної метасобитія (тип 127)

Секвенсорної метасобитія дозволяють виробникам додавати нестандартні дані у файл MIDI Bo уникнути плутанини перший байт ідентифікує виробника (якщо перший байт дорівнює нулю, то виробника визначають перші три байти) Microsoft, наприклад, використовує секвенсорної метасобитіе сідентіфікатором виробника 0 0 65 для позначки МРС-сумісних файлів MIDI

Джерело: Кінтцель Т Керівництво програміста по роботі зі звуком = A Programmers Guide to Sound: Пер з англ М: ДМК Пресс, 2000 432 с, іл (Серія «Для програмістів»)

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*