» codelab : http://codelab.fr/accueil » Forum : Livecode : http://codelab.fr/livecode » Live coding sur microcontroller : http://codelab.fr/3586 Ceci est la version imprimable d'un sujet du forum, pour retourner à la version complète : Live coding sur microcontroller |
zeni — 2012-09-16 05:17:14 |
Un projet en cours d'évolution, un système pour live coding sans ordinateur. lien vers la page de la vidéo sur youtube |
emoc — 2012-09-17 17:27:47 |
wouh, bravo! |
zeni — 2012-09-18 03:54:17 |
Merci ! |
zeni — 2012-09-18 06:54:34 |
Voici le code commenté (en anglais seulement...) du parseur et calcul de l'algorithme à partir de la verion NPI (code pour arduino MEGA mais cela ne change rien pour le parseur ou le calculateur). // Parser for algorithmic music (serial version) // This version: // * no limit on number of digits for constants // * No error checking // * No precedence (of operators) checking // * Each individual operation MUST BE between parentheses // * Algos must end with the character 'E' // by 23N! 2012.09.15 const byte MAX_CHAR=50; // max number of characters in formula char pile[MAX_CHAR],sortie[MAX_CHAR]; // stacks for conversion to RPN (shunting-yard algorithm) unsigned long pileRPN[MAX_CHAR],t; // stack for RPN computation / time variable byte p,s; // counters for pile and sortie boolean firstChar,multipleDigit; // for reinitialization when new algo is received / multiple digit detection void setup() { // This works on an arduino MEGA. // Just modify the registers and pins for other boards. // A prescaler of 8 with a 8 or 9 bits fast PWM might me more appropriate but lower sampling rate. // In the current situation, long algos might cause problems/crashes. // If sound seems too slow, just increase the increment of t. // PWM out pin DDRB = (1 << PB5); // Pin 11 on MEGA // fast-PWM 10-bit / compare match on OCR1A / output on OC1A=PB5 / prescaler=1 TCCR1A = (1 << COM1A1)|(1<<WGM10)|(1<<WGM11); TCCR1B = (1 << CS10)|(1<<WGM12); // Initial values t=0; p=0; s=0; firstChar=true; multipleDigit=false; // Serial Serial.begin(57600); Serial.println("Ready!"); } ISR(TIMER1_OVF_vect) // Interrupt Service Routine (sampling rate of sound) { // computation of the algo based on its RPN representation p=0; for (byte i=0;i<s;i++) { // Loop on the RPN algo as an array of char (=sortie) switch(sortie[i]) { case 't': // variable=> just add to pile pileRPN[p++]=t; multipleDigit=false; // not a digit break; case '+': // perform ADDITION, de-pile p--; //de-pile pileRPN[p-1]+=pileRPN[p]; // perform operation multipleDigit=false; // not a digit break; case '|': // perform OR, de-pile p--; pileRPN[p-1]|=pileRPN[p]; multipleDigit=false; break; case '&': // perform AND, de-pile p--; pileRPN[p-1]&=pileRPN[p]; multipleDigit=false; break; case '^': // perform XOR, de-pile p--; pileRPN[p-1]^=pileRPN[p]; multipleDigit=false; break; case '-': // perform SUBSTRACTION, de-pile p--; pileRPN[p-1]-=pileRPN[p]; multipleDigit=false; break; case '*': // perform MULTIPLICATION, de-pile p--; pileRPN[p-1]*=pileRPN[p]; multipleDigit=false; break; case '/': // perform DIVISION, de-pile p--; pileRPN[p-1]/=pileRPN[p]; multipleDigit=false; break; case '>': // perform BIT SHIFT RIGHT, de-pile p--; pileRPN[p-1]=pileRPN[p-1]>>pileRPN[p]; multipleDigit=false; break; case '<': // perform BIT SHIFT LEFT, de-pile p--; pileRPN[p-1]=pileRPN[p-1]<<pileRPN[p]; multipleDigit=false; break; case '%': // perform MODULO, de-pile p--; pileRPN[p-1]=pileRPN[p-1]%pileRPN[p]; multipleDigit=false; break; default: // digit, add to pile except if multiple digits (in this case process the digits) if (multipleDigit) { pileRPN[p-1]*=10; pileRPN[p-1]+=sortie[i]-48; } else { pileRPN[p++]=sortie[i]-48; multipleDigit=true; } break; } } OCR1A=pileRPN[0]; // PWM output (the final result is the first element of the stack) t++; // variable inc. } void loop() { // read the serial input and parse it (don't forget to type "E" at the end of the algo) // example (copy-paste in serial monitor): ((t>5)*t)E (">" is actually ">>" not "greater than") // each individual operation MUST BE between parentheses. while (Serial.available() > 0) { if(firstChar) { // Disable interrupt and initialize variables TIMSK1 = (0 << TOIE1); firstChar=false; p=0; s=0; } char inChar = Serial.read(); // current char char symbol=inChar; // meta-char if ((inChar>=48)&(inChar<58)) symbol='D'; // Digit if ((inChar!='(')&(inChar!=')')&(inChar!='t')&(inChar!='E')&(symbol!='D')) symbol='O'; // Operator // Shunting-yard algorithm switch(symbol) { case 't': case 'D': sortie[s++]=inChar; // if variable or digit, add to sortie break; case 'O': case '(': pile[p++]=inChar; // if operator or left parenthesis, add to pile break; case ')': sortie[s++]=pile[p-1]; // if right parenthesis, transfer from pile to sortie, remove left parenthesis // In our case there is always a single operation between parentheses. No need to check if there is // a left parenthesis in the pile, we can just move the index p back and overwrite the left parenthesis. p-=2; break; case 'E': // End char => send the new algo to the interrupt for sound generation. // Not necessary to have an end char, end can be detected by matching parentheses. // But an End char makes things clearer and easier. Serial.println("Uploaded!"); firstChar=true; t=0; p=0; TIMSK1 = (1 << TOIE1); // enable interrupt break; } } } |
zeni — 2012-09-18 08:37:25 |
Je viens de voir l'épinglé sur le sujet (comment ai-je pu le rater ?) ! Evidemment tous mes travaux de live coding sont inspirés de ceux de VIznut et je m'étais déjà bien amusé avec ibniz ! |
rep — 2012-09-20 23:00:34 |
haaa ibniz ouais j'y ai pensé direct aussi ;) |
emoc — 2012-09-21 14:41:50 |
Merci Zeni pour les infos et le code, ça m'intéresse fort d'en mettre un sur patte! |