Recherche…


Introduction

L'intention de cette rubrique est de démontrer certains programmes MIDI de base qui montrent comment utiliser le protocole et ajouter progressivement des fonctionnalités utiles que les applications plus complexes requièrent.

MIDI THRU Exemple

Le MIDI Thru est simple et facile à tester. Lorsque vous travaillez correctement, vous pourrez installer votre projet Arduino entre deux appareils MIDI, MIDI IN sur MIDI OUT et vous pourrez vérifier que les deux appareils fonctionnent ensemble. Si vous avez la possibilité de mesurer la latence, vous verrez une augmentation due à la capture de mémoire tampon en série et aux instructions de retransmission.

// 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 Thru with Queue

// 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());;
  }
}

Génération d'horloge MIDI

// 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());;
  }
}

Messages MIDI définis

En général, le protocole MIDI est décomposé en "messages". Il existe 4 classes générales de messages:

  • Voix Channel
  • Mode de canal
  • Système commun
  • Messages système en temps réel

Les messages commencent par une valeur d'octet supérieure à 0x80. Toute valeur inférieure à 0x7F est considérée comme une donnée. Ce qui signifie que 127 est la valeur maximale pouvant être encodée dans un seul octet de données MIDI. Pour encoder des valeurs plus grandes, deux octets de données MIDI ou plus sont requis.

Il convient de signaler que les messages doivent être envoyés pour terminer sans interruption ... SAUF ... Système Les messages en temps réel, qui sont un seul octet, peuvent être injectés au milieu de n'importe quel message.

Messages vocaux de canal

Statut D7..D0 Octets de données La description
1000nnnn 0kkkkkkk 0vvvvvvv Note Off event. Ce message est envoyé lorsqu'une note est libérée (terminée). (kkkkkkk) est le numéro de la clé (note). (vvvvvvv) est la vitesse.
1001nnnn 0kkkkkkk 0vvvvvvv Remarque sur l'événement. Ce message est envoyé lorsqu'une note est enfoncée (début). (kkkkkkk) est le numéro de la clé (note). (vvvvvvv) est la vitesse.
1010nnnn 0kkkkkkk 0vvvvvvv Pression de touche polyphonique (Aftertouch). Ce message est le plus souvent envoyé en appuyant sur la touche (kkkkkkk) est le numéro de la clé (note). (vvvvvvv) est la valeur de la pression.
1011nnnn 0ccccccc 0vvvvvvv Changement de contrôle. Ce message est envoyé lorsqu'une valeur de contrôleur change. Les contrôleurs incluent des dispositifs tels que des pédales et des leviers. Les numéros de contrôleur 120-127 sont réservés en tant que "Messages de mode de canal" (ci-dessous). (ccccccc) est le numéro du contrôleur (0-119). (vvvvvvv) est la valeur du contrôleur (0-127).
1100nnnn 0ppppppp Changement de programme. Ce message est envoyé lorsque le numéro de patch change. (ppppppp) est le nouveau numéro de programme.
1101nnnn 0vvvvvvv Pression du canal (After-touch). Ce message est le plus souvent envoyé en appuyant sur la touche Ce message est différent du post-touch polyphonique. Utilisez ce message pour envoyer la valeur de pression maximale la plus élevée (de toutes les touches enfoncées actuelles). (vvvvvvv) est la valeur de la pression.
1110nnnn 0lllllll 0mmmmmmm Changement de Pitch Bend. Ce message est envoyé pour indiquer une modification de la hauteur tonale (roue ou levier, en général). Le pitch bender est mesuré par une valeur de quatorze bits. Centre (pas de changement de hauteur) est 2000H. La sensibilité est une fonction du récepteur, mais peut être définie à l'aide de RPN 0. (lllllll) sont les 7 bits les moins significatifs. (mmmmmmm) sont les 7 bits les plus significatifs.

Messages du mode canal

