La norme MIDI 

Il existe à gauche et à droite des tas d'informations concernant la norme MIDI, et je n'ai pas pas la prétention d'en ajouter. J'avais juste envie d'écrire quelques mots à ma sauce, c'est ma petite contribution ;-) Attention cependant, mon texte est loin d'être exhaustif, je ne fais que survoler la chose (désolé pour le titre de cette page qui pourrait laisser penser plus).

 

Brochage des prises MIDI

Le câblage des prises MIDI concerne plutôt la réalisation pratique des interfaces MIDI, pas besoin d'en connaître le détail si vous achetez vos interfaces et câbles tout fait.

midi_din_cablage_001

Câblage valable pour les prises MIDI IN, MIDI OUT et MIDI THRU. La borne 2 est reliée à la masse au niveau des sorties (OUT et THRU) mais pas au niveau des entrées, pour éviter toute boucle de masse entre équipements. Le câblage s'effectue entre les deux broches 4 et 5, selon détail suivant :

interfaces_midi_out_001a interfaces_midi_in_001a
 

Principe général des liaisons MIDI

Les liaisons MIDI sont des liaisons de type série : on y transmet des informations binaires - informatiques - sur un "fil" unique (par rapport toutefois à un autre fil qui sert de référence). Afin d'éviter tout rebouchage de masse entre deux équipements reliés d'une part par un câble audio et d'autre part par un câble MIDI, ce dernier est branché sur une interface électriquement isolée du reste de la circuiterie de l'équipement. Les données sont envoyées de façon asynchrone, c'est à dire qu'elles sont véhiculées de l'émetteur vers le récepteur sans être accompagné d'une horloge de "référence" permettant de savoir quand lire les données qui arrivent, comme c'est le cas avec les liaisons de type I2C et des liaisons entre clavier PS2 et ordinateur (un fil DATA et un fil CLOCK dans les deux cas). C'est aussi de cette façon que fonctionnent les liaisons série de type RS232, appelée COMx (COM1, COM2, etc.). N'utiliser qu'un seul fil pour transmettre des informations permet d'économiser sur le câblage physique, mais demande en retour une grande rigueur, une grande qualité des données émises et notamment une bonne précision du rythme avec lequel les données sont transmises. Car le circuit récepteur, qui ne reçoit que les données et aucune information d'horloge, ne peut qu'être informé de la vitesse théorique sous laquelle les données vont arriver, et cherche à synchroniser sa propre horloge interne sur le rythme des données arrivantes. Bien sûr, on ne peut pas certifier à 100 % que les données émises vont l'être exactement à telle ou telle vitesse, il y a forcement une imprécision, une certaine tolérance, et le récepteur doit être en mesure de s'accommoder de petits écarts entre la vitesse théorique (par exemple 31250 bits par secondes) et la vitesse réellement constatée (par exemple 31200 bits par secondes). Comme ces écarts ne doivent pas être trop importants, il est nécessaire que l'émetteur qui envoie les données le fasse à un rythme le plus stable possible et le plus proche de celui attendu. Si ce point n'est pas respecté, le récepteur peut "décrocher" et ne plus reconnaitre du tout les données qui arrivent.

Transport des données

Dans le monde informatique, il est fréquent de travailler avec des nombres, catégorisés selon leur grandeur (on parle aussi de longueur). Ainsi, on peut travailler avec un nombre qui ne peut prendre que deux valeurs comme le bit, tout comme on peut travailler avec des nombres qui peuvent prendre 256 valeurs différentes comme l'octet (byte en angalis, à ne pas confondre avec bit). D'un point de vue machine, tous les nombres sont décrits par un nombre plus ou moins important de bits, mais un bit ne peut jamais prendre plus de deux valeurs différentes, qui seront toujours 0 ou 1. Pour plus de détails, voir page Informatique et nombres et ICI. S'il est facile de véhiculer sur un seul fil un nombre qui peut prendre deux valeurs (on envoie une tension ou on n'envoie rien du tout), il n'est pas facile d'envoyer en une seule fois un nombre qui peut prendre plus de deux valeurs, sachant que l'on reste dans le monde du numérique et que les valeurs intermédiaires (entre 0 et 1) ne sont pas autorisées. On peut envoyer plusieurs informations en même temps en recourant à des procédés de modulation (porteuses et sous-porteuses), mais cela complique singulièrement la fabrication des circuits émetteurs et récepteurs, et en augmente le coût dans des proportions importantes. Il est bien plus simple et bien moins couteux d'envoyer les données les unes après les autres, à la queue-leu-leu, mais cela prend évidement plus de temps. Si cependant la quantité de données à envoyer n'est pas trop importante, et si le temps mis pour envoyer le tout n'est pas excessif, c'est une solution qui convient parfaitement. Et c'est ainsi que la norme RS232 et la norme MIDI travaillent, et de façon fort correcte quand les précautions élémentaires - telles que qualité et longueur des câbles adaptées à l'usage, et notamment à la vitesse - sont respectées. Le principe de base est fort simple, nous allons le voir avec un exemple pratique.

Supposons que nous ayons à transporter le nombre 45 d'un point à un autre, et qu'on ne dispose que d'un seul fil pour assurer le transport de cette information. Il va falloir décomposer ce nombre 45 en informations élémentaires que sont les bits. Comme le nombre 45 est inférieur à 256, il rentre dans la catégorie des octets, codés sur 8 bits. Cela signifie que l'on peut envoyer à la que-leu-leu huit informations distinctes que sont les 8 bits de l'octet, pour véhiculer la valeur 45. Il ne reste au récepteur qu'à savoir qu'à quel moment, telle valeur reçue (0 ou 1) correspond à tel ou tel bit parmi les huit attendus. Bien sûr il ne faut pas qu'il se trompe car le moindre bit lu à la place d'un autre a de grandes chances de rendre la valeur reçue invalide. Le travail de récupération des bits reçus n'est pas aussi simple qu'il peut en paraitre, et c'est pourquoi des fabricants proposent ce qu'on appelle des UART, qui sont des composants spécialisés dans ce genre de travail. Un UART peut très bien être un composant électronique à part entière (un circuit qui ne fait que ce travail précis), tout comme il peut être intégré dans un autre composant tel un microcontrôleur. Pour simplifier, nous pouvons dire que côté émetteur on envoie (on écrit) les 8 bits de l'octet les uns après les autres, ce qui est équivalent à une conversion parallèle (8 fils) / série (1 fil). Et que côté récepteur, on lit les 8 bits de l'octet les uns après les autres et on les regroupe pour retrouver le nombre d'un seul bloc, composé de tous ses bits, ce qui est équivalent à une conversion série (1 fil) / parallèle (8 fils).

liaison_serie_ps_sp_001a
A gauche l'émetteur de données, à droite le récepteur

Sur le synoptique ci-avant, nous voyons que chaque bit est transmis sur un seul fil après conversion parallèle / série, en commençant par le bit_0 et en terminant par le bit_7 (mais on peut aussi fort bien transmettre le bit de poids fort en premier et terminer avec le bit de poids faible). Le transfert de chaque bit est cadencé à une certaine vitesse, qui est celle de l'horloge CLK (CLK vient du mot CLOCK qui en anglais veut dire horloge) : le bit_0 est transmis au temps T0, le bit_1 est transmis au temps T1, etc., pour terminer avec le bit_7 transmis au temps T7. L'exemple est donné pour un nombre tenant sur 8 bits, mais le principe est rigoureusement le même pour des données tenant sur un nombre plus grand ou moins grand de bits. Disons qu'il est plus commun de trouver des informations de 8 bits ou des informations multiples de ce nombre, qui peuvent donc être décomposées en paquets de 8 bits (un octet). Par exemple, si on veut transmettre un nombre tenant sur 32 bits, on peut dire qu'on envoie un seul "double mot" (DWord) de 32 bits, ou que l'on envoie 2 mots (word) de 16 bits chacun, ou encore que l'on envoie 4 octets (byte) de 8 bits chacun. Dans tous les cas, ce sont bien 32 informations séparées qui sont transmises. 

