vendredi 15 juin 2018

MIDI par usb avec Arduino Leonardo

Jusqu'à maintenant, chaque fois que j'ai abordé un projet impliquant le protocole MIDI, j'ai utilisé les traditionnels connecteurs DIN à 5 broches.  Ces connecteurs sont tout à fait appropriés lorsqu'on veut brancher une carte Arduino à un clavier MIDI, par exemple.  Mais pour établir une communication MIDI entre l'Arduino et un ordinateur, un simple câble usb s'avère plus pratique (surtout si vous ne possédez pas d'instruments de musique compatibles MIDI).

Dans ce tuto, nous explorons donc l'utilisation d'une carte Arduino Leonardo pour établir une communication MIDI avec un ordinateur.  Plutôt qu'un Leonardo, n'importe quelle carte Arduino pouvant se comporter comme un périphérique USB pourrait faire l'affaire (Zero, Due, 101...); toutefois, ce projet ne fonctionnera pas avec une carte Arduino Uno.

Installation d'un logiciel MIDI sur l'ordinateur

Nous aurons besoin d'un logiciel compatible MIDI sur l'ordinateur auquel nous brancherons le Leonardo.  Si vous avez déjà l'habitude de jouer avec des contrôleurs MIDI, utilisez votre logiciel préféré.  Sinon, je vous propose VMPK, ou Virtual MIDI Piano Keyboard qui est léger, gratuit, et convient parfaitement à nos besoins.  Le logiciel est disponible pour Windows, Linux et Mac, mais j'ai fait mes tests sous Windows 7.



Installation de la bibliothèque MIDIUSB

Vous devez également installer la bibliothèque MIDIUSB dans votre IDE Arduino.  Attention, il ne s'agit pas de la bibliothèque MIDI conventionnelle que vous avez peut-être déjà installée dans le passé.



Exemple 1:  communication de l'Arduino vers l'ordinateur (MIDI out)

Une première utilisation possible consiste à envoyer des instructions MIDI de la carte Arduino vers l'ordinateur (le Leonardo agit comme contrôleur MIDI).  L'exemple "MIDIUSB_write" qui accompagne la bibliothèque MIDIUSB envoie à l'ordinateur une même note de façon répétitive; j'ai modifié cet exemple pour jouer en boucle une courte mélodie constituée de 16 notes.

Le sketch

Le sketch contient une fonction noteOn qui permet de jouer une note.  Cette fonction nécessite trois paramètres:  channel (le canal MIDI utilisé), pitch (la note de la gamme à jouer) et velocity (le volume sonore avec lequel la note doit être jouée).

Ainsi,  "noteOn(0, 0x48, 64)" jouera la note "do du 5e octave" avec une vélocité de 64 (moyenne) sur le canal 0.

Dans le protocole MIDI, chaque note est jouée aussi longtemps qu'elle n'est pas interrompue par un message "noteOff", qui prend les mêmes arguments que la fonction "noteOn".

Les 16 notes qui constituent notre mélodie sont stockées dans un tableau bidimensionnel nommé "melodie":  le premier élément est le "pitch", et le deuxième est la durée en millisecondes.  J'aurais pu ajouter un troisième élément pour la vélocité mais, dans cette exemple, toutes les notes de la mélodie sont jouées avec la même intensité.


/**************************************************************************************************
Leonardo MIDI USB out
Ce sketch permet à une carte Arduino Leonardo de transmettre une
mélodie par MIDI USB.
https://electroniqueamateur.blogspot.com/2018/06/midi-par-usb-avec-arduino-leonardo.html
*****************************************************************************************************/
#include "MIDIUSB.h" // Bibliothèque MIDIUSB: https://github.com/arduino-libraries/MIDIUSB
int duree = 500; //durée d'une noire, en millisecondes.
// définition de quelques notes sur 2 octaves
#define NOTE_C4 0x3C //do
#define NOTE_D4 0x3E //ré
#define NOTE_E4 0x40 //mi
#define NOTE_F4 0x41
#define NOTE_G4 0x43
#define NOTE_A4 0x45
#define NOTE_B4 0x47
#define NOTE_C5 0x48
#define NOTE_D5 0x4A
#define NOTE_E5 0x4C
#define NOTE_F5 0x4D
#define NOTE_G5 0x4F
#define NOTE_A5 0x51
#define NOTE_B5 0x53
#define NOTE_C6 0x54
#define nombreDeNotes 16 // nombre de notes à jouer dans notre mélodie
// la melodie est constituée de 16 notes (pour chaque note: hauteur et durée)
int melodie[nombreDeNotes][2] = {
{NOTE_C5, 1 },
{NOTE_G4, 1 },
{NOTE_C5, 1 },
{NOTE_E5, 1 },
{NOTE_G5, 1 },
{NOTE_E5, 1 },
{NOTE_F5, 1 },
{NOTE_E5, 1 },
{NOTE_F5, 1 },
{NOTE_A5, 1 },
{NOTE_D5, 2 },
{NOTE_E5, 1 },
{NOTE_D5, 1 },
{NOTE_E5, 1 },
{NOTE_G5, 1 },
{NOTE_C5, 4 },
};
// les fonctions noteOn et noteOff reçoivent 3 arguments: le canal MIDI (0 à 15),
// la hauteur de la note (48 pour le do central),
// et la vélocité, qui contrôle le volume de la note(0 à 127).
void noteOn(byte channel, byte pitch, byte velocity) {
midiEventPacket_t noteOn = {0x09, 0x90 | channel, pitch, velocity};
MidiUSB.sendMIDI(noteOn);
}
void noteOff(byte channel, byte pitch, byte velocity) {
midiEventPacket_t noteOff = {0x08, 0x80 | channel, pitch, velocity};
MidiUSB.sendMIDI(noteOff);
}
void setup() {
}
void loop() {
for (int i = 0; i < nombreDeNotes; i++) {
noteOn(0, melodie[i][0], 64); // canal zéro, do, intensité moyenne
MidiUSB.flush(); // nécessaire pour envoyer la note MAINTENANT
delay(melodie[i][1] * duree - 10);
noteOff(0, melodie[i][0], 64);
MidiUSB.flush();
delay(10); // pour séparer les notes les unes des autres
}
}

Réglages du logiciel MIDI

Pour que la mélodie émise par l'Arduino soit jouée par l'ordinateur, il faut faire en sorte que Virtual MIDI Piano Keyboard utilise la carte Leonardo comme entrée MIDI.  Pour  ce faire, vous choisissez "Connexions MIDI" dans le menu "Éditer".


Si la carte est branchée à un port USB de l'ordinateur, "Arduino Leonardo" devrait être disponible dans la liste proposée pour "Connexion du port d'entrée MIDI".  Il vous faut également un pilote capable de jouer les sons ("Pilote MIDI OUT").  Dans mon cas, on me propose "Windows MM", probablement parce que Windows Movie Maker était déjà installé sur l'ordinateur.  Si la liste "Pilote MIDI OUT" est vide pour vous, vous devrez installer un pilote sur votre ordinateur (VirtualMIDISynth, par exemple).

La mélodie devrait maintenant être jouée sur la carte de son de l'ordinateur.  Notez que vous pouvez modifier le "programme" (l'instrument utilisé pour jouer la mélodie): ça peut être un son de piano, de trompette, de clarinette, etc.

