Show Posts
Pages: [1] 2
1  Using Arduino / Audio / Re: One-line algorithmic music on: September 21, 2012, 09:15:07 am
A simple example: ((t>3)*t)E

Another example from your code: (t|(t>>9|t>>7))*t&(t>>11|t>>9). This becomes ((t|((t>9)|(t>7)))*(t&((t>11)|(t>9))))E
Parentheses make thing quite complicated and long. That's why it might be better to just write directly in RPN or to use operators precedence.
In RPN, it becomes (if no mistake): t11>>t9>>|t&t9>>t7>>|t|*

Stephane
2  Using Arduino / Audio / Re: One-line algorithmic music on: September 21, 2012, 08:27:20 am
Here is my code (with serial, not a keyboard as in the video):

Code:
// 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;
    }
  }
}

If the algorithm is entered in RPN then it's even easier as there is almost nothing in the loop.
In the case of a keyboard and an LCD screen, then it's getting difficult to type anything if the algo is a bit long (the program rarely enters the loop and then misread the keyboard most of the time). What I do in this case is using an arduino for the interface/parsing (just a loop, no interrupt) and an attiny for sound (computation of the algo). Those two are connected through serial.
3  Using Arduino / Audio / Re: One-line algorithmic music on: September 21, 2012, 01:59:19 am
No eval on the arduino but you can program a parser or just type directly in Reverse Polish Notation (RPN). Then live coding of algorithm music on the microcontroller is possible.
4  International / Réalisations et Projets Finis / Live Coding sur arduino on: September 15, 2012, 07:55:33 am
Mon dernier projet (pas vraiment fini en fait, mais assez avancé): un système pour du live coding sans ordinateur. L'arduino est utilisé comme parseur et générateur de son. Pour le moment, l'arduino ne parse que des algorithmes assez simples (très inspirés par les travaux de VIznut: http://countercomplex.blogspot.jp/2011/10/algorithmic-symphonies-from-one-line-of.html), mais dans le future je pense ajouter un sequencer ou tout simplement la génération de signaux de base (triangle, sinus,...).
Bon, une vidéo expliquera cela mieux qu'un long texte =>


et sinon, quelques détails supplémentaires ici: http://cho-yaba.com

Commentaires, suggestions,... sont les bienvenus !
5  International / Français / Re: Fonction delay, taches paralelles et gestion du temps non-bloquant on: May 17, 2012, 04:54:00 am
Dans ce cas, il suffirait peut-être de mettre tempsPassé à millis() seulement lorsque un piéton appuie sur le bouton.
Et ajouter une condition (boolean sur l'état du bouton: tester la valeur de tempsPassé seulement si le bouton a été appuyé et remettre tout à jour une fois les actions effectuées).
6  International / Français / Re: Fonction delay, taches paralelles et gestion du temps non-bloquant on: May 16, 2012, 09:54:04 pm
Il faut mettre à jour tempsPassé dans la condition. C'est seulement une fois que les 2000ms se sont écoulées que tempsPassé doit être remis à jour. Au tout début aussi, dans le setup(), il faut mettre tempsPassé égal à millis().
                    if (millis() - tempsPassé >= 2000)
                    {
                        //action quelquonque
                        tempsPassé = millis()
                    }

J'ai remplacé le == par un >= car il y a pas mal de chance que la différence ne soit pas exactement 2000.
7  International / Français / Re: reset intempestifs du programme on: May 16, 2012, 09:50:45 pm
Je ne connais pas les caractéristiques exactes de cette board mais ça sent bon le manque de puissance.
Si il y a un régulateur de voltage (très probable), ça ne change pas grand chose d'augmenter le voltage en entrée car le régulateur est limité en courant de toute façon. Il vaut mieux alimenter séparément la carte et les éléments qui consomment le plus.
8  International / Français / Re: Générer du bruits (audio) on: March 14, 2012, 12:13:48 am
Il y a pas mal de possibilités.
1) DDS (Direct Digital Synthesis): pratique pour les signaux périodiques, possibilité d'ajouter facilement une envelope ADSR, le signal de base peut être construit sur mesure, plusieurs signaux de bases peuvent être sélectionner.
2) PCM (Pulse Code Modulation): pratique pour des samples mais limité en taille.
3) Si le signal est vraiment très très simple, simplement utiliser une sortie digitale et sortir HIGH/LOW aux bons instants (c'est peut-être suffisant pour simuler le son d'un compteur geiger).
4) Après il y a des choses plus complexes (granular synthesis par example) qui me semblent inutiles dans ton cas.

