====== Fiat lux ====== * Porteur du projet : [[:user:resonance|resonance]] Fenshu et Eric * Date : 01/09/2017/ - 01/07/2018/ * Licence : [[http://creativecommons.org/licenses/by-sa/3.0/legalcode|CC-by-sa-3.0]] * Description : Synthé fonctionnant avec lumiere et arduino ... * Fichiers sources : design {{ :projets:fiat_lux:fiatlux-lightsynthdesign-vect.ai |}} codes : dans la page ! * Lien : {{tag>light, synth, arduin, mozzi}} ===== Description ===== Fiat lux est un triple synthétiseur fonctionnant avec des led et des panneaux solaires. 3 Arduino programmés en synthétiseur (avec la library Mozzi pour certains), envoient du signal audio (électrique) dans des leds. Celles-ci sont manipulables et orientables, font face à des panneaux solaires qui capte la lumiere. Ces panneaux solaires ont des sorties jack, permettant de se brancher à un ampli audio. **Cet instruments a été exposé :** * Mixart Myris Toulouse - Sonoptic 2020 * Printemps de Bourges - 2018 * CityLab Barcelona - 2017 (beta) * ... et utilisé dans des concerts de Fenshu {{projets:fiat_lux:accueil:img_20180609_140822.jpg?1100|Fiat lux}} On capte le son emis en lumiere par des leds, via un panneau solaire. Ca donne ceci : {{youtube>nbi2d_UTToQ?large}} //Le troisieme synth de la video est l'exemple de la librarie mozzi : Sensor/lighttemperature...// {{youtube>AMaS_aPNssI?large}} ===== Circuit basique ===== Un montage digne des plus grands moments de l'électronique française {{ :projets:fiat_lux:img_20180609_113815.jpg?nolink |}} ===== Codes ===== Voici quelques codes pas mal... Certains utilisent les libraries Tone et Mozzi pour transformer l'arduino en petit synthé ! ==== Synth 1 : FM synth - mozzi ==== Audio pin : 9 \\ On controle un synthe fm avec 5 potards ... ++++ Le code | /* Use 5 Analogic inputs to control fm synth (A0 - ... - A4 ) Output Pin 9 - led ... */ #include #include // oscillator #include // table for Oscils to play #include #include // maps unpredictable inputs to a range // int freqVal; // desired carrier frequency max and min, for AutoMap const int MIN_CARRIER_FREQ = 22; const int MAX_CARRIER_FREQ = 440; const int MIN = 1; const int MAX = 10; const int MIN_2 = 1; const int MAX_2 = 15; // desired intensity max and min, for AutoMap, note they're inverted for reverse dynamics const int MIN_INTENSITY = 700; const int MAX_INTENSITY = 10; // desired mod speed max and min, for AutoMap, note they're inverted for reverse dynamics const int MIN_MOD_SPEED = 10000; const int MAX_MOD_SPEED = 1; AutoMap kMapCarrierFreq(0,1023,MIN_CARRIER_FREQ,MAX_CARRIER_FREQ); AutoMap kMapIntensity(0,1023,MIN_INTENSITY,MAX_INTENSITY); AutoMap kMapModSpeed(0,1023,MIN_MOD_SPEED,MAX_MOD_SPEED); AutoMap mapThis(0,1023,MIN,MAX); AutoMap mapThisToo(0,1023,MIN_2,MAX_2); const int KNOB_PIN = 0; // Pitch const int LDR1_PIN=5; // RingMOD const int LDR2_PIN=2; // LFO speed const int LDR3_PIN=3; // Harmonic const int LDR4_PIN=4; // reso-nance Oscil aCarrier(COS2048_DATA); Oscil aModulator(COS2048_DATA); Oscil kIntensityMod(COS2048_DATA); int mod_ratio = 5; // brightness (harmonics) long fm_intensity; // carries control info from updateControl to updateAudio // smoothing for intensity to remove clicks on transitions float smoothness = 0.95f; Smooth aSmoothIntensity(smoothness); void setup(){ Serial.begin(115200); // set up the Serial output so we can look at the light level startMozzi(); // :)) } void updateControl(){ // freqVal = map(LDR3_PIN, 0, 1023, 1, 100); int freqVal = mozziAnalogRead(LDR3_PIN); // value is 0-1023 int FRQ = mapThis(freqVal); int knob2 = mozziAnalogRead(LDR4_PIN); // value is 0-1023 int knob2Val = mapThis(knob2); // read the knob int knob_value = mozziAnalogRead(KNOB_PIN); // value is 0-1023 // map the knob to carrier frequency int carrier_freq = kMapCarrierFreq(knob_value); //calculate the modulation frequency to stay in ratio int mod_freq = carrier_freq * mod_ratio * FRQ; // set the FM oscillator frequencies aCarrier.setFreq(carrier_freq); aModulator.setFreq(mod_freq); // read the light dependent resistor on the width Analog input pin int LDR1_value= mozziAnalogRead(LDR1_PIN); // value is 0-1023 // print the value to the Serial monitor for debugging int LDR1_calibrated = kMapIntensity(LDR1_value); // calculate the fm_intensity fm_intensity = ((long)LDR1_calibrated * knob2Val * (kIntensityMod.next()+128))>>8; // shift back to range after 8 bit multiply // read the light dependent resistor on the speed Analog input pin int LDR2_value= mozziAnalogRead(LDR2_PIN); // value is 0-1023 Serial.print("LDR0 = "); Serial.print(knob_value); Serial.print("\t"); // prints a tab Serial.print("LDR1 = "); Serial.print(LDR1_value); Serial.print("\t"); // prints a tab Serial.print("LDR2 = "); Serial.print(LDR2_value); Serial.print("\t"); // prints a tab Serial.print("LDR3 = "); Serial.print(freqVal); Serial.print("\t"); // prints a tab Serial.print("LDR4 = "); Serial.print(knob2); Serial.print("\t"); // prints a tab // use a float here for low frequencies float mod_speed = (float)kMapModSpeed(LDR2_value)/1000; kIntensityMod.setFreq(mod_speed); Serial.println(); // finally, print a carraige return for the next line of debugging info } int updateAudio(){ long modulation = aSmoothIntensity.next(fm_intensity) * aModulator.next(); return aCarrier.phMod(modulation); } void loop(){ audioHook(); } ++++ ==== Synth 2 : Rythm box 3led ==== Audio out : Pin 5 , 9 ,10 \\ On fait simplement clignoter 3 led a la noire, croche triolet, et on controle le temp avec un potentiometre et une photoresistance... ++++ Le code | // 3 led a jouant a la noire, croche et triolet // un potentiometre 10k en A0 : controle le tempo général... // une photo resistance en A1 : controle un effet de delay #define led1 5 #define led2 9 #define led3 10 //#define factor 10 //factor for pwm tone ! int factor = 10; unsigned long previousMillis[3]; //[x] = number of leds void setup() { pinMode(led1, OUTPUT); pinMode(led2, OUTPUT); pinMode(led3, OUTPUT); Serial.begin(9600); } void loop() { int sensorValue = analogRead(A1); sensorValue = map(sensorValue, 0, 1023, 2000, 0); if(sensorValue > 1990) { sensorValue == 10000; } int sensorValueB = analogRead(A0); sensorValueB = map(sensorValueB, 0, 1023, 1023, 0); int sensorValueC = analogRead(A2); factor = map(sensorValueC, 0, 1023, 2, 200); if(sensorValueB > 800) { BlinkLedSimple(led1, sensorValue, 0,sensorValueB); //BlinkLed( which led, interval, one of the stored prevMillis BlinkLedSimple(led2, sensorValue/3, 1,sensorValueB); //last parameters must be different for each led BlinkLedSimple(led3, sensorValue/2, 2,sensorValueB); } if(sensorValueB > 400 && sensorValueB < 800 ) { BlinkLed(led1, sensorValue, 0,sensorValueB); //BlinkLed( which led, interval, one of the stored prevMillis BlinkLed(led2, sensorValue/3, 1,sensorValueB); //last parameters must be different for each led BlinkLed(led3, sensorValue/2, 2,sensorValueB); } if(sensorValueB < 400) { BlinkLedSuper(led1, sensorValue, 0,sensorValueB); //BlinkLed( which led, interval, one of the stored prevMillis BlinkLedSuper(led2, sensorValue/3, 1,sensorValueB); //last parameters must be different for each led BlinkLedSuper(led3, sensorValue/2, 2,sensorValueB); } Serial.print("potentiometre"); Serial.println(sensorValue); Serial.print("ldr"); Serial.println(sensorValueB); // delay(1); } ///Simple blink void BlinkLedSimple (int led, int interval, int array, int pwm){ if (((long)millis() - previousMillis[array]) >= interval){ previousMillis[array]= millis(); //stores the millis value in the selected array digitalWrite(led, !digitalRead(led)); //changes led state }} ///delayyyy blink void BlinkLed (int led, int interval, int array, int pwm){ if (((long)millis() - previousMillis[array]) >= interval){ previousMillis[array]= millis(); //stores the millis value in the selected array digitalWrite(led, !digitalRead(led)); //changes led state delay (pwm/factor); digitalWrite(led, !digitalRead(led)); //changes led state delay (pwm/factor); digitalWrite(led, !digitalRead(led)); //changes led state } } ///super delayyyy blink void BlinkLedSuper (int led, int interval, int array, int pwm){ if (((long)millis() - previousMillis[array]) >= interval){ previousMillis[array]= millis(); //stores the millis value in the selected array digitalWrite(led, !digitalRead(led)); //changes led state delay (pwm/factor); digitalWrite(led, !digitalRead(led)); //changes led state delay (pwm/factor); digitalWrite(led, !digitalRead(led)); //changes led state delay (pwm/factor); digitalWrite(led, !digitalRead(led)); //changes led state delay (pwm/factor); digitalWrite(led, !digitalRead(led)); //changes led state delay (pwm/factor); digitalWrite(led, !digitalRead(led)); //changes led state delay (pwm/factor); digitalWrite(led, !digitalRead(led)); //changes led state delay (pwm/factor); digitalWrite(led, !digitalRead(led)); //changes led state delay (pwm/factor); digitalWrite(led, !digitalRead(led)); //changes led state } } ++++ ==== Synth 3 : Theremin ==== Audio out : Pin 9 \\ 2 pot (selecteur si pot ou ldr pour controler le pitch, pitch ) un ldr (pitch).... ++++ Le code | #include #include // oscillator template #include // sine table for oscillator #include #include #define INPUT_PIN 0 // analog control input LDR #define INPUT_PINA 1 // analog control input #define MIX_PIN 2 // analog control input unsigned int echo_cells_1 = 32; unsigned int echo_cells_2 = 60; unsigned int echo_cells_3 = 127; int bumpy_input = 12; #define CONTROL_RATE 64 ControlDelay <128, int> kDelay; // 2seconds // oscils to compare bumpy to averaged control input Oscil aSin0(SIN2048_DATA); Oscil aSin1(SIN2048_DATA); Oscil aSin2(SIN2048_DATA); Oscil aSin3(SIN2048_DATA); // use: RollingAverage myThing RollingAverage kAverage; // how_many_to_average has to be power of 2 int averaged; void setup(){ kDelay.set(echo_cells_1); startMozzi(); } void updateControl(){ int mix = mozziAnalogRead(MIX_PIN); int pot = mozziAnalogRead(INPUT_PINA) ; int ldr = mozziAnalogRead(INPUT_PIN) ; if (mix > 500) { bumpy_input = ldr; } else { bumpy_input = pot; } averaged = kAverage.next(bumpy_input); aSin0.setFreq(averaged); aSin1.setFreq(kDelay.next(averaged)); aSin2.setFreq(kDelay.read(echo_cells_2)); aSin3.setFreq(kDelay.read(echo_cells_3)); } int updateAudio(){ return 3*((int)aSin0.next()+aSin1.next()+(aSin2.next()>>1) +(aSin3.next()>>2)) >>3; } void loop(){ audioHook(); } ++++ ===== Autres codes Outsider ===== On peut reprogrammer les arduino si on est pas content ! ==== Code pour communiquer avec PureData COMPORT (2 led branché en 9 et 10): ==== On controle ainsi deux pins avec tone depuis Pure Data... **Patch PureData :** voir fichier 4 dans la page ressource [[http://reso-nance.org/wiki/logiciels/serial/accueil?s[]=puredata&s[]=serial]] ++++ Le code | String inputString = ""; // chaine de caractères pour contenir les données boolean stringComplete = false; // pour savoir si la chaine est complète String fct =""; String arg=""; int index; #include Tone freq1; Tone freq2; void setup() { Serial.begin(9600); // port série freq1.begin(9); freq2.begin(10); } void loop() { if (stringComplete) { //Serial.println(inputString); index = inputString.indexOf(' '); // on récupère la position du séparateur (l'espace " ") fct = inputString.substring(0,index); // on coupe la chaine en deux : la fonction et l'argument arg = inputString.substring(index,inputString.length()); if (fct == "LED10") { freq2.play(arg.toInt(),300); } else if (fct == "LED9") { freq1.play(arg.toInt(),300); } inputString = ""; // vide la chaine stringComplete = false; } } /* SerialEvent est déclenché quand de nouvelles données sont reçues. Cett routine tourne entre chaque loop(), donc utiliser un delay la fait aussi attendre */ void serialEvent() { while (Serial.available()) { char inChar = (char)Serial.read(); // Récupérer le prochain octet (byte ou char) inputString += inChar; // concaténation des octets if (inChar == '\n') { // caractère de fin pour notre chaine stringComplete = true; } } } ++++ ==== Relaxation didgeridoo Mozzi ==== Synth 2 ou 3 \\ Audio pin 9 ++++ Le code | #include #include // oscillator template #include // sine table for oscillator const char KNOB_PIN = 0; // set the input for the knob to analog pin 0 const char LDR_PIN = 1; // set the input for the LDR to analog pin 1 // use: Oscil oscilName (wavetable), look in .h file of table #included above Oscil aSin(SIN2048_DATA); byte volume; void setup(){ startMozzi(); // :)) } void updateControl(){ // read the potentiometer int knob_value = mozziAnalogRead(KNOB_PIN); // value is 0-1023 // map it to an 8 bit volume range for efficient calculations in updateAudio volume = knob_value >> 2; // 10 bits (0->1023) shifted right by 2 bits to give 8 bits (0->255) // read the light dependent resistor int light_level = mozziAnalogRead(LDR_PIN); // value is 0-1023 light_level = map(light_level,0,1023,0,12); light_level = light_level*100 + 200; // set the frequency aSin.setFreq( light_level); } int updateAudio(){ // cast char output from aSin.next() to int to make room for multiplication return ((int)aSin.next() * volume) >> 8; // shift back into range after multiplying by 8 bit value } void loop(){ audioHook(); // required here delay(100); } ++++ ==== Multitone Bug ==== synth 2 ou 3 : bug avec 3 tone... audio out : pin 9 ++++ Le code | #define led1 9 #define led2 5 #define led3 10 void setup() { pinMode(led1, OUTPUT); pinMode(led2, OUTPUT); pinMode(led3, OUTPUT); } void loop() { int sensorValue = analogRead(A1); sensorValue = map(sensorValue, 0, 1023, 0, 100000); int sensorValueB = analogRead(A0); sensorValueB = map(sensorValueB, 0, 1023, 0, 10000); int sensorValueC = analogRead(A2); sensorValueC = map(sensorValueC,0, 1023, 0,random (5) + 100); tone(led1,sensorValue,sensorValueC); delay (sensorValueC); tone(led1,sensorValueB,sensorValueC); delay (sensorValueC); tone(led1,sensorValueC,sensorValueC); delay (sensorValueC); } ++++ ===== Design ===== {{ :projets:fiat_lux:dsc_0839.jpg?nolink |}} Fichier source en haut de page ! \\ Projet luxueux : Utilisation de la laser et cnc. {{ :projets:fiat_lux:screen_shot_06-09-18_at_02.49_pm.png?nolink&1000 |}} ===== Matériaux et outils ===== * 3 arduino nano * Potentiometres 10k x10 * 2 ldr + resistance 50k * cables * cp 3mm oukoumé * pin 18mm epaisseur * CNC * LASERCUT * feràsouder... * patience (compter 2 jours sans manger) ===== Photos ===== {{:projets:fiat_lux:fiatlux.png?1100|}} {{gallery>?&crop&lightbox}} ===== Notice d'utilisation ===== - Brancher les 5 lampions sur les sorties instruments - Brancher les sortie audio principale (panneau solaire) sur une table de mixage ou enceintes audio - Brancher l'alimentation sur la prise micro usb a gauche. (coté FM) - Brancher l'alimentation usb sur une prise avec un bouton interrupteur - Si les lampions s'allume tous ou clignote c'est bon, si certains ne s'allume pas.. ou ne sonnent pas ... eteindre et rallumer la prise pour reset. Il ya quelques problemes qui sont encore a resoudre : * Retirer les lampions peut aussi arreter le synthé du milieu... donc eviter de brancher et debrancher celui ci en live... (commencer tout branché) * Possible faux contact pres des leds par moments... il faut les bouger un peu et ca repart (a moins que la led soit grillée)