Go Down

### Topic: One-line algorithmic music (Read 13000 times)previous topic - next topic

#### stimmer

##### Oct 03, 2011, 12:27 amLast Edit: Oct 03, 2011, 12:29 am by stimmer Reason: 1
Some demoscene guys have been experimenting with generating loops from short C programs and some of them sound pretty cool! Take a look at this:

http://countercomplex.blogspot.com/2011/10/algorithmic-symphonies-from-one-line-of.html

The algorithms looked simple enough to run on an Arduino so I wrote a sketch to try them out. Audio out is on pin 10. Have a go at altering the formulas and 'composing' your own, it is great fun.

Code: [Select]
`// one-line algorithmic music// see viznut's blog http://countercomplex.blogspot.com/2011/10/algorithmic-symphonies-from-one-line-of.html// and http://www.youtube.com/watch?v=GtQdIYUtAHg&feature=related// ported to arduino by stimmer// Audio out on pin 10void setup() {  TCCR1B = (TCCR1B & 0xf8) | 1;  analogWrite(10,1);}void putb(byte b){  static long m;  long t;  while((t=micros())-m < 125);  m=t;    OCR1B=b;}void loop() {  long v;  for(long t=0;;t++)putb(    // uncomment ONE line below  // or try making one of your own...    t*((t>>12|t>>8)&63&t>>4)   // by viznut  // ((-t&4095)*(255&t*(t&t>>13))>>12)+(127&t*(234&t>>8&t>>3)>>(3&t>>14)) // by tejeez  // t*(t>>11&t>>8&123&t>>3)    // by tejeez  // t*((t>>9|t>>13)&25&t>>6)   // by visy  // (t*(t>>5|t>>8))>>(t>>16)   // by tejeez  // ((t*(t>>8|t>>9)&46&t>>8))^(t&t>>13|t>>6) // by xpansive  // ((t&4096)?((t*(t^t%255)|(t>>4))>>1):(t>>3)|((t&8192)?t<<2:t)) // by skurk (raer's version)  // (t>>7|t|t>>6)*10+4*(t&t>>13|t>>6) // by viznut, xpansive, varjohukka  // t*5&(t>>7)|t*3&(t*4>>10) // by miiro  // (t|(t>>9|t>>7))*t&(t>>11|t>>9) // by red  // v=(v>>1)+(v>>4)+t*(((t>>16)|(t>>6))&(69&(t>>9))) // by pyryp  // (t>>6|t|t>>(t>>16))*10+((t>>11)&7)  //by viznut  // (t*(4|7&t>>13)>>((~t>>11)&1)&128) + ((t)*(t>>11&t>>13)*((~t>>9)&3)&127) // by stimmer    );  }`
Due VGA library - http://arduino.cc/forum/index.php/topic,150517.0.html

#### sciguy

#1
##### Oct 05, 2011, 02:19 am
MIND BLOWN