Et bien pour les données MIDI, ce n'est pas plus compliqué : on envoie dans un fil électrique, un certain nombre d'octets (paquets de 8 bits) pour former un message. Et comme les besoins dans le domaine musical peuvent être variés et bien différents, plusieurs types de messages ont été inventés, allant du message simple qui commande l'exécution ou l'arrêt d'une note, au message de type "exclusif" dont le contenu peut correspondre à la totalité des paramètres utilisateur d'un synthétiseur.

Messages MIDI

Comme cela vient d'être dit, il existe plusieurs types de messages MIDI, d'une longueur plus ou moins importante. Les messages les plus utilisés sont sans doute les messages de type NoteOn et NoteOff, qui indiquent à un instrument de musique électronique quand il faut jouer une note (NoteOn) et quand il faut cesser de la jouer (NoteOff). On peut trouver dans les messages MIDI deux catégories d'octets, qui sont les octets de Statut (Status) et les octets deDonnée (Data). Dans le texte qui suit, nous allons parfois parler en octets et parfois parler en bits - selon la circonstance, avec toujours en tête qu'un octet comporte 8 bits. Ce qui veut dire par exemple que s'il est indiqué qu'il faut envoyer 3 octets pour un message MIDI donné, cela correspond à l'envoi de 24 bits de données consécutifs. Attention cependant, envoyer 24 bits de données utiles ne signifie pas qu'il n'y aura en tout que 24 bits dans le message complet ! Chaque octet sera en effet encadré par un bit de Start, et par un bit de Stop. Pour un octet utile, nous avons donc 10 bits de données à transmettre, ce qui conduit à l'envoi de 30 bits si le message MIDI comporte 3 octets. La durée pendant laquelle chaque bit est transmis est de 32 us (microsecondes), ce qui revient à dire qu'un octet utile avec ses deux bits de Start et de Stop occupe un temps de 320 us. Un rythme de période 32 us correspond à une vitesse de 31,250 KHz (1 / 0.000032), ou encore 31,250 Kbauds (le baud exprime simplement le nombre de bits transmis en une seconde, il est donc équivalent à la fréquence de transmission).

Scission des octets

Si les messages MIDI sont composés de plusieurs octets, il est important de noter dès maintenant que certains octets peuvent se partager la place pour diffuser plusieurs types d'informations. Un octet comporte en effet 8 bits, et rien n'interdit d'utiliser 4 bits de cet octet pour transmettre une information, et d'utiliser les 4 autres bits pour transmettre une autre information, complètement indépendante de la première. Il serait en effet dommage de gaspiller des ressources, en s'octroyant un octet qui ne représentera jamais une valeur supérieure à 15 et qui pourrait tenir sur 4 bits. S'il faut transmettre deux valeurs qui chacune ne dépassent jamais la valeur 15, autant les faire entrer toutes deux dans un seul octet. Bien sûr, la méthode de "lecture" des bits n'est plus tout à fait la même, mais le principe reste le même. Prenons un exemple pratique pour voir ça de plus près. Dans la page Les nombres en informatique, nous voyons comment chaque bit d'un octet peut avoir un poids différent, le premier bit avec sa valeur de 1 et le huitième bit avec sa valeur de 128.

informatique_nombres_001db

Si on veut utiliser les 8 bits d'un octet pour véhiculer deux informations différentes tenant chacune sur 4 bits, il suffit de voir les choses de la façon suivante, avec les 4 bits "de gauche" à pied d'égalité (en terme de poids) avec les 4 bits de "droite". Au lieu d'additionner la valeur des bits positionnés à 1 parmi les 8 disponibles, on additionne d'abords la valeur des bits positionnés à 1 parmi les quatre premiers pour obtenir la première valeur, et ensuite on additionne la valeur des bits positionnés à 1 parmi les quatre derniers pour obtenir la deuxième valeur.

informatique_nombres_001fa