D'autres exemples de MIDI out

Comme je l'ai déjà mentionné, l'exemple "MIDIUSB_write" fournit avec la bibliothèque MIDIUSB fait la même chose, mais avec une seule note.  De plus, des informations apparaissent dans le moniteur série de l'IDE Arduino, ce qui peut aider au débogage.

Si vous préférez fabriquer un petit contrôleur MIDI, jetez un oeil sur la page MidiDevice du site officiel Arduino: on vous guide dans la fabrication d'un clavier MIDI constitué de 7 boutons poussoirs.


Exemple 2:  communication de l'ordinateur vers l'Arduino (MIDI in)

Dans ce deuxième exemple, nous allons envoyer des messages MIDI de l'ordinateur vers l'Arduino.  Pour vérifier que ça fonctionne, vous pouvez essayer l'exemple "MIDIUSB_read" fourni avec la bibliothèque MIDIUSB: lorsque vous jouez une note sur le clavier du logiciel Virtual MIDI Piano Keyboard, elle s'affiche dans le moniteur série de l'IDE Arduino.

Pour ma part, j'ai essayé quelque chose qui me semblait un tout petit peu plus amusant:  chaque fois que je clique sur une note du logiciel Virtual MIDI Piano Keyboard, l'Arduino produit cette note à travers un haut-parleur.  Le Leonardo servira donc de synthétiseur MIDI (remarquez que la pertinence du projet est un peu discutable: la carte de son de l'ordinateur produit un son de bien meilleur qualité que la fonction tone de l'Arduino...).

Circuit

Le haut-parleur est relié à la broche 8 du Leonardo, par l'entremise d'un transistor pour éviter que le haut-parleur, à cause de sa très faible impédance, ne draine trop de courant (plus de détails ici).



Sketch