Sounds awesome, I'll have to have a go at it sometime
Soundcloud page: http://soundcloud.com/beefinator-2
Old soundcloud page (ran out o

#### robtillaart

#2
##### Oct 05, 2011, 09:32 pm
Did you try the Arduino random generator allready?
Or an PI in 1 million decimals generator?
...
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

#### jlswbs

#3
##### Oct 18, 2011, 09:10 am
Thanks this great job.
http://jlswbs.blogspot.com
http://jlswbs.wordpress.com
http://jls.wbs.cz

#### sushyoshi

#4
##### Oct 19, 2011, 01:08 pm
Beautifull!

I dont get the code at all but amazing how such low volume code can make those sounds.

Thanks!

#### AnomalousRobot

#5
##### Oct 23, 2011, 12:37 am
Hello world!

This is the thread that has just inspired me to get an arduino and get into electronics. So awesome! My starter kit is in the mail.

I wonder if it's feasible to create a standalone interface for this that would allow you to write new algorithms using only the arduino itself.
I'm thinking there would be an LCD screen and at least 4 buttons to move left and right through the line of code and "up and down" to alter the selected character.

Any ideas on how feasible/difficult this would be to create? I don't have much electronics experience and only some experience with BASIC. But the arduino code I've seen so far is pretty easy to understand.

Thanks for the inspiration.

#### stimmer

#6
##### Oct 26, 2011, 12:57 am
It would be pretty difficult to do  - Arduino doesn't have an equivalent to the Eval function in BASIC and that's what you'd need to be able to completely change the algorithm at runtime.

It is possible to make slight changes to an algorithm such as changing numeric constants by turning them into variables. I've been experimenting with this myself - try this sketch, use a button from GND to pin 2 to decrease one of the variables and pin3 to increase it.

Code: [Select]
`// interactive one-line algorithmic music by stimmervoid setup() {  TCCR1B = (TCCR1B & 0xf8) | 1;  analogWrite(10,1);  pinMode(2,INPUT);digitalWrite(2,HIGH);  pinMode(3,INPUT);digitalWrite(3,HIGH);  pinMode(13,OUTPUT);}void putb(byte b){  static long m;  long t;  while((t=micros())-m < 125);  m=t;    OCR1B=b;}void loop() {  long v;  static int debounce=0;  static int var=25;    for(long t=0;;t++){putb(      t*((t>>9|t>>13)&var&t>>6) // original by visy was t*((t>>9|t>>13)&25&t>>6)     );    if(debounce==0){      digitalWrite(13,LOW);      if(digitalRead(2)==0){var--;debounce=2000;}      if(digitalRead(3)==0){var++;debounce=2000;}    }else{       debounce--;digitalWrite(13,debounce>300);    }  }}`
Due VGA library - http://arduino.cc/forum/index.php/topic,150517.0.html

#### jakeybob

#7
##### Nov 04, 2011, 11:32 pm
I just did a similar thing (see http://arduino.cc/forum/index.php/topic,77884.0.html ). You can't write entirely new algorithms, but you can adjust the parameters of whatever ones you upload while they play.

#### zeni

#8
##### Sep 21, 2012, 08:59 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.

#### DuaneB

#9
##### Sep 21, 2012, 11:31 am
Thats great, I used to do something similar for pc graphics.

I would add a potentiometer to select which algorithm runs at run time and a simple LED Visualizer that would make a really neat project.

Duane B

rcarduino.blogspot.com

http://rcarduino.blogspot.com/2012/04/servo-problems-with-arduino-part-1.html
then watch this
http://rcarduino.blogspot.com/2012/04/servo-problems-part-2-demonstration.html

Rcarduino.blogspot.com

#### DuaneB

#10
##### Sep 21, 2012, 02:12 pmLast Edit: Sep 21, 2012, 03:44 pm by DuaneB Reason: 1
Quote

I would add a potentiometer to select which algorithm runs at run time and a simple LED Visualizer that would make a really neat project.

Actually I would not do that at all, instead I would convert it to run using interrupts and read four buttons to decide which of upto 16 algorithms plays and then add a four bit LED Visualiser.

I will put up a video in a little while, in the meantime, heres the code -

Code: [Select]
`// one-line algorithmic music// see viznut's blog http://countercomplex.blogspot.com/2011/10/algorithmic-symphonies-from-one-line-of.html// and http://www.youtube.com/watch?v=GtQdIYUtAHg&feature=related// ported to arduino by stimmer// Audio out on pin 10// Further ported to Interrupt based music generation with 4 button selection of upto 16 algorithms (or 15 + silence on no buttons pressed)// by Duane B aka RCArduino//// Buttons are digital 8,9,10,11, music output is on digital 6//// Also added a four LED Visualiser on digital pins 2,3,4,5// #define SAMPLE_MAX (65535.0)#define SAMPLE_FREQUENCY (8000.0)#define TIMER1_FREQUENCY 2000000#define UPDATE_RATE 8000// by keeping t global we can use it to drive the visualiser as welllong t;// iterate the grains and LFO SIGNAL (TIMER1_COMPA_vect) { OCR1A += (TIMER1_FREQUENCY/UPDATE_RATE); t++; switch(PINB&15) {   default:   case 0:     OCR0A = 0;     break;   case 1:     OCR0A = ((-t&4095)*(255&t*(t&t>>13))>>12)+(127&t*(234&t>>8&t>>3)>>(3&t>>14)); // by tejeez     break;   case 2:     OCR0A = t*(t>>11&t>>8&123&t>>3); // by tejeez     break;   case 3:     OCR0A = t*((t>>9|t>>13)&25&t>>6);   // by visy     break;   case 4:     OCR0A = (t*(t>>5|t>>8))>>(t>>16);   // by tejeez - nothing     break;   case 5:     OCR0A = ((t*(t>>8|t>>9)&46&t>>8))^(t&t>>13|t>>6); // by xpansive     break;   case 6:     OCR0A = ((t&4096)?((t*(t^t%255)|(t>>4))>>1):(t>>3)|((t&8192)?t<<2:t)); // by skurk (raer's version)     break;   case 7:     OCR0A = (t>>7|t|t>>6)*10+4*(t&t>>13|t>>6); // by viznut, xpansive, varjohukka     break;   case 8:     OCR0A = t*5&(t>>7)|t*3&(t*4>>10); // by miiro - nothing     break;   case 9:     OCR0A = (t|(t>>9|t>>7))*t&(t>>11|t>>9); // by red     break;   case 10:     long v;     OCR0A = v=(v>>1)+(v>>4)+t*(((t>>16)|(t>>6))&(69&(t>>9))); // by pyryp     break;   case 11:      OCR0A = (t>>6|t|t>>(t>>16))*10+((t>>11)&7);  //by viznut     break;   case 12:     OCR0A = (t*(4|7&t>>13)>>((~t>>11)&1)&128) + ((t)*(t>>11&t>>13)*((~t>>9)&3)&127); // by stimmer - wow!     break;   case 13:     // free to use     break;   case 14:     // free to use     break;   case 15:     // free to use     break;     // any more and we need another bit from PORTB }}void setup(){  TCCR1A=0x0;          // set the timer prescaler to 8 = 16/8 = 2MHz  TCCR1B=0x02;          // set the timer prescaler to 8 = 16/8 = 2MHz  TIMSK1 |= (1<<OCIE1A);   // Enable output compare match interrupt on OCR1A     //TCCR0A=0B10110011;                                    //-8 bit audio PWM  TCCR0A=0B10000011;                                    //-8 bit audio PWM  //TCCR0A=0x83;          // Set timer waveform generation mode to FAST PWM, clear OC0A On match, set at bottom - OC0A = digital pin 6.  TCCR0B=0x01;          // Set to clock frequency, no prescaler  OCR0A=127;            // set in the middle - do we need this ? probably not.  DDRD|=1<<6;          // Set digital pin 6 to output - channels 2 and 3  DDRB &= (~15); // set digital pins 8,9,10,11 as inputs   DDRD |= ((1<<2) | (1<<3) | (1<<4) | (1<<5)); // set digital pins 2,3,4,5 as outputs for the visualiser}void loop(){ unsigned char output = OCR0A; // dvidide by 16 to get a four bit power level output >> 4; // clear visualiser bits on portD PORTD &= 0B000011; // set the visualiser bits PORTD |= (output<<2);}`

There are some little bugs that I will sort out

1) Leds do not turn off when there is no output
2) Two of the tunes do not play