Sur ce dernier exemple, on dispose d'une première information correspondant au nombre 12 stockée sur les quatre bits de poids fort, et d'une seconde information correspondant au nombre 2 stockée sur les quatre bits de poids faible. Et devinez le meilleur : cette façon de faire permet d'écrire la valeur d'un octet avec deux caractère alphanumériques compris entre 0 et 9 ou entre A et F. Pour l'exemple précédent, on peut écrire l'octet sous la forme hexadécimale "C2", où le caractère 2 représente la valeur des quatre premiers bits (ceux de poids faibles, à droite), et où le caractère C représente la valeur des quatre derniers bits (ceux de poids fort, à gauche). Bien sûr, la correspondance entre valeur hexa et valeur décimale est plus évidente à établir quand on sait que A = 10, B = 11, C = 12, D = 13, E = 14 et F = 15. Voici quelques exemples de conversion binaire / hexa pour se faire la main :

00000000 = 00h = $00
11110000 = F0h = $F0
11111111 = FFh = $FF
00000011 = 03h = $03
00110000 = 30h = $30
00110011 = 33h = $33
01010101 = 55h = $55
10101010 = AAh = $AA

Remarque : une valeur hexadécimale peut être notée sous la forme XXd ou sous la forme $XX.

Types de messages

Tous les messages MIDI, quels qu'ils soient, sont composés de plusieurs octets, et la lecture (le décodage) du premier octet permet de comprendre de quel type de message il s'agit. Nous l'avons vu tout à l'heure, il existe des messages de Statut et des messages de Donnée. Un octet peut prendre une valeur décimale comprise entre 0 (00000000 en binaire, $00 en hexa) et 255 (11111111 en binaire, $FF en hexa). Si la valeur du premier octet est comprise entre 0 et 127 (premier caractère du code hexa compris entre 0 et 7) alors nous avons affaire à un octet de Donnée. Si la valeur du premier octet est comprise entre 128 et 255 (premier caractère du code hexa compris entre 8 et F) alors nous avons affaire à un octet de Statut :

- de $00 à $7F (de 0 à 127 en décimal) : octet de donnée
- de $80 à $FF (de 128 à 255 en décimal) : octet de statut

Exemples : 

00011011 = $1B = octet de donnée
01010000 = $50 = octet de donnée
11000000 = $C0 = octet de statut
11100001 = $D1 = octet de statut

Notez que le bit le plus à gauche (celui de poids le plus fort) est forcement à 0 pour les octets de donnée et forcement à 1 pour les octets de statut.

Dans un message MIDI, on peut avoir un octet Statut suivi d'un octet Donnée. L'octet Donnée peut par exemple représenter une valeur quelconque, et l'octet Statut peut indiquer à quel paramètre de l'instrument donner la valeur de l'octet Donnée. En pratique, un message MIDI commence toujours par un octet de type Statut, qui indique précisément ce qui suit. Les messages de Statut servent généralement à :

- indiquer le type de données véhiculées dans la suite du message;
- indiquer un numéro de canal, utile pour savoir si l'instrument récepteur doit traiter les données qui suivent ou les ignorer.

Il est à noter que les octets Statut ne sont pas forcement suivi d'octet Donnée, c'est le cas par exemple des messages Système Temps réel.

Messages de type "voix"

Un message de type NoteOn est envoyé à chaque fois que l'on appuie sur la touche d'un clavier. Tant que l'on maintien cette touche enfoncé, il ne se passe rien du tout, le message NoteOn est parti une fois et n'est pas répété. Un message de type NoteOff est émis quand on relache la touche qui était enfoncée. Ces deux types de message NoteOn et NoteOff comportent 3 octets, ni plus ni moins. Ces trois octets comportent plusieurs informations, qui sont les suivantes :

- Type de message
- Numéro de canal MIDI
- Numéro de note jouée
- Force de frappe (vélocité)

Type de message

Cette information, qui n'occupe que la moitié d'un octet (4 bits) permet de savoir s'il faut commencer à jouer une note (NoteOn) ou s'il faut l'arrêter (NoteOff), ou encore si le message comporte une commande de changement de jeux (changement d'un instrument ou d'un paramètre d'un instrument, modulation d'une note, etc).

$8x = [1000xxxx] = NoteOff
$9x = [1001xxxx] = NoteOn
$Ax = [1010xxxx] = After Touch polyphonique
$Bx = [1011xxxx] = Control Change
$Cx = [1100xxxx] = Program Change
$Dx = [1101xxxx] = After Touch de canal
$Ex = [1110xxxx] = Pitch Bend (pitch wheel)
(le caractère x indique que la valeur peut être quelconque)

