Передача MIDI даних у комп'ютер

Передача одиничного потоку даних

Від одного сенсора передати дані з Arduino в Max/MSP дуже просто. Для прикладу візьмемо потенціометр і підключимо його до pin 0 контролера Arduino. Контролер буде зчитувати стан потенціометра та передавати дані послідовним потоком до комп'ютера в ПО Max/MSP. Діапазон чисел від потенціометра буде лежати в межах 0-127, що якраз підходить для MIDI.

Як тільки дані прийняті Max/MSP, вони одразу ж будуть перенаправлені на об'єкт ctlout, що дає можливість контролювати будь-який параметр в будь-якому застосунку, який приймає MIDI дані.

Підключення потенціометра до Arduino

Скетч для Arduino дуже простий:

byte val;

void setup() { 
Serial.begin(57600); // Відкриваємо послідовний вивід даних
} 

void loop() { 
val = analogRead(0) / 8; // зчитуємо значення потенціометра та перетворюємо до діапазону 0 - 127 
Serial.print(val, BYTE); // віддаємо значення в послідовний порт
delay(5); // затримка
}
}

Патч для Max/MSP:

Патч для Max/MSP

Але що робити, якщо потрібно передавати дані від 2-х, 3-х, або відразу 4-х потенціометрів? Ось тут відразу почнуться проблеми. Справа в тому, що в один проміжок часу може передаватися/прийматися лише один байт. І будуть виникати неминучі затримки в передачі даних.

В даному варіанті в першому байті буде міститися інформація від першого потенціометра, у другому байті - від другого. На стороні ПК, в MIDI-секвенсорі буде важко розділити ці дані, та й неефективно.

Передача багатопотокових даних

Одним із рішень даної проблеми є перетворення всіх даних від потенціометрів у MIDI-формат в контролері Arduino, а потім вже передача MIDI-даних з Arduino в Max/MSP.

MIDI структура

Структура MIDI здається складною лише на перший погляд, насправді ви в ній швидко освоїтеся. Кожна дія (взяття ноти, зняття ноти, питч-бенд та ін.) передається у вигляді MIDI-подій. Ми будемо працювати з MIDI-подіями, що складаються з трьох байтів. Відповідно, в кожному байті зберігається 8 біт і ми охоплюємо діапазон від 0 до 255.

Перший байт - статус, за ним йдуть 2 байти з даними. У статусному байті міститься інформація про тип події, яку ми передаємо (взяття ноти, зняття ноти, пауза тощо) і номер каналу від 1 до 16. Байти з даними містять інформацію про дію, наприклад, якщо б натиснули клавішу якоїсь ноти, то дані будуть містити тон ноти та як різко ви її натиснули (velocity): Status Byte; Data Byte #1; Data Byte #2;

Байт статусу

Статусний байт розділений на два полубайта. Перший полубайт містить біти 4-7 байта, а другий полубайт біти 0-3. Для зручності, прийнято використовувати шістнадцяткову систему числення, таким чином, перший полубайт може містити значення від 0 до F, те ж саме і другий 0-F.

Перший полубайт вказує на тип події:
8 = Note Off
9 = Note On
A = After Touch
B = Control Change
C = Patch Change
D = Channel Pressure
E = Pitch Bend
F = System Message

Другий полубайт вказує на номер каналу:
0 = Канал 1
1 = Канал 2
2 = Канал 3
3 = Канал 4
4 = Канал 5
5 = Канал 6
6 = Канал 7
7 = Канал 8
8 = Канал 9
9 = Канал 10
A = Канал 11
B = Канал 12
C = Канал 13
D = Канал 14
E = Канал 15
F = Канал 16

Якщо поєднати два полубайта, то ми отримаємо всю необхідну інформацію статусного байта про MIDI-дію. Наприклад, якщо потрібно передати інформацію про взяття ноти на 1-му каналі, то значення статусного байта буде 0x90. Префікс 0x вказує на те, що використовується шістнадцяткова система числення, 9 - взяття ноти, 0 - 1 канал. Або, якщо потрібно передати питч-бенд на 3-каналі, то значення статус-байта буде 0xE2.

Байти даних

Після того, як передано статусний байт, потрібно передати два байти з даними. Для того, щоб стало більш зрозуміло, наведу два приклади: у першому буде взяття ноти (note-on), у другому повідомлення контроллера (control change).

При взятті ноти в байті #1 міститься значення тону (pitch) в діапазоні 0-127. В байті #2 міститься значення velocity також в діапазоні 0-127. Наприклад, якщо потрібно передати взяття ноти на 3 каналі з pitch 60 та velocity 123, то послідовність байтів для передачі буде наступною:
0x92
60
123
У статусному байті 9 вказує на взяття ноти, 2 - третій канал. У наступному байті #1 цифра 60 вказує на тон, у байті #2 цифра 123 - значення velocity. Якщо передається взяття ноти (note-on), але зі значенням velocity - 0, то це рівносильно зняттю ноти (note-off).