Duane B

rcarduino.blogspot.com
http://rcarduino.blogspot.com/2012/04/servo-problems-with-arduino-part-1.html
then watch this
http://rcarduino.blogspot.com/2012/04/servo-problems-part-2-demonstration.html

Rcarduino.blogspot.com

#### zeni

#11
##### Sep 21, 2012, 03:27 pm
Here is my code (with serial, not a keyboard as in the video):

Code: [Select]
`// 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.15const byte MAX_CHAR=50; // max number of characters in formulachar 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 variablebyte p,s; // counters for pile and sortieboolean firstChar,multipleDigit; // for reinitialization when new algo is received / multiple digit detectionvoid 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.

#### DuaneB

#12
##### Sep 21, 2012, 03:36 pm
That looks very interesting, do you have any examples using your notation that could be pasted into the serial monitor ?

Duane B

rcarduino.blogspot.com
http://rcarduino.blogspot.com/2012/04/servo-problems-with-arduino-part-1.html
then watch this
http://rcarduino.blogspot.com/2012/04/servo-problems-part-2-demonstration.html

Rcarduino.blogspot.com

#### zeni

#13
##### Sep 21, 2012, 04:15 pm
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

#### DuaneB

#14
##### Sep 21, 2012, 09:35 pm
Stimmer,
Since I have put a video on youtube which is essentially a video of your original sketch in action with a half and hours worth of additions, what can I add to the description to credit you ? do you have a web page or just a link to this post which I have already included ?

Duane B
http://rcarduino.blogspot.com/2012/04/servo-problems-with-arduino-part-1.html
then watch this
http://rcarduino.blogspot.com/2012/04/servo-problems-part-2-demonstration.html

Rcarduino.blogspot.com

Go Up

Please enter a valid email to subscribe