Si on y regarde de plus près, le type de message n'est en fait codé que sur 3 bits, car le premier bit est toujours à 1 (puisque qu'on a affaire à un octet de Statut). Nous ne pouvons donc disposer que de 8 types de messages différents. Là nous n'en voyons que 7, le huitième, qui commence par F, sera vu plus loin.

Numéro de canal MIDI

On peut disposer de 16 canaux MIDI sur une même liaison MIDI, pour faire jouer 16 instruments musicaux différents, par exemple. Les canaux MIDI sont numérotés de 1 à 16, et leur nombre informatique correspondant est compris entre 0 et 15. Cela signifie que la réception d'un code canal 10 correspond en fait au canal MIDI numéro 11. Toujours ce décalage infernal de une unité entre nombres traités en informatique (qui commencent par 0) et nombres traités par les gens normaux (qui commencent par 1). Tout comme l'information de type de message, le numéro de canal n'occupe que 4 bits. 

$x0 = canal MIDI numéro 1
$x1 = canal MIDI numéro 2
...
$xE = canal MIDI numéro 15
$xF = canal MIDI numéro 16

Et c'est ainsi qu'eut lieu le mariage entre type de message (4 bits) et numéro de canal (4 bits), tous deux ne formant plus qu'un seul octet (8 bits) :

$90 = NoteOn (9) sur canal MIDI numéro 1 (0)
$93 = NoteOn (9) sur canal MIDI numéro 4 (3)
$80 = NoteOff (8) sur canal MIDI numéro 1 (0)
$8F = NoteOff (8) sur canal MIDI numéro 16 (F)

Numéro de note jouée

A chaque note à faire jouer par l'instrument de musique (do, ré, mi, etc) correspond un nombre compris entre 0 et 127. Au fameux LA3 (diapason ou tonalité du téléphone) correspond ainsi le nombre décimal 69 ($45 en héxa). A chaque fois qu'on veut descendre d'un demi-ton, on retranche 1 à cette valeur. Et à chaque fois qu'on veut monter d'un demi-ton, on ajoute 1 à cette valeur. Exemples :

DO-2 = 0d = $00
....
SOL3 = 67d = $43
SOL#3 = 68d = $44
LA3 = 69d = $45
LA#3 = 70d = $46
SI3 = 71d = $47
...
SOL8 = 127d = $7F

Comment se rappeler de ces correspondances ? Vous allez sans doute me trouver quelque peu coquin, mais on pourrait dire que deux personnes en position 69 sont au diapason...

Force de frappe (vélocité)

