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.


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow