Передача MIDI данных от Arduino в компьютер

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

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

Как лишь данные приняты Max/MSP, они сразу же будут перенаправлены на объект ctlout, что дает возможность контроля над любым параметром в любом приложении, которые принимают MIDI данные.

Скетч для Arduino очень прост:

byte val;

void setup() {
Serial.begin(57600); // Открываем последовательный вывод данных
}

void loop() {
val = analogRead(0) / 8; // считываем значение потенциометра и преобразовываем к диапазону 0 — 127
Serial.print(val, BYTE); // отдаем значение в послед. порт
delay(5); // задержка
}
}

Патч для Max/MSP:

Но что делать, если необходимо передавать данные от 2-х, 3-х, или сразу от 4-х потенциометров? Вот тут сразу начнутся проблемы. Дело в том, что в один промежуток времени может передаваться/приниматься лишь один байт. И будут возникать неизбежные задержки в передаче данных.

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

Передача многопоточных данных

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

MIDI структура

Структура MIDI кажется сложной лишь на первый взгляд, на самом деле вы в ней быстро освоитесь. Каждое действие (взятие ноты, снятие ноты, питч-бенд и др.) передается в виде MIDI-событий. Мы будем работать с MIDI-событиями состоящими из 3-х байт. Соответственно в каждом байте хранится 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:

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:

Пример 2. Отсылаем событие контроллера каждую секунду

Скетч 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:

Соединяем все воедино

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

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

Скетч Arduino:

byte val = 0;

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

void loop() {
val = analogRead(0) / 8; // считываем значение потенциометра 1

// let’s send a control change message
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

// let’s send a control change message
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:

Пример 2. Считываем значение с 6 потенциометров и передаем данные контроллера 1 в канал 1, 2, 3, 4, 5 и 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:

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

Добавить комментарий

Ваш адрес email не будет опубликован.