Lorsque le Leonardo reçoit un message "noteOn", il établit une correspondance entre le code MIDI qui indique la hauteur de la note (pitch) et la fréquence qui devra être émise par le haut parleur.  La variable MidiToFreq est un tableau bi-dimensionnel qui contient, pour chaque pitch MIDI, la fréquence en hertz.  Une fois la fréquence connue, on utilise la fonction tone pour jouer cette note sur le haut-parleur (broche 8).  Lorsqu'on reçoit un message "noteOff", on utilise noTone pour interrompre le signal PWM de la broche 8.


/***********************************************************************************************
Leonardo MIDI USB in
La carte Leonardo reçoit des messagges MIDI par USB et
produit un son correspondant au message reçu.
(Un haut parleur est branché à la broche 8)
https://electroniqueamateur.blogspot.com/2018/06/midi-par-usb-avec-arduino-leonardo.html
*****************************************************************************************************/
#include "MIDIUSB.h" // Bibliothèque MIDIUSB: https://github.com/arduino-libraries/MIDIUSB
// correspondance entre pitch MIDI et fréquence
int MidiToFreq [61][2] {
{0x24, 65}, {0x25, 69}, {0x26, 73}, {0x27, 78}, {0x28, 82}, {0x29, 87}, {0x2A, 93}, {0x2B, 98}, {0x2C, 104},
{0x2D, 110}, {0x2E, 117}, {0x2F, 123}, {0x30, 131}, {0x31, 139}, {0x32, 147}, {0x33, 156}, {0x34, 165},
{0x35, 175}, {0x36, 185}, {0x37, 196}, {0x38, 208}, {0x39, 220}, {0x3A, 233}, {0x3B, 247}, {0x3C, 262},
{0x3D, 277}, {0x3E, 294}, {0x3F, 311}, {0x40, 330}, {0x41, 349}, {0x42, 370}, {0x43, 392}, {0x44, 415},
{0x45, 440}, {0x46, 466}, {0x47, 494}, {0x48, 523}, {0x49, 554}, {0x4A, 587}, {0x4B, 622}, {0x4C, 659},
{0x4D, 698}, {0x4E, 740}, {0x4F, 784}, {0x50, 831}, {0x51, 880}, {0x52, 932}, {0x53, 988}, {0x54, 1047},
{0x55, 1109}, {0x56, 1175}, {0x57, 1245}, {0x58, 1319}, {0x59, 1397}, {0x5A, 1480}, {0x5B, 1568},
{0x5C, 1661}, {0x5D, 1760}, {0x5E, 1865}, {0x5F, 1976}, {0x60, 2093}
};
void setup() {
pinMode(13, OUTPUT); // pour allumer la LED intégrée à la carte
}
void loop() {
midiEventPacket_t rx;
do {
rx = MidiUSB.read();
if (rx.header != 0) {
if (rx.byte1 == 0x90) // message noteOn
{
digitalWrite(13, true); // on allume la LED intégrée à la carte
// on cherche quelle fréquence il faut jouer
int note = 0;
// recherche de la note reçue dans notre tableau de conversion, pour connaitre sa fréquence
for (int i = 0; i <= 60; i++) {
if (MidiToFreq[i][0] == rx.byte2){
note = MidiToFreq[i][1];
}
}
if (note != 0) {
tone(8, note); //on joue sur le haut-parleur la note reçue par MIDI
}
}
if (rx.byte1 == 0x80) // message noteOff
{
noTone(8); // interruption de la note jouée sur le haut-parleur
digitalWrite(13, false); // on éteint la LED intégrée à la carte
}
}
} while (rx.header != 0);
}

Réglages du logiciel MIDI

Pour que le logiciel Virtual MIDI Piano Keyboard achemine les messages vers la carte Leonardo, il faut effectuer quelques réglages, en passant par "Connexions MIDI" dans le menu Éditer.


Si la carte est branchée à un port USB de l'ordinateur, "Arduino Leonardo" devrait être disponible dans la liste "Connexion du port de sortie".



Chaque fois que vous cliquez sur une touche du clavier de piano dans la fenêtre du logiciel Virtual MIDI Piano Keyboard, la note se fait entendre dans le haut-parleur branché à l'Arduino (pour que toutes les touches fonctionnent, réglez le paramètre "Octave de base" à 3).

1 commentaire:

  1. remarquez que la pertinence du projet est un peu discutable: la carte de son de l'ordinateur produit un son de bien meilleur qualité que la fonction tone de l'Arduino...

    Oui mais c'est 100 fois plus fun !
    Bravo pour tous ces montages et expériences que je découvre avec bonheur (Traceur Série/Oscilloscope, frequencemètre).
    Il est tard, mais je sens que je vais revenir dès demain sur ton site :-)

    RépondreSupprimer