La force de frappe est liée à la vélocité de la frappe de la touche : plus on tape fort et plus ça frappe vite. La vélocité est représentée par un nombre compris entre 1 (ppp / pianissimo, force de frappe minimale) et 127 (fff / fortissimo, force de frappe maximale). La valeur $40 (64 en décimal) est donnée comme valeur centrale par défaut (mp-mf / mezzo-forte). Cette information est bien sûr parlante pour un instrument de musique dynamique, qui sait faire entendre une différence sonore (autre que le volume) selon la force de frappe sur ses touches (attention aux sons d'orgue, qui généralement ne sont pas assujettis aux variations de vélocité). 

Remarque : l'arrêt d'une note peut être commandée par la réception d'un message de type NoteOff, ou par la réception d'un message de type NoteOn associé à une vélocité de 0 (zéro). La valeur 0 ne doit donc pas être utilisée pour une info de type NoteOn si on veut jouer la note.

Quelques exemples de messages de type NoteOn ou NoteOff

En résumé, 4 informations différentes sont transmises dans 3 octets :

[1sssnnnn] [0xxxxxxx] [0xxxxxxx]
 Statut     Donnée 1   Donnée 2

sss = type de message (001 pour Note On et 000 pour NoteOff)
nnnn = numéro de canal MIDI (compris entre 0 et 15)
xxxxxxx = valeur des données (compris entre 0 et 127)
Donnée 1 = hauteur de la note (69d pour le LA3, un exemple entre autres)
Donnée 2 = vélocité de la note (comprise entre 0 et 127, généralement $40 - soit 64 en décimal - pour un clavier non dynamique)

Exemple 1 : Démarrage note LA3 avec vélocité de $64 (100 en décimal)

[10010000] [01000101] [01100100]
 $90        $45        $64
 Statut     Donnée 1   Donnée 2
 NoteOn     LA3        100

Exemple 2 : Démarrage note DO1 avec vélocité de $75 (117 en décimal)

[10010000] [00100100] [01110101]
 $90        $24        $75
 Statut     Donnée 1   Donnée 2
 NoteOn     DO1        117

Exemple 3 : Arrêt note LA3 

[10000000] [01000101] [00000000]
 $80        $45        $00
 Statut     Donnée 1   Donnée 2
 NoteOff    LA3        0

Pour ce troisième exemple, une information de type NoteOn avec vélocité de 0 est aussi interprété en tant que NoteOff.

Messages Système

Les messages Système sont des messages qui ne servent pas à jouer des notes, mais à transmettre des informations de natures diverses, dont la priorité - d'un point de vue temporelle - est plus ou moins marquée. Il commence par un octet dont la valeur est comprise entre $F0 et $FF. Ces octets peuvent être transmis seuls (cas des messages temps réel) ou être suivis de plusieurs octets de donnée.

Messages de type SysEx (SYStem EXclusive)

Ce type de message ne s'adresse qu'à une seule marque d'instrument ou même à un seul modèle. C'est typiquement le genre de message que l'on utilise pour le transfert de grosses quantités d'informations, comme les "dump" d'une mémoire complète ou d'un son individuel. La construction d'un tel message doit répondre à quelques impératifs si on ne veut pas qu'un message adressé à un modèle d'instrument particulier soit reconnu par un autre modèle. Il est en particulier nécessaire d'inclure en début de message, un code qui est propre au constructeur et un autre code propre au modèle d'instrument. Heureusement, chaque marque a son code, et ne doit utiliser que le sien, ce qui en théorie interdit tout conflit entre marques différentes. Bien entendu, de tels messages peuvent être acceptés par un ordinateur équipé d'un séquenceur universel ou d'un éditeur / gestionnaire de bibliothèques sonores. Un message SYSEX commence par un octet de valeur $F0 et se termine par un octet de valeur $F7 (EOX). Hormis ces deux octets de début et de fin de trame, on dispose de quelques autres valeurs d'octet permettant par exemple d'indiquer la position en cours dans un morceau ($F2, pointeur de position).

$F0 = Début de message SYSEX
$F1 = non utilisé
$F2 = Pointeur de position (suivi de deux octets de donnée)
$F3 = Sélecteur de morceau (suivi d'un octet de donnée)
$F4 = non utilisé
$F5 = non utilisé
$F6 = Requête d'accordage (Tune Request)
$F7 =Fin de message SYSEX (EOX, End Of eXclusive)

Messages Temps réel

Ces messages sont de type prioritaires car leur rôle est de donner des informations fortement dépendante du jeu temps réel (live). Ces messages sont les plus brefs que l'on peut rencontrer dans la norme MIDI, ils ne sont composés que d'un seul octet de Statut et ne sont suivi d'aucun octet de donnée. Tous les messages temps réel ont une valeur comprise entre $F8 et $FF.

$F8 = Horloge MIDI (Timing Clock)
$F9 = Horloge MIDI émise en fin de mesure
$FA = Start (départ)
$FB = Continue (reprise)
$FC = Stop (arrêt)
$FD = non utilisé
$FE = Active Sensing (message de vie envoyé toutes les 300 ms)
$FF = Reset système (réinitialisation) - peu utilisé, voire déconseillé

Le message $F8 - horloge MIDI - est émis tous les 1/24 de noire, il s'agit d'une synchronisation appelée 24 PPQN (Pulses Per Quarter Note, pulsations par quart de note).

Ouvrage de référence MIDI qui m'a servi bien souvent...

Un livre pas bien épais mais vraiment très bien écrit.


Le MIDI pratique - Jean-Paul Verpaux
 

 

 

 

Accuil