====== BrutBox / Développements ====== ===== Cahier des charges ===== **Janvier 2015** : {{.:cahierdescharges-2015-01.pdf|}} * Nom : BrutBox * État de l'art : [[http://orguesensoriel.com/|Orgue Sensoriel]]. Refaire sensiblement la même chose en moins cher, en libre/reproductible, (en moins bien ergonomiquement ?) mais en plus intéressant musicalement. Les capteurs sont distingués pour les animateurs : **déclencheurs/variateurs**, afin qu'ils s'accaparent le dispositif. Notez la taille des capteurs, les couleurs, la fixation, la connectique en Jack et l'utilisation avec 1 seul handicapé et 1 animateur. * Entrées : kinect, accéleromètre sans fil, neurosky (sans routage), capteur distance, piezo pince, micro, crayon graphite, conductivité corps (genre makey makey), webcam (face tracking, fiducials, ...), gros boutons, pavé XY façon kaospad, tapis XY * Minimiser le champs d’intervention à un seul capteur. Possibilités de séries de capteurs identiques (ex:touches). * Interface : patchs musicaux (faible programmation) : Pure Data ou MaxMSP * Sorties : VST, sortie Midi (vers synthétiseur), 3D (Pure Data) * Production : Armada ===== Dev ===== * [[http://piratepad.net/brutboxv1|pad v1]] * [[projets:brutbox:v1b:accueil|brutbox v1.2]] * [[.:backv1:]] * [[projets:brutbox:dev:wireless:accueil|Malinette/Brutbox wireless]] * Dev version wirless - OSC : https://framagit.org/guiaum/EMI_WALLET (prevoir 10/15 minute de decoupe par cube (voir 45minutes sur mauvaise laser.. )+ temps assemblage assez long ... et 10€ de matos par boite) ==== État de l'art ==== {{.:orguesensoriel.jpg|}}\\ //[[http://orguesensoriel.com|Orgue Sensoriel]]// {{.:valise-pedagogique-interactive.jpg|}}\\ //[[http://jeromeabel.net/fr/code/valise-pedagogique-interactive|Valise Interactive]]// {{.:teenage-engineering-oplab.png|}}\\ //[[https://www.youtube.com/playlist?list=PLSM1HuwZomMhqBqJjoRpsohKnESq-q9LJ|OpLab]]// ===== Logiciel ===== ==== PARTHENAY - OCTOBRE 2016 ==== Résidence de développement au Foyer de vie Les Genêts. Cas d'empechements lourds.\\ == version en cours : == {{:projets:brutbox:dev:brutbox-prepa-parthenay_4.zip|Brutbox simplifiée - version intermédiaire - semaine n°2}} {{:projets:brutbox:dev:ecran-brutbox-parthenay.jpg|}} **POINTS ABORDÉS :**\\ Recherche de simplification du logiciel pour des personnels encadrants ne pratiquant pas ou peu l'informatique musicale: * Création d'une collection d'objets "débutant" contenant chacun un selecteur de son pré-établis; * Simplification des entrées audio présnetes par défaut sur les patchs vierges (bb-micro-in.pd) * Simplification des sorties audio (bb-audio-out-simple.pd) * Renforcer la distinction entre instruments à simple déclenchement (bouton action unique) et instruments à variations (progressif); * Simplification de l'interface pour la fenêtre menu débutant. cf proposition ci-dessous. {{:projets:brutbox:dev:ergo-main-brutbox-debutant.gif|}} == COLLECTION DÉBUTANT == **INSTRUMENTS (noms et système de typage à définir)**\\ **à action simples** * synth-batterie (**a faire**) * synth-bouton * synth-percussion **à variations** * synth-mono * synth-organ * synth-sirene * synth-mouche **EFFECTS (ergonomie a voir)**\\ * delay * flanger * pitch ==== GANTNER - FEVRIER 2016 ==== {{.:bb-2016-02-25-gantner.png|}} (résidence à l'Espace Gantner) :{{.:bb-2016-02-24-gantner.zip|}} Nouveautés : * Partition commune entre les collections d'objets communs à Brutbox et Malinette. * Sous menu dans le menu projet pour organiser les créations par dossier * intégration de l'objet IN "faceOSC" des petits debrouillards * intégration du bloc video dans les entrées bb !temporairement : les enregistrements Brutbox arrivent dans le dossier media/recording de la Malinette Cette version contient la séquence d'une dizaine d'exemples pour quelques heures d'atelier avec différents exercices : voix, effets audio, ondes cérébrale, guitare électronique, loopsampler, capteur lumière et sons binauraux... * Basé sur la Malinette et Pure Data Extended : https://git.framasoft.org/resonance/malinette/tree/master ===== Électronique ===== ==== Version sans fil - oSC ==== https://framagit.org/guiaum/EMI_WALLET **Décembre 2018 :** Par 3615 senor , basé sur ESP 8266 , batterie lipo , routeur wifi xiaomi, chargeur de lipo, et interrupteur ils pour eteindre chaque cube une fois rangé. 8-) **notice utilisation** * bb sans fil envoie vers 10.0.0.2 malinette * le routeur fixe l'addresse 10.0.0.2 a l'adresse MAC du pc d'eric * eric renvoie ensuite directe de pd vers d'autres IP oscin >>> oscout ==== Capteurs ==== * Externe : Joystick Thrustmaster® * Externe : Wiimote® (mac) >> Voir la page ressource [[materiel:wiimote:accueil|Wiimote]] * Infrarouge 3/30cm : 1 ana * infrarouge 20/150cm : 1 ana * Piezo (plaque) : 1 ana * Pression carré (plaque) : 1 ana * Micro electret : 1 ana * Gros bouton (~buzzer) : 1 ana * Module Joystick : 2 ana (prise dédiée) * Accéléromètre ou gyroscope ? : 2 ana (prise dédiée) * Touch : MPR121 **prises dédiées SCL/SDA - entrées digitales 5 & 6 D0/D1** * Encodeur potentiomètre (+ robinet ?) : **prises dédiées "INTERRUPTION" - entrées digitales 7 & 8 D2/D3** ==== MindWave ==== Nous utilisons un casque Mindwave neurosky pour capter les donnéees (médiation et concentration) d'un utilisateur. Nous utilisons **Processing** qui envoie les données en OSC à PureData (les bibliothèques oscP5 et MindsetProcessing sont nécessaires). ++++ Le code pour processing | import oscP5.*; import netP5.*; import processing.serial.*; import pt.citar.diablu.processing.mindset.*; boolean SEND_OSC = true; String OSC_ADDRESS = "127.0.0.1"; int OSC_PORT = 54321; String SERIAL_PORT = "/dev/tty.MindWaveMobile-DevA"; OscP5 oscP5; NetAddress myRemoteLocation; MindSet mindSet; void setup() { frameRate(20); oscP5 = new OscP5(this, 12345); myRemoteLocation = new NetAddress(OSC_ADDRESS, OSC_PORT); mindSet = new MindSet(this, SERIAL_PORT); } void draw() { } void exit() { //println("Exiting"); mindSet.quit(); super.exit(); } public void attentionEvent(int attentionLevel) { OscMessage myMessage = new OscMessage("/mindset/attentionlevel"); myMessage.add(attentionLevel); oscP5.send(myMessage, myRemoteLocation); } public void meditationEvent(int meditationLevel) { OscMessage myMessage = new OscMessage("/mindset/meditationlevel"); myMessage.add(meditationLevel); oscP5.send(myMessage, myRemoteLocation); } public void eegEvent(int delta, int theta, int low_alpha, int high_alpha, int low_beta, int high_beta, int low_gamma, int mid_gamma) { OscMessage myMessage = new OscMessage("/mindset/eeg"); myMessage.add(delta); myMessage.add(theta); myMessage.add(low_alpha); myMessage.add(high_alpha); myMessage.add(low_beta); myMessage.add(high_beta); myMessage.add(low_gamma); myMessage.add(mid_gamma); oscP5.send(myMessage, myRemoteLocation); } ++++ ==== Wiimote ==== Une piste d'utiliser la manette Wiimote pour creer un dispositif ou l'on peut changer de capteur. En démontant le nunchuk et en retirant le joystick nous pouvons utiliser deux entrées analogiques. Attention la wiimote est alimenté en 3.3v, donc nous sommes limité aux capteurs resistifs qui fonctionnent à cette tension. On utilise ensuite OSCULATOR (sur macOS) pour recevoir les données et les transformer en midi. [[materiel:wiimote:accueil|Voir page ressource Wiimote]] {{ .:nunchuck_hack.jpg?900 |}} {{ .:screen_shot_06-03-15_at_01.21_pm.png?900 |}} ==== Carte électronique ==== Nous utilisons pour le moment, la carte Teensy 2.0 qui permet de convertir en MIDI les données de nos capteurs. En guise de connectique nous avons opté pour des connecteurs USB (pour éviter les faux contacts).\\ === VERSION 1 === [[projets:brutbox:dev:carte|carte v1]] === VERSION 2 === [[projets:brutbox:dev:carte2|carte v2]] == Fournisseurs discounts (connecteurs et cables usb)== * [[https://www.accessoires-informatiques.com/Prix/Cordon-compatible-USB-20-2727.html|Cable USB A B]] * [[http://www.dx.com/p/usb-a-female-180-degree-dip-type-connector-socket-dc-30v-20-piece-pack-123937|USB A droit]] * [[http://www.dx.com/p/diy-usb-4-pin-female-type-b-90-degree-dip-socket-connector-silver-10-piece-pack-127645|USB B]] ===== Firmware Teensy ===== ==== Février 2016 ==== Après de nombreux autres test plus complexe on est revenu au plus simple et basique : ++++ teensy-8-in.ino | // the MIDI channel number to send messages const int channel = 1; // the MIDI continuous controller for each analog input const int controllerA0 = 1; // const int controllerA1 = 2; // const int controllerA2 = 3; // const int controllerA3 = 4; // const int controllerA4 = 5; // const int controllerA5 = 6; // const int controllerA6 = 7; // const int controllerA7 = 8; // void setup() { } // store previously sent values, to detect changes int previousA0 = -1; int previousA1 = -1; int previousA2 = -1; int previousA3 = -1; int previousA4 = -1; int previousA5 = -1; int previousA6 = -1; int previousA7 = -1; elapsedMillis msec = 0; void loop() { // only check the analog inputs 50 times per second, // to prevent a flood of MIDI messages if (msec >= 50) { msec = 0; int n0 = analogRead(A0) / 8; int n1 = analogRead(A1) / 8; int n2 = analogRead(A2) / 8; int n3 = analogRead(A3) / 8; int n4 = analogRead(A4) / 8; int n5 = analogRead(A5) / 8; int n6 = analogRead(A6) / 8; int n7 = analogRead(A7) / 8; // only transmit MIDI messages if analog input changed if (n0 != previousA0) { usbMIDI.sendControlChange(controllerA0, n0, channel); previousA0 = n0; } if (n1 != previousA1) { usbMIDI.sendControlChange(controllerA1, n1, channel); previousA1 = n1; } if (n2 != previousA2) { usbMIDI.sendControlChange(controllerA2, n2, channel); previousA2 = n2; } if (n3 != previousA3) { usbMIDI.sendControlChange(controllerA3, n3, channel); previousA3 = n3; } if (n4 != previousA4) { usbMIDI.sendControlChange(controllerA4, n4, channel); previousA4 = n4; } if (n5 != previousA5) { usbMIDI.sendControlChange(controllerA5, n5, channel); previousA5 = n5; } if (n6 != previousA6) { usbMIDI.sendControlChange(controllerA6, n6, channel); previousA6 = n6; } if (n7 != previousA7) { usbMIDI.sendControlChange(controllerA7, n7, channel); previousA7 = n7; } } // MIDI Controllers should discard incoming MIDI messages. // http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash while (usbMIDI.read()) { // ignore incoming messages } } ++++ ==== Olds Firmwares Teensy 2 ==== Réception des données MIDI à partir de Pure Data {{:projets:brutbox:dev:pd-brutbox-help.png?400|}} Envoie en 10 bits et réception avec pd avec la boite [<< 7] : int value = 1023; Serial.begin(9600); Serial.println(value >> 7); // ou Serial.println(value & 0x7F); ++++ teensy_brutbox.ino (12 ana + encoder,sans on/off, sans capa) | /* * TEENSY 2 for BRUTBOX * Analog sensors + encoder + touch * * Licence : GNU/GPL3 * Date : 12/06/2015 * Website : http://reso-nance.org/wiki/projets/malinette-brutbox * * Hardware add-on : the MPR121 module for touch sensors * * Midi mapping : * 12 analog sensors (midi controller from 0 to 11) * 1 encoder (midi controller 12) */ // Include libraries #include // Midi channel const int channel = 1; // Analog setup int anaPins[] = {22,11,12,13,14,15,16,17,18,19,20,21}; // analog pins const int anaNb = 12; // number of inputs int anaCtl[] = {11,10,9,8,7,6,5,4,3,2,1,0}; // controller in int anaValues[anaNb]; // current analog values int anaLastValues[anaNb]; // previous analog values // Encoder setup Encoder encoderSensor (7, 8); long encoderOldPosition = -999; long encoderNewPosition; long encoderLastPosition; // Sampling rate elapsedMillis msec = 0; void setup() { } void loop() { if (msec >= 40) { msec = 0; // Analog sensors loop for (int i = 0; i < anaNb; i++) { anaValues[i] = (int) analogRead(anaPins[i]) / 8 ; if (anaValues[i] != anaLastValues[i]) { usbMIDI.sendControlChange(anaCtl[i], anaValues[i], channel); anaLastValues[i] = anaValues[i]; } } // Encoder loop encoderNewPosition = encoderSensor.read(); if (encoderNewPosition != encoderOldPosition) { if (encoderNewPosition > encoderOldPosition) {usbMIDI.sendControlChange(12, 0, channel);} else if (encoderNewPosition < encoderOldPosition) {usbMIDI.sendControlChange(12, 127, channel);} encoderOldPosition = encoderNewPosition; } } while (usbMIDI.read()) { // Discard incoming MIDI messages. } } ++++ ++++ teensy_brutbox.ino (8 analogique simple , pas de librairie encoder, wire, capacitif...) | // the MIDI channel number to send messages const int channel = 1; // the MIDI continuous controller for each analog input const int controllerA0 = 0; // 10 = pan position const int controllerA1 = 1; // 11 = volume/expression const int controllerA2 = 2; // 91 = reverb level const int controllerA3 = 3; // 93 = chorus level const int controllerA4 = 4; // 93 = chorus level const int controllerA5 = 5; // 93 = chorus level const int controllerA6 = 6; // 10 = pan position const int controllerA7 = 7; // 11 = volume/expression const int controllerA8 = 8; // 91 = reverb level const int controllerA9 = 9; // 93 = chorus level const int controllerA10 = 10; // 93 = chorus level const int controllerA11 = 11; // 93 = chorus level void setup() { } // store previously sent values, to detect changes int previousA0 = -1; int previousA1 = -1; int previousA2 = -1; int previousA3 = -1; int previousA4 = -1; int previousA5 = -1; int previousA6 = -1; int previousA7 = -1; int previousA8 = -1; int previousA9 = -1; int previousA10 = -1; int previousA11 = -1; elapsedMillis msec = 0; void loop() { // only check the analog inputs 50 times per second, // to prevent a flood of MIDI messages if (msec >= 50) { msec = 0; int n0 = analogRead(A0) / 8; int n1 = analogRead(A1) / 8; int n2 = analogRead(A2) / 8; int n3 = analogRead(A3) / 8; int n4 = analogRead(A4) / 8; int n5 = analogRead(A5) / 8; int n6 = analogRead(A6) / 8; int n7 = analogRead(A7) / 8; int n8 = analogRead(A8) / 8; int n9 = analogRead(A9) / 8; int n10 = analogRead(A10) / 8; int n11 = analogRead(A11) / 8; // only transmit MIDI messages if analog input changed if (n0 != previousA0) { usbMIDI.sendControlChange(controllerA0, n0, channel); previousA0 = n0; } if (n1 != previousA1) { usbMIDI.sendControlChange(controllerA1, n1, channel); previousA1 = n1; } if (n2 != previousA2) { usbMIDI.sendControlChange(controllerA2, n2, channel); previousA2 = n2; } if (n3 != previousA3) { usbMIDI.sendControlChange(controllerA3, n3, channel); previousA3 = n3; } if (n4 != previousA4) { usbMIDI.sendControlChange(controllerA4, n4, channel); previousA4 = n4; } if (n5 != previousA5) { usbMIDI.sendControlChange(controllerA5, n5, channel); previousA5 = n5; } if (n6 != previousA6) { usbMIDI.sendControlChange(controllerA6, n6, channel); previousA6 = n6; } if (n7 != previousA7) { usbMIDI.sendControlChange(controllerA7, n7, channel); previousA7 = n7; } if (n8 != previousA8) { usbMIDI.sendControlChange(controllerA8, n8, channel); previousA8 = n8; } if (n9 != previousA9) { usbMIDI.sendControlChange(controllerA9, n9, channel); previousA9 = n10; } if (n10 != previousA10) { usbMIDI.sendControlChange(controllerA10, n10, channel); previousA4 = n10; } if (n11 != previousA11) { usbMIDI.sendControlChange(controllerA11, n11, channel); previousA11 = n11; } } // MIDI Controllers should discard incoming MIDI messages. // http://forum.pjrc.com/threads/24179-Teensy-3-Ableton-Analog-CC-causes-midi-crash while (usbMIDI.read()) { // ignore incoming messages } } ++++ ++++ teensy_brutbox.ino (sans on off pour MAC) | /* * TEENSY 2 for BRUTBOX * Analog sensors + encoder + touch * * Licence : GNU/GPL3 * Date : 12/06/2015 * Website : http://reso-nance.org/wiki/projets/malinette-brutbox * * Hardware add-on : the MPR121 module for touch sensors * * Midi mapping : * 12 analog sensors (midi controller from 0 to 11) * 1 encoder (midi controller 12) * 12 touch sensors (midi note from 60 to 71) */ // Include libraries #include #include "Adafruit_MPR121.h" #include // Midi channel const int channel = 1; // Analog setup int anaPins[] = {22,11,12,13,14,15,16,17,18,19,20,21}; // analog pins const int anaNb = 12; // number of inputs int anaCtl[] = {11,10,9,8,7,6,5,4,3,2,1,0}; // controller in int anaValues[anaNb]; // current analog values int anaLastValues[anaNb]; // previous analog values // Encoder setup Encoder encoderSensor (7, 8); long encoderOldPosition = -999; long encoderNewPosition; long encoderLastPosition; // Capacitive Touch MPR121 module // Connection Teensy2 // USB wiring : d+ : SDA, d- : SCL, SCL = DO, SDA = D1 Adafruit_MPR121 cap = Adafruit_MPR121(); uint16_t lasttouched = 0; uint16_t currtouched = 0; const int touchNb = 12; // number of touch inputs int touchCtl[] = {60,61,62,63,64,65,66,67,68,69,70,71}; // note in // Sampling rate elapsedMillis msec = 0; void setup() { // Trying to connect to the capacitive module if (!cap.begin(0x5A)) { while (1); } delay(1000); } void loop() { if (msec >= 20) { msec = 0; // Analog sensors loop for (int i = 0; i < anaNb; i++) { anaValues[i] = (int) analogRead(anaPins[i]) / 8 ; if (anaValues[i] != anaLastValues[i]) { usbMIDI.sendControlChange(anaCtl[i], anaValues[i], channel); anaLastValues[i] = anaValues[i]; } } // Encoder encoderNewPosition = encoderSensor.read(); if (encoderNewPosition != encoderOldPosition) { if (encoderNewPosition > encoderOldPosition) {usbMIDI.sendControlChange(12, 0, channel);} else if (encoderNewPosition < encoderOldPosition) {usbMIDI.sendControlChange(12, 127, channel);} encoderOldPosition = encoderNewPosition; } // Capacitive loop currtouched = cap.touched(); for (uint8_t i=0; i < touchNb; i++) { if ((currtouched & _BV(i)) && !(lasttouched & _BV(i)) ) {usbMIDI.sendNoteOn(touchCtl[i], 127, channel);} if (!(currtouched & _BV(i)) && (lasttouched & _BV(i)) ) {usbMIDI.sendNoteOn(touchCtl[i], 0, channel);} } lasttouched = currtouched; // reset our state } while (usbMIDI.read()) { // Discard incoming MIDI messages. } } ++++ ++++ teensy_brutbox.ino (avec on off) | /* * TEENSY 2 for BRUTBOX * Control inputs (sensors) with MIDI messages * * Licence : GNU/GPL3 * Date : 11/06/2015 * Website : http://reso-nance.org/wiki/projets/malinette-brutbox * * Hardware add-on : the MPR121 module for touch sensors * * Midi mapping : * 12 analog sensors (midi controller from 0 to 11) * 1 encoder (midi controller 12) * 12 touch sensors (midi note from 60 to 71) */ // Include libraries #include #include "Adafruit_MPR121.h" #include // Midi channel const int channel = 1; // Capacitive Touch MPR121 module // Connection Teensy2 // USB wiring : d+ : SDA, d- : SCL, SCL = DO, SDA = D1 Adafruit_MPR121 cap = Adafruit_MPR121(); uint16_t lasttouched = 0; uint16_t currtouched = 0; const int touchNb = 12; // number of touch inputs const int touchThreshold = 60; int touchStateCtl[] = {40, 41, 42} ; // touch on/off int touchState[touchNb]; // state : on/off //int currentTouchValues[touchNb]; //int lastTouchValues[touchNb]; int touchCtl[] = {60,61,62,63,64,65,66,67,68,69,70,71}; // note in int touchOn = 0; // Analog setup int anaPins[] = {22,11,12,13,14,15,16,17,18,19,20,21}; // analog pins const int anaNb = 12; // number of inputs int anaCtl[] = {11,10,9,8,7,6,5,4,3,2,1,0}; // controller in int anaStateCtl[] = {20, 21} ; // sensor on (20), sensor off (21) int anaState[anaNb]; // state : on/off int anaValues[anaNb]; // current analog values int anaLastValues[anaNb]; // previous analog values // Encoder setup Encoder encoderSensor (7, 8); long encoderOldPosition = -999; long encoderNewPosition; long encoderLastPosition; int encoderStateCtl = 13; // receive ctlout 13 int encoderOn = 0; // Sampling rate elapsedMillis msec = 0; int rate = 20; void setup() { // Midi receive : on/off sensors usbMIDI.setHandleControlChange(OnControlChange); } void loop() { if (msec >= rate) { msec = 0; // Analog sensors loop for (int i = 0; i < anaNb; i++) { if(anaState[i] == 1) { // check first if the sensor is on anaValues[i] = (int) analogRead(anaPins[i]) / 8 ; if (anaValues[i] != anaLastValues[i]) { usbMIDI.sendControlChange(anaCtl[i], anaValues[i], channel); anaLastValues[i] = anaValues[i]; } } } // Capacitive loop if(touchOn == 1){ currtouched = cap.touched(); for (uint8_t i=0; i < touchNb; i++) { if(touchState[i] == 1) { // check first if the sensor is on if ((currtouched & _BV(i)) && !(lasttouched & _BV(i)) ) { usbMIDI.sendNoteOn(touchCtl[i], 127, channel); } if (!(currtouched & _BV(i)) && (lasttouched & _BV(i)) ) { usbMIDI.sendNoteOn(touchCtl[i], 0, channel); } } } lasttouched = currtouched; // reset our state } // Encoder if (encoderOn == 1) { encoderNewPosition = encoderSensor.read(); if (encoderNewPosition != encoderOldPosition) { if (encoderNewPosition > encoderOldPosition) { usbMIDI.sendControlChange(12, 0, channel); } else if (encoderNewPosition < encoderOldPosition) { usbMIDI.sendControlChange(12, 127, channel); } encoderOldPosition = encoderNewPosition; usbMIDI.sendControlChange(12, encoderNewPosition, channel); } } } while (usbMIDI.read()) { // Discard incoming MIDI messages. } } // Receive Midi Control Change void OnControlChange(byte channel, byte control, byte value) { // Analog sensors on/off if (control == anaStateCtl[0]) {anaState[-value+(anaNb-1)] = 0;} else if (control == anaStateCtl[1]) {anaState[-value+(anaNb-1)] = 1;} else if (control == touchStateCtl[0]) {touchState[value] = 0;} else if (control == touchStateCtl[1]) {touchState[value] = 1;} else if (control == touchStateCtl[2]) { touchOn = value; if (touchOn == 1) {cap.begin(0x5A);} } else if (control == encoderStateCtl) {encoderOn = value;} } ++++ ++++ teensy-onoff_no-capacitif.ino (cc de 20 à 31 - non attribués / sensor on(46), sensor off(47) ) | // Include libraries #include //#include "Adafruit_MPR121.h" #include // Midi channel const int channel = 1; // Analog setup int anaPins[] = {22,11,12,13,14,15,16,17,18,19,20,21}; // analog pins const int anaNb = 12; // number of inputs int anaCtl[] = {20,21,22,23,24,25,26,27,28,29,30,31}; // cc non-attribués int anaStateCtl[] = {46, 47} ; // sensor on (46), sensor off (47) int anaState[anaNb]; // state : on/off int anaValues[anaNb]; // current analog values int anaLastValues[anaNb]; // previous analog values // Encoder setup Encoder encoderSensor (7, 8); long encoderOldPosition = -999; long encoderNewPosition; long encoderLastPosition; int encoderStateCtl = 13; // receive ctlout 13 int encoderOn = 0; // Sampling rate elapsedMillis msec = 0; int rate = 20; void setup() { // Midi receive : on/off sensors usbMIDI.setHandleControlChange(OnControlChange); } void loop() { if (msec >= rate) { msec = 0; // Analog sensors loop for (int i = 0; i < anaNb; i++) { if(anaState[i] == 1) { // check first if the sensor is on anaValues[i] = (int) analogRead(anaPins[i]) / 8 ; if (anaValues[i] != anaLastValues[i]) { usbMIDI.sendControlChange(anaCtl[i], anaValues[i], channel); anaLastValues[i] = anaValues[i]; } } } // Encoder if (encoderOn == 1) { encoderNewPosition = encoderSensor.read(); if (encoderNewPosition != encoderOldPosition) { if (encoderNewPosition > encoderOldPosition) { usbMIDI.sendControlChange(12, 0, channel); } else if (encoderNewPosition < encoderOldPosition) { usbMIDI.sendControlChange(12, 127, channel); } encoderOldPosition = encoderNewPosition; usbMIDI.sendControlChange(12, encoderNewPosition, channel); } } } while (usbMIDI.read()) { // Discard incoming MIDI messages. } } // Receive Midi Control Change void OnControlChange(byte channel, byte control, byte value) { // Analog sensors on/off if (control == anaStateCtl[0]) {anaState[-value+(anaNb-1)] = 0;} else if (control == anaStateCtl[1]) {anaState[-value+(anaNb-1)] = 1;} else if (control == encoderStateCtl) {encoderOn = value;} } ++++ ++++ test-nrpn.ino (sur 1 capteur analo A0) !! mais erreur de compilation… | // Fixed values, for demonstration uint32_t channel = 1; // channels are 1 to 16 uint32_t param = 0; // your parameter number here, 0 to 16k //uint32_t val = 2; // your value here, 0 to 16k // in actual use this would come from some physical controller like an analog value // or be computed by monitoring an encoder void sendNRPNHR(uint32_t parameter, uint32_t value, uint32_t channel) { // Send an arbitrary 14-bit value to an arbitrary 14-bit non-registered parameter // Note that param MSB and LSB are shared between RPN and NRPN, so set both at once // Also, null out the RPN (and NRPN) active parameter (best practice) after data is sent (as it persists) // Control change 99 for NRPN, MSB of param usb_midi_write_packed(0xB00B | (((channel - 1) & 0x0F) << 8) | ((99 & 0x7F) << 16) | ((parameter & 0x7F) << 24)); // Control change 98 for NRPN, LSB of param usb_midi_write_packed(0xB00B | (((channel - 1) & 0x0F) << 8) | ((98 & 0x7F) << 16) | (((parameter >>7) & 0x7F) << 24)); // Control change 6 for Data Entry MSB of value usb_midi_write_packed(0xB00B | (((channel - 1) & 0x0F) << 8) | ((6 & 0x7F) << 16) | ((value & 0x7F) << 24)); // Control change 38 for Data Entry LSB of param usb_midi_write_packed(0xB00B | (((channel - 1) & 0x0F) << 8) | ((38 & 0x7F) << 16) | (((value >>7) & 0x7F) << 24)); // Now null out active parameter by sending null (127, 0x7F) as MSB and LSB // Control change 101 for RPN, MSB of param usb_midi_write_packed(0xB00B | (((channel - 1) & 0x0F) << 8) | ((101 & 0x7F) << 16) | (0x7F << 24)); // Control change 100 for NRPN, LSB of param usb_midi_write_packed(0xB00B | (((channel - 1) & 0x0F) << 8) | ((100 & 0x7F) << 16) | (0x7F << 24)); } void setup() { } // store previously sent values, to detect changes int previousA0 = -1; elapsedMillis msec = 0; void loop() { // only check the analog inputs 50 times per second, // to prevent a flood of MIDI messages if (msec >= 80) { msec = 0; int n0 = analogRead(A0); if (n0 != previousA0) { //int valA0 = map(n0, 0, 1023, 0, 16383); sendNRPNHR(param, n0, 1); // channel 1 previousA0 = n0; } } } /////////////////////////////////// LOG ERREURS ////////////////////////////////////////////////////// Arduino : 1.6.7 (Mac OS X), TD: 1.27, Carte : "Teensy 2.0, MIDI, 16 MHz, US English" /Users/zinc5/Documents/Arduino/test-nrpn2/test-nrpn2.ino: In function 'void sendNRPNHR(uint32_t, uint32_t, uint32_t)': /Users/zinc5/Documents/Arduino/test-nrpn2/test-nrpn2.ino:14:83: warning: left shift count >= width of type [enabled by default] usb_midi_write_packed(0xB00B | (((channel - 1) & 0x0F) << 8) | ((99 & 0x7F) << 16) | ((parameter & 0x7F) << 24)); ^ /Users/zinc5/Documents/Arduino/test-nrpn2/test-nrpn2.ino:14:115: error: 'usb_midi_write_packed' was not declared in this scope usb_midi_write_packed(0xB00B | (((channel - 1) & 0x0F) << 8) | ((99 & 0x7F) << 16) | ((parameter & 0x7F) << 24)); ^ /Users/zinc5/Documents/Arduino/test-nrpn2/test-nrpn2.ino:16:83: warning: left shift count >= width of type [enabled by default] usb_midi_write_packed(0xB00B | (((channel - 1) & 0x0F) << 8) | ((98 & 0x7F) << 16) | (((parameter >>7) & 0x7F) << 24)); ^ /Users/zinc5/Documents/Arduino/test-nrpn2/test-nrpn2.ino:18:82: warning: left shift count >= width of type [enabled by default] usb_midi_write_packed(0xB00B | (((channel - 1) & 0x0F) << 8) | ((6 & 0x7F) << 16) | ((value & 0x7F) << 24)); ^ /Users/zinc5/Documents/Arduino/test-nrpn2/test-nrpn2.ino:20:83: warning: left shift count >= width of type [enabled by default] usb_midi_write_packed(0xB00B | (((channel - 1) & 0x0F) << 8) | ((38 & 0x7F) << 16) | (((value >>7) & 0x7F) << 24)); ^ /Users/zinc5/Documents/Arduino/test-nrpn2/test-nrpn2.ino:23:84: warning: left shift count >= width of type [enabled by default] usb_midi_write_packed(0xB00B | (((channel - 1) & 0x0F) << 8) | ((101 & 0x7F) << 16) | (0x7F << 24)); ^ /Users/zinc5/Documents/Arduino/test-nrpn2/test-nrpn2.ino:23:99: warning: left shift count >= width of type [enabled by default] usb_midi_write_packed(0xB00B | (((channel - 1) & 0x0F) << 8) | ((101 & 0x7F) << 16) | (0x7F << 24)); ^ /Users/zinc5/Documents/Arduino/test-nrpn2/test-nrpn2.ino:25:84: warning: left shift count >= width of type [enabled by default] usb_midi_write_packed(0xB00B | (((channel - 1) & 0x0F) << 8) | ((100 & 0x7F) << 16) | (0x7F << 24)); ^ /Users/zinc5/Documents/Arduino/test-nrpn2/test-nrpn2.ino:25:99: warning: left shift count >= width of type [enabled by default] usb_midi_write_packed(0xB00B | (((channel - 1) & 0x0F) << 8) | ((100 & 0x7F) << 16) | (0x7F << 24)); ^ exit status 1 Erreur lors de la compilation. ++++ === Avec Encoder === * Ajouter la bibliothèque : http://www.pjrc.com/teensy/arduino_libraries/Encoder.zip ([[https://www.pjrc.com/teensy/td_libs_Encoder.html|source]]) {{.:rotary_encoder_arduino_hookup.png?200|}} === Avec capacitif MPR121 === * Module MPR121 : https://www.adafruit.com/products/1982. Alimention possible en 5V ou 3.3V * Ajouter la bibliothèque : https://github.com/adafruit/Adafruit_MPR121_Library ([[https://learn.adafruit.com/adafruit-mpr121-12-key-capacitive-touch-sensor-breakout-tutorial/wiring|source]]) {{.:mpr121.png?200|}} === Teensy for BrutBox === * Fichiers : {{.:pd-teensy-brutbox.zip|}} * Midi : https://www.pjrc.com/teensy/td_midi.html et https://www.pjrc.com/teensy/td_libs_MIDI.html **Avec Pure Data** : {{.:pd-brutbox.png|}} **Avec Arduino** : ++++ teensy_brutbox_2.ino | // TEENSY 2 - BRUTBOX // Control inputs (sensors) with MIDI messages // 08/06/2015 - http://reso-nance.org #include #include "Adafruit_MPR121.h" #include // Capacitive apacitive MPR121 // Connection Teensy2 // USB wiring : d+ : SDA, d- : SCL, SCL = DO, SDA = D1 Adafruit_MPR121 cap = Adafruit_MPR121(); const int touchNb = 12; // number of touch inputs const int touchThreshold = 60; int touchStateCtl[] = {40, 41, 42} ; // touch on/off int touchState[touchNb]; // state : on/off int currentTouchValues[touchNb]; int lastTouchValues[touchNb]; int touchCtl[] = {60,61,62,63,64,65,66,67,68,69,70,71}; // note in int touchOn = 0; // Analog setup int anaPins[] = {22,11,12,13,14,15,16,17,18,19,20,21}; // analog pins const int anaNb = 12; // number of inputs int anaCtl[] = {11,10,9,8,7,6,5,4,3,2,1,0}; // controller in int anaStateCtl[] = {20, 21} ; // sensor on (20), sensor off (21) int anaState[anaNb]; // state : on/off int anaValues[anaNb]; // current analog values int anaLastValues[anaNb]; // previous analog values // Encoder setup Encoder encoderSensor (7, 8); long encoderOldPosition = -999; long encoderNewPosition; int encoderStateCtl = 13; // receive ctlout 13 int encoderOn = 0; const int channel = 1; // Sampling rate const long interval = 30; unsigned long currentMillis; unsigned long previousMillis = 0; void setup() { // Midi receive : on/off sensors usbMIDI.setHandleControlChange(OnControlChange); } void loop() { currentMillis = millis(); if(currentMillis - previousMillis >= interval) { previousMillis = currentMillis; // Analog sensors loop for (int i = 0; i < anaNb; i++) { if(anaState[i] == 1) { // check first if the sensor is on anaValues[i] = (int) analogRead(anaPins[i]) / 8 ; Serial.println(anaValues[i]); if (anaValues[i] != anaLastValues[i]) { usbMIDI.sendControlChange(anaCtl[i], anaValues[i], channel); anaLastValues[i] = anaValues[i]; } } } // Capacitive loop if(touchOn == 1){ for (uint8_t i=0; i < touchNb; i++) { if(touchState[i] == 1) { // check first if the sensor is on currentTouchValues[i] = cap.filteredData(i); if ((currentTouchValues[i] - lastTouchValues[i]) < -touchThreshold) { usbMIDI.sendNoteOn(touchCtl[i], 127, channel); } if ((currentTouchValues[i] - lastTouchValues[i]) > touchThreshold) { usbMIDI.sendNoteOn(touchCtl[i], 0, channel); } lastTouchValues[i] = currentTouchValues[i]; } } } // Encoder if (encoderOn == 1) { encoderNewPosition = encoderSensor.read(); if (encoderNewPosition != encoderOldPosition) { encoderOldPosition = encoderNewPosition; usbMIDI.sendControlChange(12, encoderNewPosition, channel); } } } // Discard incoming MIDI messages. while (usbMIDI.read()) {} } // Receive Midi Control Change void OnControlChange(byte channel, byte control, byte value) { // Analog sensors on/off if (control == anaStateCtl[0]) {anaState[-value+(anaNb-1)] = 0;} else if (control == anaStateCtl[1]) {anaState[-value+(anaNb-1)] = 1;} else if (control == touchStateCtl[0]) {touchState[value] = 0;} else if (control == touchStateCtl[1]) {touchState[value] = 1;} else if (control == touchStateCtl[2]) { touchOn = value; if (touchOn == 1) { cap.begin(0x5A); for (uint8_t i=0; i<4; i++) {lastTouchValues[i] = cap.filteredData(i); } } } else if (control == encoderStateCtl) {encoderOn = value;} } ++++ ===== Prototypes ===== ==== Prototype 0.1 - 03/2015==== * [[.:pistes:|Pistes initiales]] 2014 * [[.:v0.1|Protototype 0.1]] : Espace Gantner 06/03/2015 ==== Prototype 0.2 ==== **juin 2015 au LFO** : http://piratepad.net/brutbox * Sélection élargie de capteurs (sensibilités, capacités moteurs) * Design des capteurs plus gros, plus lourds, codes couleurs pour faciliter la compréhension et le maniement * Câblages plus longs pour s'installer confortablement dans un espace de jeu collectif * Patchs en forme de pièces musicales préconçues pour //X// capteurs/participants {{.:scenebrutbox.jpg|}} ==== Prototype v1 ==== * Pad de travail : http://piratepad.net/brutboxv1 ==== Prototype raspberry-pi ==== * kit raspberry pi 3 + sd card + alimentation + keyboard (option) = 70€ * touch screen 7" 800x480 = 70€ * carte son (si besoin entrée micro...) = entre 3 et 35€ * Mcp3008 = 4€ * capteurs brutbox. ----- ----- ===== Boites ===== Découpe de boîtes en bois contre-plaqué de 3mm avec une machine à découpe laser. Attention certains fichiers ont des problèmes d'échelle (à multiplier par 125%), et d'autres sont outdatés... * {{.:brutbox-proto2.zip|fichiers de découpe des boites et PCB}} * {{.:bb-gaitelyrique.zip|fichiers de découpe des boites non corrects.}} Nous avons utilisé un générateur de boite : http://boxmaker.connectionlab.org