Cet article a été mis à jour le 6 décembre 2020 (compatibilité avec la version actuelle de la bibliothèque MIDI).
Après avoir transformé mon Arduino en séquenceur MIDI, voici un projet où l'Arduino servira plutôt d'arpégiateur MIDI.
Lorsque cet arpégiateur est branché à un clavier MIDI, il s'agit d'enfoncer quelques touches du clavier de façon à former un accord: votre clavier se met alors à jouer les notes qui correspondent aux touches enfoncées, mais de façon séquentielle (arpège). Cet arpège est jouée en boucle, à une vitesse réglable par un potentiomètre, même après que les touches du clavier aient été relâchées. Vous formez un autre accord sur le clavier et le nouvel arpège est joué en boucle...vous voilà transformé en virtuose de la musique nouvel-âge! L'intérêt de ce dispositif, c'est que vous pouvez obtenir des effets très intéressants en exécutant l'arpège beaucoup plus rapidement que vous ne pourriez le faire vous-mêmes, et vos mains peuvent jouer autre chose pendant que les arpèges sont répétés.
Le circuit
Le circuit est le même que pour mon séquenceur, mais avec un bouton et une LED en moins: donc un Arduino Uno auquel on branchera un circuit de communication MIDI, un interrupteur, une LED indicatrice et deux potentiomètres.
Je présente donc pour la troisième fois le schéma du circuit de communication MIDI, pour plus de détails je vous invite à consulter l'article complet. Il existe des shields déjà prêts à l'emploi, le plus connu est probablement celui conçu par Sparkfun
Sans surprises l'interrupteur "on-off" servira à mettre l'arpégiateur en fonction, et à l'arrêter (sinon, vos arpèges continueraient de jouer jusqu'à ce que vous débranchiez l'Arduino...). Remarquez qu'il s'agit d'un interrupteur à deux positions (on-off) et non d'un bouton-poussoir momentané. Cet interrupteur est placé entre l'entrée 7 de l'Arduino et la masse (GND). Nul besoin d'ajouter une résistance, puisque le sketch utilise la résistance pull-up interne de cette broche.
La LED s'allumera pour indiquer que l'arpégiateur est en fonction: on la branche entre la broche 9 de l'Arduino et la masse (GND), en n'oubliant pas de lui associer une résistance protectrice de 220 Ω.
Finalement, un premier potentiomètre (de 10 kΩ ou plus) est branché à l'entrée analogique A0 de façon à contrôler la vitesse à laquelle les arpèges seront exécutés. J'ai aussi ajouté un deuxième potentiomètre (branché à A1) qui permet de modifier le programme MIDI, c'est à dire la sonorité utilisée par votre clavier pour jouer les sons (onde carrée, piano, cornemuse, etc.). Ce potentiomètre n'est pas essentiel, mais il peut permettre des effets intéressants.
Le dessin ci-dessous illustre toutes les connexions autres que la liaison MIDI qui avait déjà été illustrée plus haut.
La bibliothèque MIDI
Pour utiliser avec succès le sketch qui se trouve à la fin de cet article, il faut avoir installé la bibliothèque MIDI de Forty Seven Effects. Pour ce faire, on peut passer par le gestionnaire de bibliothèques.
Le sketch
Il faut d'abord savoir quelles touches du clavier sont enfoncées. Puisque le protocole MIDI fonctionne à base de messages "note on" (lorsqu'une nouvelle touche est enfoncée) et "note off" (lorsqu'une touche est relâchée), le sketch utilise ces messages pour tenir à jour un registre des touches enfoncées (c'est le tableau touchesActives[]).
La première version de mon sketch se contentait de jouer en arpèges les touches enfoncées, et les arpèges s'interrompaient aussitôt qu'on relâchait les notes. Cette interruption engendrait un effet sonore plutôt désagréable chaque fois qu'on changeait d'accord sur le clavier, c'est pourquoi j'ai modifié mon sketch pour que les arpèges continuent d'être joués après que les touches aient été relâchées.
Ça complique un peu le programme, car il est impossible pour le musicien de relâcher toutes les touches exactement au même moment: on attend donc qu'un même accord soit maintenu pendant au moins 50 millisecondes avant de le copier dans le tableau notesActives[], qui contient les notes qui doivent être jouées en arpège.
Voilà! Bien entendu, il serait relativement facile de fusionner ce sketch avec celui du séquenceur pour qu'un même appareil puisse remplir n'importe laquelle de ces deux fonctions.
-
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/**************************************************** | |
Arpégiateur MIDI | |
Entrée: des accords joués sur un clavier MIDI | |
Sortie: ces mêmes accords joués sous la forme d'arpèges | |
http://electroniqueamateur.blogspot.com/2014/01/fabrication-dun-arpegiateur-midi-base.html | |
*****************************************************/ | |
#include <MIDI.h> // bibliothèque MIDI: https://github.com/FortySevenEffects/arduino_midi_library | |
#define nombreMaxDeNotes 8 // nombre maximal de notes différentes dans l'arpège | |
// (peut être augmenté si vous avez beaucoup, beaucoup de doigts) | |
#define tempoPot A0 //potentiomètre qui contrôle la vitesse d'exécution | |
#define programPot A1 // potentiomètre qui contrôle le timbre du clavier | |
#define boutonOnOff 7 // bouton on/off | |
#define ledOnOff 9 // Led indicatrice on/off | |
int touchesActives[nombreMaxDeNotes]; // tableau contenant le numéro des touches enfoncées sur le clavier | |
int combienDeTouches = 0; // combien de touches du clavier sont présentement enfoncées | |
int notesActives[nombreMaxDeNotes]; // tableau contenant le numéro des notes à jouer en arpège | |
int combienDeNotes = 0; // combien de notes à jouer dans l'arpège | |
int delaiEntreLesNotes; // en millisecondes | |
unsigned long previousNoteTime = 0; // moment où la dernière note a été jouée (en millisecondes) | |
unsigned long previousTouchTime = 0; // dernière fois où une touche a été pressée ou relâchée | |
int playIndex = 0; // numéro de la note à jouer dans l'arpège | |
int program; // numéro de l'instrument utilisé pour jouer les notes | |
int arpegiateurOn = 0; // devient 1 lorsque l'arpégiateur est en fonction | |
int previousArpegiateurOn = 0; // 1 si l'arpégiateur était en fonction à l'itération précédente | |
int derniereNoteJouee = 0; // numéro de la dernière note jouée | |
int mettreAJour = 0; // 1 si une mise à jour des notes est requise | |
MIDI_CREATE_DEFAULT_INSTANCE(); | |
void setup() { | |
MIDI.begin(MIDI_CHANNEL_OMNI); | |
MIDI.turnThruOff (); // pour ce sketch, on ne veut pas retourner le message au clavier | |
MIDI.setHandleNoteOn(handleNoteOn); // fonction exécutée lors d'un message NoteOn | |
MIDI.setHandleNoteOff(handleNoteOff); // fonction exécutée lors d'un message NoteOff | |
// initialisation de la LED indicatrice | |
pinMode(ledOnOff, OUTPUT); | |
// initialisation du bouton | |
pinMode(boutonOnOff, INPUT); | |
digitalWrite(boutonOnOff, HIGH); // on active la résistance pullup interne | |
} | |
void handleNoteOn(byte channel, byte note, byte velocity) { | |
int number, holder; | |
if (arpegiateurOn) { | |
previousTouchTime = millis(); | |
mettreAJour = 1; | |
number = MIDI.getData1(); // quelle touche a été enfoncée? | |
if (combienDeTouches <= nombreMaxDeNotes - 1) { | |
touchesActives[combienDeTouches] = number; // mise à jour de la liste des notes actives | |
combienDeTouches = combienDeTouches + 1; //nombre de notes jouées | |
} | |
// on fait un tri du tableau, puisqu'il a changé | |
trierTableau(); | |
} | |
} | |
void handleNoteOff(byte channel, byte note, byte velocity) { | |
int number, index, holder; | |
if (arpegiateurOn) { | |
previousTouchTime = millis(); | |
mettreAJour = 1; | |
number = MIDI.getData1(); // quelle touche a été relâchée? | |
if (combienDeTouches > 0) { | |
for (int i = 0; i < combienDeTouches; i++) { | |
if (touchesActives[i] == number) { | |
touchesActives[i] = 0; | |
index = i; // position de la note effacée | |
} | |
} | |
// on repousse ce zéro à la fin de l'Array | |
for (int i = index; i < combienDeTouches - 1; i++) { | |
touchesActives[i] = touchesActives[i + 1]; | |
} | |
touchesActives[combienDeTouches - 1] = 0; | |
combienDeTouches = combienDeTouches - 1; //nombre de notes jouées | |
} | |
// on fait un tri du tableau, puisqu'il a changé | |
trierTableau(); | |
} | |
} | |
void trierTableau() { | |
int holder; | |
for (int x = 0; x < combienDeNotes; x++) | |
for (int y = 0; y < combienDeNotes - 1; y++) | |
if (notesActives[y] > notesActives[y + 1]) { | |
holder = notesActives[y + 1]; | |
notesActives[y + 1] = notesActives[y]; | |
notesActives[y] = holder; | |
} | |
} | |
void loop() { | |
// lecture du bouton on/off | |
arpegiateurOn = !digitalRead(boutonOnOff); | |
// la LED s'allume si l'arpégiateur est actif | |
digitalWrite(ledOnOff, arpegiateurOn); | |
if (!arpegiateurOn && previousArpegiateurOn) { // on vient tout juste d'éteindre | |
MIDI.sendNoteOn(derniereNoteJouee, 0, 1); | |
combienDeNotes = 0; | |
previousArpegiateurOn = 0; | |
} | |
if (arpegiateurOn) { | |
previousArpegiateurOn = 1; | |
MIDI.read(); // on vérifie si une touche a été enfoncée ou relâchée | |
// une mise à jour des notes de l'arpège est-elle requise? | |
// (si au moins une touche est enfoncée sans modification depuis au moins 50 ms) | |
if (combienDeTouches && ((millis() - previousTouchTime) > 50) && mettreAJour) { | |
combienDeNotes = combienDeTouches; | |
for (int i = 0; i < combienDeTouches; i++) { | |
notesActives[i] = touchesActives[i]; | |
} | |
mettreAJour = 0; | |
} | |
// et maintenant, on joue les arpèges: | |
if (combienDeNotes) { // il y a des notes à jouer | |
// lecture du potentiomètre de tempo | |
delaiEntreLesNotes = 30 + analogRead(tempoPot); | |
// lecture du potentiomètre de Programme | |
// on peut diviser par un nombre plus grand que 8 pour avoir moins de programmes possibles, | |
// mais meilleure stabilité | |
if (program != analogRead(programPot) / 8) { // le programme doit changer | |
program = analogRead(programPot) / 8; | |
MIDI.sendProgramChange(program, 1); // numéro de programme, canal | |
} | |
if ((millis() - previousNoteTime) >= delaiEntreLesNotes) { // c'est le temps de jouer une note | |
previousNoteTime = millis(); | |
MIDI.sendNoteOn(derniereNoteJouee, 0, 1); // on arrête la note précédente | |
MIDI.sendNoteOn(notesActives[playIndex], 127, 1); | |
derniereNoteJouee = notesActives[playIndex]; | |
playIndex = playIndex + 1; | |
if (playIndex >= combienDeNotes) { // on retourne au début de la mélodie | |
playIndex = 0; | |
} | |
} // if ((millis() - previousNoteTime) >= delaiEntreLesNotes) | |
} // if combienDeNotes | |
} // if arpegiateur on | |
} // fin du loop |
À lire également
Beaucoup d'autres projets MIDI avec l'Arduino:
- Communication MIDI OUT avec une carte Arduino
- Fabrication d'un module MIDI (in et out) pour Arduino
- Jouer des fichiers MIDI avec Arduino
- S'entraîner à lire les notes sur une portée avec Arduino
- Séquenceur MIDI à base d'Arduino
- Identificateur d'accords MIDI
- Clavier MIDI à base d'Arduino
- Pédalier d'orgue MIDI à base d'Arduino
- Flûte à bec MIDI à base d'Arduino
- MIDI par usb avec Arduino Leonardo
- MIDI sans fil avec Arduino
Aucun commentaire:
Enregistrer un commentaire