J'ai récemment un peu discuté de la DDS et PCM:
http://cho-yaba.com/?p=1663
http://cho-yaba.com/?p=1684

Ça m'intéresse t'entendre le résultat, tiens nous au courant !
9  International / Français / Re: Tvout librarie besoin d'info on: March 02, 2012, 04:02:09 am
Pour la vidéo composite les niveaux de gris sont en fait un voltage.
La librairie TVOUT utilise un seul bit pour coder les niveaux de gris (donc noir et blanc seulement). Ça permet d'avoir des images qui prennent moins de place et peut-être d'être plus rapide (on est vite limité avec une arduino, c'est pour cela que la résolution est relativement basse).
Mais a priori, il suffit de coder sur plus de bits et utiliser un DAC (PWM ou réseau de résistances par example) pour sortir plus de niveaux de gris. 
10  International / Français / Re: Mise en fonction d'un Anémomètre on: February 17, 2012, 04:49:40 am
Il ne faut pas réinitialiser ton compteur à chaque loop sinon il est toujours à 0 ou 1 avant le calcul de la vitesse du vent. De plus le delay est inutile puisque tu ne fais que mettre en pause le programme (et donc aucune variable n'est mise à jour).
Il te faut un second compteur basé sur le temps écoulé.
Ainsi, à chaque fois qu'il s'est écoulé une certaine durée (mettons appelée D, qui dépend de la vitesse de variation de la vitesse du vent), la vitesse du vent est calculée (à partir du compteur de tours et de D) et envoyée sur le port série. Dans la foulée, le compteur de tours (Anemo_Push_Counter) et de temps sont mis à 0 et à millis() respectivement. Millis() te donne le temps actuel (depuis le moment où le programme a commencé).
Dans le loop, tu as donc une condition du genre (à mettre à la place de delay et de ce qu'il y a ensuite):
if (millis()==compteur_temps+D) {
Calcul vitesse vent;
Envoie vitesse vent sur série;
Anemo_Push_Counter=0;
compteur_temps=millis();
}

Dans setup():
Anemo_Push_Counter=0;
compteur_temps=millis();
 
Il est préférable de déclarer compteur_temps comme un unsigned long au cas où la durée entre chaque calcul de la vitesse du vent est relativement longue.
11  International / Français / Re: Mise en fonction d'un Anémomètre on: February 17, 2012, 03:12:10 am
C'est parce que tu ne mets pas à jour ta variable Last_Anemo_State.
Elle reste toujours à sa valeur initiale. Dans ta condition if, ajoute une mise à jour de cette variable à la valeur en cours (Anemo_State).
12  International / Français / Re: attiny84 RC5 on: February 14, 2012, 10:36:10 am
C'est tout à fait normal. Ces deux lignes apparaissent tout le temps. Elles n'ont aucune influence.
Si aucun autre message apparait c'est que tout va bien!
13  International / Français / Re: attiny84 RC5 on: February 13, 2012, 08:31:38 pm
En fait quand je dis bootloader, c'est par rapport à ce qui est inscrit dans l'IDE arduino.
Il s'agit en fait d'écrire les "fuses".
14  International / Français / Re: attiny84 RC5 on: February 13, 2012, 03:01:41 am
A priori, n'importe quel pin est OK vu que tout se fait par software.
A noter que SoftwareSerial ne fonctionne que si la clock de l'Attiny est à 8MHz, ce qui n'est pas la valeur par défaut (qui est de 1MHz).
Il suffit de charger le bootloader 8MHz à partir de l'IDE arduino (en utilisant une carte arduino pour programmeur ISP).
Pas besoin de connecter le pin RESET. Pour écouter, juste TX et la masse.
15  International / Français / Re: Comment désactiver le reset au lancement du moniteur série on: February 10, 2012, 10:37:29 pm
C'est le fonctionnement normal. C'est parce que quand tu utilises le port serie par la connection USB de ta carte arduino, il y a d'autres pins connectés que les seuls TX et RX. C'est pour cela que quel que soit le programme que tu utilises, un signal est envoyé sur le pin DTS (je crois) du FTDI et provoque un reset. Pour éviter cela, soit tu déconnectes ce pin (c'est expliqué sur le forum anglais, je crois que c'est une capacité à enlever) sur la carte soit tu écoutes ton port série en passant par un autre port série connecté uniquement aux pins TX et RX (voire TX seulement) de la carte arduino (en plus de la masse).
Pages: [1] 2