====== Contrôleur MIDI ====== {{ :projets:dsc00183.jpg?direct&400|}} * Porteur du projet : Réso-nance / Art de Vivre * Date : décembre / 2019 * Licence : libre ! * Fichiers : {{ :projets:artdevivre:piano.zip |code Arduino}} * Lien : [[https://www.lartdevivre.org/165-rien-n-arrive-et-ca-arrive-souvent|page du spectacle]] {{tag>MIDI arduino récupération recyclage théatre}}: ===== Description ===== Dans le cadre de la création de son spectacle **Rien n'arrive ! Et ça arrive souvent !**, la compagnie [[https://www.lartdevivre.org/|l'Art de Vivre]] nous a confié la fabrication d'un contrôleur MIDI utilisant des leviers pour déclencher des sons. L'association [[https://laissezpasser.fr/|Laisser Passer]] nous a permis d'extraire de leur matériaux portuaires à recycler huit leviers articulés en aluminium qui seront la base du contrôleur. Ces huit levier ON/OFF actionnerons des sons, un neuvième levier gradué permettra de régler un volume ou des effets et deux entrées pour pédale d'expression ou switch en complétera le jeu. Les pièces nécessaires à ce fonctionnement (butées avant et arrières et le ressort de rappel, maintien des boutons poussoirs...) ont été conçues autour de ces leviers et découpé au LFO. Enfin, un cadre maintenant solidement le tout à été fabriqué en acier soudé. ===== Matériaux ===== * Leviers : récupération portuaire issu du stock de [[https://laissezpasser.fr/|Laisser Passer]] * Socle : profilé en L acier 4mm, boulons en U * Mécanique : PVC 10mm et PVC 5mm usiné à la fraiseuse numérique * Électronique : arduino Leonardo, boutons étanches de récupération, potentiomètre ===== code ===== Afin d'éviter les redondances dans le code, les entrées sont déclarées comme des //structs// contenant toutes les variables qui se réfèrent à l'entrée : numéro de pin, durée d'anti-rebond, note midi émise, valeur actuelle, valeur précédente... Ces //structs// sont ajoutés dans deux tableaux, l'un contenant les capteurs analogiques, l'autre les capteurs numériques. L'initialisation de toutes les entrées ainsi que leur traitement peut ainsi se faire sous forme de **boucle for**. Le midi est géré par la lib //MIDIUSB// de //Gary Grewal//. Des événements //note-on// et //note-off// sont envoyés quand un interrupteur est actionné et des //control changes// dès qu'une entrée analogique est bougée (pédale ou levier gradué). Chaque bouton est assigné à une note midi de C0 à B0 et les contrôles continus vont du numéro 20 au 22. Ce code implémente une zone morte autour de la dernière valeur analogique lue pour éviter l'envoi massif de messages non-significatifs. Toutefois comme l'Arduino offre une acquisition de 10bits (0~1023) et les valeurs MIDI restent bornées à 7bits (0~127 soit un demi-octet), la zone morte n'est pas nécessaire ici. Pour lire les valeurs brutes et calibrer les entrées analogiques, un **define** en première ligne peut être dé-commenté. Il transforme alors le port USB de l'arduino Leonardo non plus en périphérique MIDI mais en port série, permettant de lire sur le moniteur série d'Arduino les valeurs brutes et mise à l'échelle MIDI des capteurs telles qu'elles sont envoyées en mode normal. Les **#define** sont parfois ignorés pour les cartes Leonardo, Due et Micro par le pré-processeur des versions récentes d'arduino. le code téléchargeable en en-tête n'en possède pas pour rester compatible avec toutes les versions d'IDE d'Arduino. Le code du projet peut être consulté ci-dessous : ++++ arduinoLeonardo.ino| //#define CALIBRATION #ifndef CALIBRATION #include "MIDIUSB.h" #endif #define CHANNEL 0x1 #define DEBOUNCE 2 // in millis #define DEADBAND // 0~1023 static const unsigned int maxRate = 0; // in millis struct analog { String name; byte controllerNumber; unsigned int pin; unsigned int calibMin; unsigned int calibMax; unsigned int lastValue; unsigned int currentValue; unsigned int deadBand; }; analog analogs[] = { {"pot", 20, A0, 290, 930, 0, 0, 0}, {"pedal1", 21, A1, 0, 530, 0, 0, 0}, {"pedal2", 22, A2, 0, 530, 0, 0, 0} }; unsigned int analogsCount = sizeof(analogs)/sizeof(analog); struct digital { String name; byte midiNote; unsigned int pin; bool lastState; unsigned int debounce; long lastTriggered; }; digital digitals[] = { {"A0", 33, 2, true, DEBOUNCE, 0}, {"F0", 29, 3, true, DEBOUNCE, 0}, {"D0", 26, 4, true, DEBOUNCE, 0}, {"G0", 31, 5, true, DEBOUNCE, 0}, {"E0", 28, 6, true, DEBOUNCE, 0}, {"B0", 35, 7, true, DEBOUNCE, 0}, {"C0", 24, 8, true, DEBOUNCE, 0}, {"Bb0", 34, 9, true, DEBOUNCE, 0},}; unsigned int digitalsCount = sizeof(digitals)/sizeof(digital); void setup() { // setting up the digital inputs for (unsigned int i=0; i analogs[i].currentValue + analogs[i].deadBand) { #ifdef CALIBRATION Serial.println(analogs[i].name + ": RAW"+String(analogRead(analogs[i].pin))+", SCALED : "+ String(analogs[i].currentValue)); //analogs[i].lastValue = analogs[i].currentValue; #else byte ccValue = analogs[i].currentValue; controlChange(analogs[i].controllerNumber, ccValue); #endif delay(maxRate); } //} analogs[i].lastValue = analogs[i].currentValue; } // Reading digital inputs for (unsigned int i=0; i digitals[i].debounce) { #ifdef CALIBRATION Serial.println(digitals[i].name+":ON"); #else noteOn(digitals[i].midiNote, (byte) 127); #endif digitals[i].lastTriggered = millis(); } // input has been pulled HIGH if (currentState == HIGH && digitals[i].lastState == LOW && millis() - digitals[i].lastTriggered > digitals[i].debounce) { #ifdef CALIBRATION Serial.println(digitals[i].name+":OFF"); #else noteOff(digitals[i].midiNote); #endif digitals[i].lastTriggered = millis(); } digitals[i].lastState = currentState; } #ifndef CALIBRATION MidiUSB.flush(); #endif delay(5); } #ifndef CALIBRATION void noteOn(byte pitch, byte velocity) { midiEventPacket_t noteOn = {0x09, 0x90 | CHANNEL, pitch, velocity}; MidiUSB.sendMIDI(noteOn); } void noteOff(byte pitch) { midiEventPacket_t noteOff = {0x08, 0x80 | CHANNEL, pitch, 0x0}; MidiUSB.sendMIDI(noteOff); } void controlChange(byte control, byte value) { midiEventPacket_t event = {0x0B, 0xB0 | CHANNEL, control, value}; MidiUSB.sendMIDI(event); } #endif ++++ ===== Photos ===== {{gallery>?&crop&lightbox}}