We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexDiscussionExhibition › Evolving Loop Sequencer
Page Index Toggle Pages: 1
Evolving Loop Sequencer (Read 2465 times)
Evolving Loop Sequencer
Jun 17th, 2010, 6:44am
 
I am experimenting with automated music generation. This is a loop sequencer that creates its own loops (given a set of samples) and gradually evolves them overtime. It doesn't make anything close to good music but sometimes the beats aren't that bad either. Quality is also dependent on having good samples (looperman dot com has some good free samples). I have hopes of using genetic algorithms to more "intelligently" alter the loops but that hasn't been implemented yet.

It uses minim but plenty of things could be improved (e.g., not having to stop the samples before the next one plays). I tried to load all the samples in memory but that seems to eat up a ton of memory depending on how many you have.

Samples should be placed in a folder names "samples" in the sketch location.

Code:
//Simple automated loop sequencer
import processing.core.*;
import ddf.minim.*;


String sample_dir = "C:\\Documents and Settings\\Administrator\\My Documents\\Processing\\EvoMusic\\samples\\";



int presses_left = 0;
int presses_right = 0;
float session_duration = 300000;
boolean start = false;
boolean finished = false;
boolean saved = false;
float start_time = -1;
int index;
int bpm = 300; //This is the programmrd beats-per-minute
int obtained_bpm=0;
int obtained_count = 0;
float measurement_time;

int last_slot;
int slot;
float time_between_beats = 0;

Minim minim;
AudioSample sample;
String[] samples;

PFont myFont;
float time;
Loop current_loop;



void setup() {
   size(600, 200);

   minim = new Minim(this);
   
   println("Listing samples:: ");
   samples = listFileNames(sample_dir);
   
   for (int i=0;i<samples.length;i++) {
     println("reading " + samples[i]);
   }
   
   current_loop = new Loop(null);

   index = 1;
   
   myFont = createFont("verdana", 12);
   bpm = 300;
   
   textFont(myFont);
   frameRate(60);    
}


 
public void draw() {

 background(0);
 fill(255);
 
 time = millis() % current_loop.loop_time;
 current_loop.loop_time = 60000/bpm * current_loop.loop_size; //2000
 slot = int(current_loop.loop_size * time / current_loop.loop_time);

 if (slot != last_slot) {
   if (slot == 0) {
     current_loop.plays_left--;
     if (current_loop.plays_left <= 0) {
       current_loop = new Loop(current_loop);
     }
   }
   
   if (slot < current_loop.slots.length) {
     if (current_loop.slots[slot] >= 0) {
       if (sample != null) sample.close();
       sample = minim.loadSample("samples\\" + samples[current_loop.slots[slot]],400);
       sample.trigger();
     }
   }
   last_slot = slot;
 }
 
 text(time,10,32);
 time_between_beats = 60000 / bpm;
 text("time between beats: " + time_between_beats,10,53);
 text("slot: " + slot,10,73);
 text("bpm: " + bpm,10,92);
 text("plays left: " + current_loop.plays_left,10,112);
 int obtained_bpm = int(60000/time_between_beats);
 text("obtained bpm: " + obtained_bpm,10,132);
 show_loop(current_loop,time);
}

void show_loop(Loop thisloop,float time) {
 int slot_length = 30;
 int total_length = int(slot_length * thisloop.loop_size);
 int linex = int(total_length * time / thisloop.loop_time);
 for (int i=0;i<thisloop.loop_size;i++) {
   text(thisloop.slots[i],10+slot_length*i,12);
 }
 stroke(255,0,0);
 line( 9+linex,2, 9+linex,12);
 line(10+linex,2,10+linex,12);
 line(11+linex,2,11+linex,12);
}  

//  This method responds to key presses when the
//  program window is active: These methods test the
//  Znet AT commands and such:
   
public void keyPressed() {

  switch (key) {
    case'q':
      if (index >= samples.length) index = 0;
      println("samples.length: " + samples.length + " index: " + index);
      println("samples[" + index + "] = " + samples[index]);
      index++;
      break;
    case 'p':
      if (index >= samples.length) index = 0;
      println("samples.length: " + samples.length + " index: " + index);
      if (sample != null) sample.close();
      sample = minim.loadSample("samples\\" + samples[index],400);
      sample.trigger();
      index++;
      break;
    case '1':
      bpm--;
      time_between_beats = 60000 / bpm;
      break;
    case '2':
      bpm++;
      time_between_beats = 60000 / bpm;
      break;
    case 'n':
      if (sample != null) sample.close();
      current_loop = new Loop(null);
      break;
  }
}


String[] listFileNames(String dir) {
 File file = new File(dir);
 if (file.isDirectory()) {
   String names[] = file.list();
   return names;
 } else {
   // If it's not a directory
   return null;
 }
}
public void stop() {
 sample.close();
 minim.stop();
 super.stop();
}


There's one more class you need. I'll attach it in a reply.
Re: Evolving Loop Sequencer
Reply #1 - Jun 17th, 2010, 6:45am
 
Here's the class Loop:
Code:
class Loop {
 //This is the evolutionary unit
 //it consists of all the sounds that play during a loop
 int loop_size;
 int loop_time; //in milliseconds
 int plays_left;
 
 int[] slots;
 float[] population;
 
 Loop(Loop parent) {
   plays_left = 2;
   if (parent == null) {
     loop_size = 16;
     loop_time = 60000/bpm * loop_size; //2000
     
     int num_starters = int(random(1,loop_size/2));
     slots = new int[loop_size];
     population = new float[loop_size];
     
     for (int i=0;i<loop_size;i++) {
       slots[i] = -1;
     }
     for (int i=0;i<num_starters;i++) {
//        println("index: " + int(random(1,loop_size)) + " value: " + int(random(0,samples.length)));
       slots[int(random(1,loop_size))] = int(random(0,samples.length));
     }
     for (int i=0;i<loop_size;i++) {
       population[i] = random(100);
     }
     
   } else {
     loop_size = parent.loop_size;
     loop_time = parent.loop_time;
     /*
     if (random(100) < 10) {
       if (random(100) < 50) loop_size++;
       if (random(100) < 50) loop_size--;
     }
     if (random(100) < 10) {
       if (random(100) < 50) loop_time = loop_time + 10;
       if (random(100) < 50) loop_time = loop_time - 10;
     }
     */
     slots = new int[loop_size];
     population = new float[loop_size];
     
     for (int i=0;i<loop_size;i++) {
       if (i < parent.loop_size) {
         if (random(100) < 75) { //parent.population[i]
           slots[i] = parent.slots[i];
           population[i] = parent.population[i];
         } else {
           if (random(100) < 50) slots[i] = int(random(0,samples.length));
           else slots[i] = -1;
           population[i] = random(100);
         }
       }
     }
     
   }
 }
 
 void show_loop() {
   String txt;
   txt = "[";
   for (int i=0;i<loop_size;i++) {
     txt += slots[i];
     if (i < loop_size-1) txt += ",";
   }
   txt += "]";
   println(txt);
 }
 
 
}

Page Index Toggle Pages: 1