Statut D7..D0 Octets de données La description
1011nnnn 0ccccccc 0vvvvvvv Messages du mode canal. C'est le même code que le changement de commande (ci-dessus), mais implémente le contrôle de mode et le message spécial en utilisant les numéros de contrôleur réservés 120-127. Les commandes sont les suivantes:
Tout son éteint. À la réception de tous les sons désactivés, tous les oscillateurs s’éteignent et leurs enveloppes de volume sont mises à zéro dès que possible. c = 120, v = 0: tout son éteint
Réinitialiser tous les contrôleurs. Lorsque Réinitialiser tous les contrôleurs est reçu, toutes les valeurs du contrôleur sont réinitialisées à leurs valeurs par défaut. (Voir les pratiques spécifiques recommandées pour les défauts).
c = 121, v = x: la valeur ne doit être nulle que si cela est autorisé autrement dans une pratique spécifique recommandée.
Contrôle local. Lorsque le contrôle local est désactivé, tous les périphériques d'un canal donné répondent uniquement aux données reçues via MIDI. Les données lues, etc. seront ignorées. Local Control On restaure les fonctions des contrôleurs normaux.
c = 122, v = 0: contrôle local désactivé
c = 122, v = 127: Contrôle local activé
Toutes les notes sont désactivées. Lorsqu'un signal All Notes est reçu, tous les oscillateurs sont désactivés.
c = 123, v = 0: Toutes les notes sont désactivées (Voir le texte pour la description des commandes du mode réel.)
c = 124, v = 0: Mode Omni désactivé
c = 125, v = 0: mode omni activé
c = 126, v = M: Mode mono activé (Poly désactivé) où M est le nombre de canaux (Omni Off) ou 0 (Omni On)
c = 127, v = 0: Mode Poly activé (Mono Off) (Remarque: ces quatre messages provoquent également la désactivation de toutes les notes)

Messages communs au système

Statut D7..D0 Octets de données La description
11110000 0iiiiiii [0iiiiiii 0iiiiiii] 0ddddddd --- --- 0ddddddd 11110111 Système exclusif Ce type de message permet aux fabricants de créer leurs propres messages (tels que des vidages en masse, des paramètres de patch et d'autres données non spécifiées) et fournit un mécanisme pour créer des messages de spécification MIDI supplémentaires. Le code d'identification du fabricant (attribué par MMA ou AMEI) est soit 1 octet (0iiiiiii), soit 3 octets (0iiiiiii 0iiiiiii 0iiiiiii). Deux des ID à 1 octet sont réservés aux extensions appelées messages exclusifs universels, qui ne sont pas spécifiques à un fabricant. Si un appareil reconnaît le code d'identification comme étant le sien (ou comme un message universel pris en charge), il écoutera le reste du message (0ddddddd). Sinon, le message sera ignoré. (Remarque: seuls les messages en temps réel peuvent être entrelacés avec un système exclusif.)
11110001 0nnndddd MIDI Time Code Quarter Frame. nnn = Type de message dddd = Valeurs
11110010 0lllllll 0mmmmmmm Pointeur de position de morceau. C'est un registre interne à 14 bits qui contient le nombre de battements MIDI (1 battement = six horloges MIDI) depuis le début du morceau. l est le LSB, m le MSB.
11110011 0sssssss Song Select. The Song Select spécifie la séquence ou le morceau à jouer.
11110100 Indéfini. (Réservé)
11110101 Indéfini. (Réservé)
11110110 Demande de réglage. À la réception d'une demande de réglage, tous les synthétiseurs analogiques doivent accorder leurs oscillateurs.
11110111 Fin de la exclusivité. Utilisé pour terminer un vidage exclusif du système (voir ci-dessus).

Messages système en temps réel

Statut D7..D0 Octets de données La description
11111000 Horloge de chronométrage Envoyé 24 fois par trimestre, lorsque la synchronisation est requise (voir texte).
11111001 Indéfini. (Réservé)
11111010 Début. Lancer la séquence en cours de lecture. (Ce message sera suivi par des horloges de synchronisation).
11111011 Continuer. Continuez au point où la séquence a été arrêtée.
11111100 Arrêtez. Arrête la séquence en cours.
11111101 Indéfini. (Réservé)
11111110 Détection active. Ce message est destiné à être envoyé à plusieurs reprises pour indiquer au destinataire qu'une connexion est active. L'utilisation de ce message est facultative. Lorsqu'il est initialement reçu, le récepteur s'attend à recevoir un autre message Active Sensing tous les 300 ms (max) et s'il ne le fait pas, il supposera que la connexion est terminée. À la fin de la communication, le récepteur éteindra toutes les voix et reviendra au fonctionnement normal (détection non active).
11111111 Réinitialiser. Réinitialise tous les récepteurs du système au statut de mise sous tension. Ceci doit être utilisé avec parcimonie, de préférence sous contrôle manuel. En particulier, il ne devrait pas être envoyé à la mise sous tension.


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow