1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
/****************************************************
* 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> // nous utilisons la MIDI library
#define nombreMaxDeNotes 42 // nombre de 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]; // array contenant le numéro des touches enfoncées sur le clavier
int combienDeTouches = 0; // combien de touches du clavier sont enfoncées
int notesActives[nombreMaxDeNotes]; // array 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
void setup() {
MIDI.begin(MIDI_CHANNEL_OMNI);
MIDI.turnThruOff (); // pour ce sketch, on ne veut pas retourner le message au clavier
// 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 loop() {
int type, channel, number, holder, index;
// 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;
if (MIDI.read()) { // réception d'un message MIDI
byte type = MIDI.getType();
switch (type) {
case NoteOn: // attention, ça peut être un noteOff si velocity est zéro
previousTouchTime = millis();
mettreAJour = 1;
number = MIDI.getData1(); // quelle touche a été enfoncée?
if (MIDI.getData2()){ // vélocité non-nulle: c'est un vrai noteOn
if (combienDeTouches <= nombreMaxDeNotes - 1){
touchesActives[combienDeTouches] = number; // mise à jour de la liste des notes actives
combienDeTouches = combienDeTouches + 1; //nombre de notes jouées
}
}
else{ // vélocité nulle: c'est un NoteOff, finalement
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 de l'array, puisqu'elle a changé
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;
}
break;
case NoteOff:
// ça n'arrive jamais avec mon clavier
channel = MIDI.getChannel();
break;
}
} // fin de réception du if (MIDI.read())
// 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
} |