arduino
MIDI-Kommunikation
Suche…
Einführung
In diesem Abschnitt werden einige grundlegende MIDI-Programme beschrieben, die den Umgang mit dem Protokoll zeigen und schrittweise nützliche Funktionen hinzufügen, die komplexere Anwendungen erfordern.
MIDI THRU Beispiel
Der MIDI Thru ist einfach und leicht zu testen. Wenn Sie richtig arbeiten, können Sie Ihr Arduino-Projekt zwischen zwei MIDI-Geräten, MIDI IN und MIDI OUT, installieren und überprüfen, ob die beiden Geräte zusammenarbeiten. Wenn Sie die Latenz messen können, sehen Sie eine Zunahme aufgrund der Anweisungen zum Erfassen und erneuten Übertragen des Puffers.
// This is a simple MIDI THRU. Everything in, goes right out.
// This has been validate on an Arduino UNO and a Olimex MIDI Shield
boolean byteReady;
unsigned char midiByte;
void setup() {
// put your setup code here, to run once:
// Set MIDI baud rate:
Serial.begin(31250);
byteReady = false;
midiByte = 0;
}
// The Loop that always gets called...
void loop() {
if (byteReady) {
byteReady = false;
Serial.write(midiByte);
}
}
// The little function that gets called each time loop is called.
// This is automated somwhere in the Arduino code.
void serialEvent() {
if (Serial.available()) {
// get the new byte:
midiByte = (unsigned char)Serial.read();
byteReady = true;
}
}
MIDI durch Warteschlange
// This is a more complex MIDI THRU. This version uses a queue. Queues are important because some
// MIDI messages can be interrupted for real time events. If you are generating your own messages,
// you may need to stop your message to let a "real time" message through and then resume your message.
#define QUEUE_DEPTH 128
// Queue Logic for storing messages
int headQ = 0;
int tailQ = 0;
unsigned char tx_queue[QUEUE_DEPTH];
void setup() {
// put your setup code here, to run once:
// Set MIDI baud rate:
Serial.begin(31250);
}
// getQDepth checks for roll over. Folks have told me this
// is not required. Feel free to experiment.
int getQDepth() {
int depth = 0;
if (headQ < tailQ) {
depth = QUEUE_DEPTH - (tailQ - headQ);
} else {
depth = headQ - tailQ;
}
return depth;
}
void addQueue (unsigned char myByte) {
int depth = 0;
depth = getQDepth();
if (depth < (QUEUE_DEPTH-2)) {
tx_queue[headQ] = myByte;
headQ++;
headQ = headQ % QUEUE_DEPTH; // Always keep the headQ limited between 0 and 127
}
}
unsigned char deQueue() {
unsigned char myByte;
myByte = tx_queue[tailQ];
tailQ++;
tailQ = tailQ % QUEUE_DEPTH; // Keep this tailQ contained within a limit
// Now that we dequeed the byte, it must be sent.
return myByte;
}
void loop() {
if (getQDepth>0) {
Serial.write(deQueue());
}
}
// The little function that gets called each time loop is called.
// This is automated somwhere in the Arduino code.
void serialEvent() {
if (Serial.available()) {
// get the new byte:
addQueue((unsigned char)Serial.read());;
}
}
MIDI Clock Generation
// This is a MiDI clk generator. This takes a #defined BPM and
// makes the appropriate clk rate. The queue is used to let other messages
// through, but allows a clock to go immediately to reduce clock jitter
#define QUEUE_DEPTH 128
#define BPM 121
#define MIDI_SYSRT_CLK 0xF8
// clock tracking and calculation
unsigned long lastClock;
unsigned long captClock;
unsigned long clk_period_us;
// Queue Logic for storing messages
int headQ = 0;
int tailQ = 0;
unsigned char tx_queue[QUEUE_DEPTH];
void setup() {
// Set MIDI baud rate:
Serial.begin(31250);
clk_period_us = 60000000 / (24 * BPM);
lastClock = micros();
}
// getQDepth checks for roll over. Folks have told me this
// is not required. Feel free to experiment.
int getQDepth() {
int depth = 0;
if (headQ < tailQ) {
depth = QUEUE_DEPTH - (tailQ - headQ);
} else {
depth = headQ - tailQ;
}
return depth;
}
void addQueue (unsigned char myByte) {
int depth = 0;
depth = getQDepth();
if (depth < (QUEUE_DEPTH-2)) {
tx_queue[headQ] = myByte;
headQ++;
headQ = headQ % QUEUE_DEPTH; // Always keep the headQ limited between 0 and 127
}
}
unsigned char deQueue() {
unsigned char myByte;
myByte = tx_queue[tailQ];
tailQ++;
tailQ = tailQ % QUEUE_DEPTH; // Keep this tailQ contained within a limit
// Now that we dequeed the byte, it must be sent.
return myByte;
}
void loop() {
captClock = micros();
if (lastClock > captClock) {
// we have a roll over condition - Again, maybe we don't need to do this.
if (clk_period_us <= (4294967295 - (lastClock - captClock))) {
// Add a the ideal clock period for this BPM to the last measurement value
lastClock = lastClock + clk_period_us;
// Send a clock, bypasing the transmit queue
Serial.write(MIDI_SYSRT_CLK);
}
} else if (clk_period_us <= captClock-lastClock) {
// Basically the same two commands above, but not within a roll over check
lastClock = lastClock + clk_period_us;
// Send a clock, bypasing the transmit queue
Serial.write(MIDI_SYSRT_CLK);
}
if (getQDepth>0) {
Serial.write(deQueue());
}
}
// The little function that gets called each time loop is called.
// This is automated somwhere in the Arduino code.
void serialEvent() {
if (Serial.available()) {
// get the new byte:
addQueue((unsigned char)Serial.read());;
}
}
MIDI-Nachrichten definiert
Im Allgemeinen wird das MIDI-Protokoll in "Messages" unterteilt. Es gibt 4 allgemeine Nachrichtenklassen:
- Kanalstimme
- Kanalmodus
- System allgemein
- System-Echtzeitnachrichten
Meldungen beginnen mit einem Byte-Wert über 0x80. Jeder Wert unter 0x7F gilt als Daten. Bedeutet effektiv, dass 127 der maximale Wert ist, der in ein einzelnes MIDI-Datenbyte codiert werden kann. Um größere Werte zu kodieren, sind zwei oder mehr MIDI-Datenbytes erforderlich.
Es sollte darauf hingewiesen werden, dass Nachrichten ohne Unterbrechung gesendet werden müssen, bis sie beendet werden. AUSNAHME ... System-Echtzeitnachrichten, bei denen es sich um ein einzelnes Byte handelt, das mitten in eine Nachricht eingefügt werden kann.
Kanal-Sprachnachrichten
Status D7..D0 | Datenbytes | Beschreibung |
---|---|---|
1000nnnn | 0kkkkkkk 0vvvvvvv | Note Off event.Diese Nachricht wird gesendet, wenn eine Notiz freigegeben wird (beendet). (kkkkkkk) ist die Schlüsselnummer (Notiz). (vvvvvvv) ist die Geschwindigkeit. |
1001nnnn | 0kkkkkkk 0vvvvvvv | Hinweis zum Ereignis. Diese Nachricht wird gesendet, wenn eine Notiz gedrückt wird (Start). (kkkkkkk) ist die Schlüsselnummer (Notiz). (vvvvvvv) ist die Geschwindigkeit. |
1010nnnn | 0kkkkkkk 0vvvvvvv | Polyphoner Tastendruck (Aftertouch). Diese Nachricht wird meistens gesendet, wenn die Taste gedrückt wird, nachdem die Taste "unten" gedrückt wurde. (kkkkkkk) ist die Schlüsselnummer (Notiz). (vvvvvvv) ist der Druckwert. |
1011nnnn | 0ccccccc 0vvvvvvv | Kontrollwechsel Diese Nachricht wird gesendet, wenn sich ein Controller-Wert ändert. Controller umfassen Geräte wie Pedale und Hebel. Die Controllernummern 120-127 sind als "Channel Mode Messages" (unten) reserviert. (ccccccc) ist die Controller-Nummer (0-119). (vvvvvvv) ist der Controller-Wert (0-127). |
1100nnnn | 0ppppppp | Programmänderung. Diese Nachricht wird gesendet, wenn sich die Patchnummer ändert. (ppppppp) ist die neue Programmnummer. |
1101nnnn | 0vvvvvvv | Kanaldruck (After-Touch). Diese Nachricht wird meistens gesendet, wenn die Taste gedrückt wird, nachdem die Taste "unten" gedrückt wurde. Diese Meldung unterscheidet sich von der polyphonen Nachberührung. Verwenden Sie diese Nachricht, um den einzigen größten Druckwert (von allen derzeit gedrückten Tasten) zu senden. (vvvvvvv) ist der Druckwert. |
1110nnnn | 0lllllll 0mmmmmmm | Pitch Bend Change. Diese Nachricht wird gesendet, um eine Änderung in der Neigungsverstellung (normalerweise Rad oder Hebel) anzuzeigen. Der Pitch Bender wird mit einem 14-Bit-Wert gemessen. Die Mitte (keine Tonhöhenänderung) beträgt 2000H. Die Empfindlichkeit ist eine Funktion des Empfängers, kann aber mit RPN 0 eingestellt werden. (Lllllll) sind die niedrigstwertigen 7 Bits. (mmmmmmm) sind die wichtigsten 7 Bits. |
Kanalmodus-Meldungen
Status D7..D0 | Datenbytes | Beschreibung |
---|---|---|
1011nnnn | 0ccccccc 0vvvvvvv | Kanalmodus-Meldungen. Dies ist derselbe Code wie für die Steuerungsänderung (oben), implementiert jedoch die Modussteuerung und die Sondermeldung unter Verwendung der reservierten Controller-Nummern 120-127. Die Befehle sind: |
Alle Ton aus. Wenn All Sound Off empfangen wird, schalten sich alle Oszillatoren aus und ihre Lautstärke wird so bald wie möglich auf Null gesetzt. c = 120, v = 0: Alle Töne aus | ||
Alle Controller zurücksetzen. Wenn alle Controller zurückgesetzt werden, werden alle Controller-Werte auf ihre Standardwerte zurückgesetzt. (Informationen zu den Standardeinstellungen finden Sie in den empfohlenen Empfehlungen.) | ||
c = 121, v = x: Der Wert darf nur Null sein, sofern in einer bestimmten empfohlenen Übung nichts anderes zulässig ist. | ||
Lokale Steuerung. Wenn Local Control deaktiviert ist, reagieren alle Geräte eines bestimmten Kanals nur auf Daten, die über MIDI empfangen werden. Abgespielte Daten usw. werden ignoriert. Local Control On stellt die Funktionen der normalen Controller wieder her. | ||
c = 122, v = 0: Lokalsteuerung aus | ||
c = 122, v = 127: Lokale Kontrolle Ein | ||
Alle Notizen aus. Wenn All Notes Off empfangen wird, werden alle Oszillatoren ausgeschaltet. | ||
c = 123, v = 0: Alle Notizen aus (Beschreibung der tatsächlichen Modusbefehle finden Sie im Text.) | ||
c = 124, v = 0: Omni-Modus aus | ||
c = 125, v = 0: Omni-Modus ein | ||
c = 126, v = M: Monomodus Ein (Poly Off), wobei M die Anzahl der Kanäle (Omni Off) oder 0 (Omni On) ist | ||
c = 127, v = 0: Poly-Modus ein (Mono aus) (Hinweis: Diese vier Meldungen bewirken auch, dass alle Notizen ausgeschaltet sind). |
Allgemeine Systemmeldungen
Status D7..D0 | Datenbytes | Beschreibung |
---|---|---|
11110000 | 0iiiiiii [0iiiiiii 0iiiiiii] 0ddddddd --- --- 0ddddddd 11110111 | System Exklusiv. Mit diesem Nachrichtentyp können Hersteller ihre eigenen Nachrichten erstellen (z. B. Bulk-Dumps, Patch-Parameter und andere nicht spezifizierte Daten) und bieten einen Mechanismus zum Erstellen zusätzlicher MIDI-Spezifikationsnachrichten. Der Hersteller-ID-Code (von MMA oder AMEI zugewiesen) ist entweder 1 Byte (0iiiiiii) oder 3 Byte (0iiiiiii 0iiiiiii 0iiiiiii). Zwei der 1-Byte-IDs sind für Erweiterungen reserviert, die als Universal Exclusive Messages bezeichnet werden und nicht herstellerspezifisch sind. Wenn ein Gerät den ID-Code als seinen eigenen erkennt (oder als unterstützte Universal-Nachricht), wird der Rest der Nachricht (0ddddddd) abgehört. Andernfalls wird die Nachricht ignoriert. (Hinweis: Nur Echtzeitnachrichten können mit einem System Exclusive verschachtelt werden.) |
11110001 | 0nnndddd | MIDI-Timecode-Viertelrahmen. nnn = Nachrichtentyp dddd = Werte |
11110010 | 0lllllll 0mmmmmmm | Song-Positionszeiger. Dies ist ein internes 14-Bit-Register, das die Anzahl der MIDI-Beats (1 Beat = sechs MIDI-Clocks) seit dem Beginn des Songs enthält. l ist das LSB, m das MSB. |
11110011 | 0sssssss | Song auswählen. Die Song-Auswahl legt fest, welche Sequenz oder welcher Song gespielt werden soll. |
11110100 | Nicht definiert. (Reserviert) | |
11110101 | Nicht definiert. (Reserviert) | |
11110110 | Tune Request. Nach Erhalt einer Tune-Anfrage sollten alle analogen Synthesizer ihre Oszillatoren abstimmen. | |
11110111 | Ende von Exclusive. Wird verwendet, um einen System Exclusive-Dump zu beenden (siehe oben). |
System-Echtzeitnachrichten
Status D7..D0 | Datenbytes | Beschreibung |
---|---|---|
11111000 | Timing-Uhr. Wird 24 Mal pro Viertelnote gesendet, wenn eine Synchronisierung erforderlich ist (siehe Text). | |
11111001 | Nicht definiert. (Reserviert) | |
11111010 | Start. Starten Sie die Wiedergabe der aktuellen Sequenz. (Diese Meldung wird mit Zeitschaltuhren angezeigt). | |
11111011 | Fortsetzen. Fahren Sie an dem Punkt fort, an dem die Sequenz gestoppt wurde. | |
11111100 | Halt. Stoppen Sie die aktuelle Sequenz. | |
11111101 | Nicht definiert. (Reserviert) | |
11111110 | Aktive Wahrnehmung. Diese Nachricht soll wiederholt gesendet werden, um dem Empfänger mitzuteilen, dass eine Verbindung aktiv ist. Die Verwendung dieser Nachricht ist optional. Beim ersten Empfang erwartet der Empfänger alle 300 ms (max) eine weitere Active Sensing-Nachricht. Andernfalls geht der Empfänger davon aus, dass die Verbindung beendet wurde. Bei Beendigung schaltet der Receiver alle Stimmen aus und kehrt zum normalen (nicht aktiven Abtastmodus) zurück. | |
11111111 | Zurücksetzen. Setzen Sie alle Empfänger im System in den Einschaltzustand zurück. Dies sollte sparsam verwendet werden, vorzugsweise unter manueller Kontrolle. Insbesondere sollte es nicht beim Einschalten gesendet werden. |