Якщо статусний байт передає повідомлення контроллера, то в 1-му байті міститься номер контроллера 0-127, а в другому його значення 0-127. Наприклад:
0xB4
1
82
Тут значення B в статусному байті вказує, що це повідомлення контроллера (control change), 4 - п'ятий канал. Перший байт даних містить цифру 1, це контролер Modulation. Другий байт містить величину 82 контролера.

Основні контролери MIDI

Modulation (CC #1)
Breath (CC #2)
Foot Pedal (CC #4)
Portamento Time (CC #5)
Volume (CC #7)
Pan (CC #10)
Expression (CC #11)
Soft Pedal (CC #68)

Передача даних з Arduino

Отже, після всього вищезазначеного ми зможемо легко надсилати MIDI-дані з Arduino. Потім ці дані надходять до Max/MSP і далі передаються в virtual MIDI path (IAC Driver Bus 1 під OS X або LooBe1 під Windows), а потім вже в музичне ПО або DAW (Live, Logic, ProTools, Reason).

Наводжу приклади з взяттям ноти та з передачею повідомлення контроллера.

Приклад 1. Відсилаємо подію взяття ноти, пауза 1 сек, зняття ноти, пауза 1 сек.

Arduino

Скетч Arduino:

void setup() { 
Serial.begin(57600);
} 

void loop() { 
// відсилаємо note-on 
Serial.print(0x90, BYTE); // MIDI Note-on; канал 1 
Serial.print(60, BYTE); // MIDI note pitch 60 
Serial.print(127, BYTE); // MIDI note velocity 127 
delay(1000); // пауза 1 сек

// відсилаємо note-off 
Serial.print(0x90, BYTE); // MIDI Note-on; канал 1 
Serial.print(60, BYTE); // MIDI note pitch 60 
Serial.print(0, BYTE); // MIDI note velocity 0 (т.е. note off) 
delay(1000); // пауза 1 сек
}

Патч для Max/MSP:

Патч для Max/MSP

Приклад 2. Відсилаємо подію контроллера кожну секунду

Arduino

Скетч Arduino:

void setup() { 
Serial.begin(57600);
} 

void loop() { 
// відсилаємо повідомлення контроллера
Serial.print(0xB2, BYTE); // MIDI control change; канал 3 
Serial.print(1, BYTE); // MIDI controller #1 
Serial.print(127, BYTE); // MIDI controller value of 127 
delay(1000); // пауза 1 сек
}

Патч для Max/MSP:

Патч для Max/MSP

Об'єднуємо все воєдино

Тепер, ми легко можемо зчитувати стан кількох потенціометрів, сформувати та надіслати MIDI-дані в Max/MSP. Розглянемо пару прикладів.

Приклад 1. Зчитуємо значення потенціометрів, підключених до аналогових входів 0 та 1. Ці значення будуть надсилатися в MIDI канал 1, контролер 1 та канал 2, контролер 1.

Arduino і 2 потенціометра

Скетч Arduino:

byte val = 0; 

void setup() { 
Serial.begin(57600);
} 

void loop() { 
val = analogRead(0) / 8; // зчитуємо значення потенціометра 1

// давайте надішлемо повідомлення контролера 
Serial.print(0xB0, BYTE); // MIDI control change; канал 1 
Serial.print(1, BYTE); // MIDI controller #1 
Serial.print(val, BYTE); // MIDI controller значення потенціометра 1 

val = analogRead(1) / 8; // зчитуємо значення потенціометра 2 

// давайте надішлемо повідомлення контролера 
Serial.print(0xB1, BYTE); // MIDI control change; канал 2 
Serial.print(1, BYTE); // MIDI controller #1 
Serial.print(val, BYTE); // MIDI controller значення потенціометра 2 
delay(5); 
}

Патч для Max/MSP:

Патч для Max/MSP

Приклад 2. Зчитуємо значення з 6 потенціометрів та передаємо дані контроллера 1 в канал 1, 2, 3, 4, 5 та 6.

Arduino і 6 потенціометров

Скетч Arduino:

byte val = 0; 

void setup() { 
Serial.begin(57600);
} 

void loop() { 
for(int i = 0; i < 6; i ++) { 
val = analogRead(i) / 8; // зчитуємо значення потенціометрів
// (на аналогових входах 0 - 5) 

// відправляємо повідомлення контролера

Serial.print(0xB0 + i, BYTE); // MIDI control change; номер каналу 
Serial.print(1, BYTE); // MIDI controller #1 
Serial.print(val, BYTE); // MIDI controller значення від потенціометра 
delay(1); // пауза
} 
}

Патч для Max/MSP:

Патч для Max/MSP

Оригінал статті

Top