Adam's Blog
×

Day 10

Saturday September 11, 2010
Category: Creative Pact 2010

I went out tonight to three art openings around town and I was totally jazzed from seeing art. So I have come home and tried to do something before I go to sleep. This is my first sketch that is a continuation of the day before.

I was looking at things and thinking about in-between. I have made a simple patch that takes yesterday’s patch but adds a cloud of random points and I can do linear interpolation between the two. It is crude right now but there are some very interesting intermediate states between objects that arrive. I have also properly implemented the Dan Shiffman sugar from his space junk sketch so I get some more variation from frame to frame.

Again, OPENGL so code will follow the image, now animated.

Screenshot of software.


import ddf.minim.*;
import ddf.minim.analysis.*;
import processing.opengl.*;
import javax.media.opengl.*;

Minim minim;
AudioInput input;

int Segments = 21;
float[][] mylines = new float[Segments*Segments][3];
float[][] myrandomlines = new float[Segments*Segments][3];
float theta;
float phi;
float scalething = 200;
int r = 1;
int p;

color c1 = color(240,0,0);
color c2 = color (20,150,150);

void setup()
{
  size(640,480, OPENGL);

  minim = new Minim(this);
  input = minim.getLineIn(Minim.STEREO, 512);

  	for(int i=0;i<Segments;++i)
	{
		theta = (float)i/Segments * 2 * PI;
		for(int j=0;j<Segments;++j)
		{
			phi = (float)j/Segments * PI;

			mylines[i*Segments+j][0] = sin(theta)*cos(phi)*scalething;
			mylines[i*Segments+j][1] = sin(theta)*sin(phi)*scalething;
			mylines[i*Segments+j][2] = cos(theta)*scalething;
            
                        myrandomlines[i*Segments+j][0] = random(0,scalething) - scalething/2;
                        myrandomlines[i*Segments+j][1] = random(0,scalething) - scalething/2;
                        myrandomlines[i*Segments+j][2] = random(0,scalething) - scalething/2;
		}
	}  
}

void draw()
{ 
  background(200);
  translate(width/2, height/2);
  
  float audiolevel = input.mix.level();
  strokeWeight(audiolevel*100);
  c1 = color(audiolevel*2100,80,audiolevel*1400);

  rotateY((float)p/200);
  rotateZ((float)p/123);

  for(int i = 1 ; i < Segments * Segments; i++)
  {
      rotate(random(200));
      beginShape(LINES);
         stroke(c1); 
         vertex(mylines[i][0] * (1.0 - 1.0/r) + myrandomlines[i][0] * (1.0/r), 
            mylines[i][1] * (1.0 - 1.0/r) + myrandomlines[i][1] * (1.0/r), 
            mylines[i][2] * (1.0 - 1.0/r) + myrandomlines[i][2] * (1.0/r));
         stroke(c2); 
         vertex(mylines[i-1][0] * (1.0 - 1.0/r) + myrandomlines[i-1][0] * (1.0/r), 
           mylines[i-1][1] * (1.0 - 1.0/r) + myrandomlines[i-1][1] * (1.0/r),
           mylines[i-1][2]* (1.0 - 1.0/r) + myrandomlines[i-1][2] * (1.0/r) );
      endShape();
  }
}

void keyPressed()
{
   if (key == ' ')  
   {
      saveFrame();
   }
}

void mouseClicked(){
 r++; 
  
}

void stop()
{
  input.close();
  minim.stop();
  super.stop();
}

View this code on GitHub

Day 9

Friday September 10, 2010
Category: Creative Pact 2010

I made a bad VJ patch today. I have a rotating sphere made from a series of line strips with colour gradients. The patch pulses with size and colour to volume. Maybe soon I will put that feature extraction from the other day to use and make something a little more sophisticated.

It is made with OPENGL again so I have included the code below.

Screenshot of software.
Screenshot of software.


import ddf.minim.*;
import ddf.minim.analysis.*;
import processing.opengl.*;
import javax.media.opengl.*;

Minim minim;
AudioInput input;

int Segments = 21;
float[][] mylines = new float[Segments*Segments][3];
float theta;
float phi;
float scalething = 200;
int r;

color c1 = color(240,0,0);
color c2 = color (200,150,150);

void setup()
{
  size(640,480, OPENGL);

  
  minim = new Minim(this);
  input = minim.getLineIn(Minim.STEREO, 512);

  	for(int i=0;i<Segments;++i)
	{
		theta = (float)i/Segments * 2 * PI;
		for(int j=0;j<Segments;++j)
		{
			phi = (float)j/Segments * PI;

			mylines[i*Segments+j][0] = sin(theta)*cos(phi)*scalething;
			mylines[i*Segments+j][1] = sin(theta)*sin(phi)*scalething;
			mylines[i*Segments+j][2] = cos(theta)*scalething;
		}
	}  
}

void draw()
{ 
  translate(width/2, height/2);
  
  float audiolevel = input.mix.level();
  strokeWeight(audiolevel*100);
  c1 = color(audiolevel*2100,0,0);

  rotateX((float)r++/800);
  rotateY((float)r/200);
  rotateZ((float)r/80);
  
  background(90);
  for(int i = 1 ; i < Segments * Segments; i++)
  {
      beginShape(LINES);
         stroke(c1); vertex(mylines[i][0], mylines[i][1], mylines[i][2] );
         stroke(200, 150, 150); vertex(mylines[i-1][0], mylines[i-1][1],mylines[i-1][2]);
      endShape();
  }
}

void keyPressed()
{
   if (key == ' ')  
   {
      saveFrame();
   }
}

void stop()
{
  input.close();
  minim.stop();
  super.stop();
}

View this code on GitHub

Day 8

Thursday September 09, 2010
Category: Creative Pact 2010

Another audio analysis simple patch for today. I looked into the BeatDetect object in MINIM and found that yesterday’s code could be done even simpler by using the built in detector. It isn’t very good but it works. I didn’t do much tweaking on it but I bet with some massaging I could get it to detect my signals a little bit better.

So today’s patch is a bit of a homage to Dan Shiffman’s space junk patch. The patch has three magic lines that make it look great. The last three valid lines are rotatings in x,y,z. What makes it special is that those lines are repeated multiple times in each frame and a translate is performed afterwards with no pushMatrix() or popMatrix(). So the reference is moved about the sketch multiple times so that there is some interesting placement of objects about the space.

This patch uses the detected volume and onset information to draw a set of shapes around the screen with varying rotation based upon the detected parameters. On my machine the frames show up for a very short amount of time and often aren’t drawn fully so it looks quite glitchy and nice. When I render it out to screenshots the image is preserved. Try squinting and covering half the image in a weird way and you will see what I see when it is running, or run the code yourself.

Screenshot of software.
Screenshot of software.


import ddf.minim.*;
import ddf.minim.analysis.*;
import processing.opengl.*;
import javax.media.opengl.*;

Minim minim;
AudioInput input;
BeatDetect detectorGadget;


void setup(){
  size(640,480,OPENGL);  

  minim = new Minim(this);
  input = minim.getLineIn(Minim.STEREO, 512);
  detectorGadget = new BeatDetect();
  
 stroke(255, 255, 150);
 fill(3,190,129);
}

void draw(){
  background(30);

  float audiolevel = input.mix.level();
  detectorGadget.detect(input.mix);
  
  translate (width/2, height/2,200);

  if(detectorGadget.isOnset())
  {
    for (int i = 0 ; i < 100; i++)
    {
      ellipse(0,0, 1000*audiolevel,1000*audiolevel);
      box(10,10,100);
      rotate(audiolevel);
      translate(log(audiolevel),0);
    }
  }
}

void keyPressed()
{
   if (key == ' ')  
   {
      saveFrame();
   }
}

void stop()
{
  input.close();
  minim.stop();
  super.stop();
}

View this code on GitHub

Day 7

Wednesday September 08, 2010
Category: Creative Pact 2010

Today’s sketch is a take on the mouse controlled ball that you can rotate and throw. I have a sphere here that is rotated by making a loud sound. I have done a rather crude thresholding but I discovered that MINIM has a nice level() call on audiobuffers that return the RMS. Hooray!

I also discovered that on a mac when you export your patch to the web it doesn’t work well if you are using OPENGL. I have included the code inline with the blog, which I don’t like so much but it will get the idea to you.

Like I predicted this is a much shorter sketch than on the weekends. This is going to be the way of it until I get more efficient at my changing weeks.

Screenshot of software.


import ddf.minim.*;
import processing.opengl.*;
import javax.media.opengl.*;

Minim minim;
AudioInput input;

float r;
float inc;

void setup(){
  size(screen.width, screen.height, OPENGL);  
  hint(ENABLE_OPENGL_4X_SMOOTH);

  minim = new Minim(this);
  input = minim.getLineIn(Minim.STEREO, 512);
  
  stroke(255, 255, 150);
  noFill();
}

void draw(){
  background(30);

  float audiolevel = input.mix.level();
  if (audiolevel > 0.01)
    inc++;
  r = r + inc;
  inc = inc * 0.85;
  
  translate (width/2, height/2,mouseX);
  rotateY(r);
  sphere(200 + audiolevel*1000);
}

void keyPressed()
{
   if (key == ' ')  
   {
      saveFrame();
   }
}

void stop()
{
  input.close();
  minim.stop();
  super.stop();
}

View this code on GitHub

Day 6

Monday September 06, 2010
Category: Creative Pact 2010

Last night I finished watching the first season of The Wire. I have been watching it on DVD and the splash screen and the opening scene of the show has all of these signal displays. So, I dusted off my trigonometry skills and started making some sine waves dance on my screen.

I have some ideas about how to tweak this a bit more by casting the shapes to PImages and then applying filters but I have a busy day, so that will happen another time. I expect that the sketches during the week will be shorter than the weekend ones. I think that is just how it goes.

Screenshot of software.
Screenshot of software.


Today’s Code:

float amp1;
float inc;
float tri;
boolean up;
float downer;

void setup(){
 size(400,300); 
  amp1 = height/2;
  fill(255);
  smooth();
}

void draw(){
  noStroke();
  fill(0,15);
  rect(0,0,width,height);
  stroke(40,197,90);
  fill(255);

  amp1 = pow (10, -tri/10);
  
  if (up)
    downer = -1;
  else 
    downer = 1;  

  for (int i = 0 ; i < width; i++)
  {
     point (i, sin(float(i)/width * TWO_PI + frameCount/PI)*downer * -1 *amp1*height/2 + height/2  - amp1*50) ;  
     point (i, sin(float(i)/width * TWO_PI *2 - frameCount/(3*PI))* downer * amp1*height/4 + height/4) ;  
     point (i, sin(float(i)/width * TWO_PI *20 - frameCount/(9*PI))* downer * amp1*height*.23 + height*.8 + amp1*30) ;  
 
  }
  
  if ( tri >= 20)
  {
    inc = -.2;
    up = !up;
  }
  if ( tri <= 0)
    inc = .16;

  tri = tri + inc;
}

void keyPressed(){
 if (key == ' ')
    saveFrame(); 
}

View this code on GitHub

Day 5

Monday September 06, 2010
Category: Creative Pact 2010

Today I was working with analysis. This patch doesn’t have a lot of good looks but I have implemented a zero crossing rate function, an rms function for time domain analysis, spectral centroid, spectral rolloff, and spectral compactness. I coded up a spectral flatness measure but I keep getting zero as the output. I haven’t done thorough debugging job because I was trying to make sure I have something done for today!

I started out hoping that I could implement both the spectral features and time domain features as an AudioListener object but the FFT object doesn’t work that way. So, I made a method that is called every draw loop. This isn’t the nicest solution but it works. I am dreaming up a link between jAudio and MINIM. If I’m not careful I might be putting another thing on my plate :)

Today’s patch is really just an extension of MINIM’s spectral display patch but an overlay of the feature extraction output. My hope is to eventually do a MINIM version of sndpeek. Maybe tomorrow there will be text and waterfall plots... maybe.

Screenshot of software.
Screenshot of software.


import ddf.minim.analysis.*;
import ddf.minim.*;

Minim minim;
AudioPlayer jingle;
FFT fft;
DrawTime dt;

int w;
float[]  myspectrum;

void setup()
{
  size(512, 200, P3D);

  minim = new Minim(this);
  jingle = minim.loadFile("jingle.mp3", 2048);
  jingle.loop();
  
  fft = new FFT(jingle.bufferSize(), jingle.sampleRate());
  // calculate averages based on a miminum octave width of 22 Hz
  // split each octave into three bands
  fft.logAverages(22, 3);
  
  dt = new DrawTime();
  jingle.addListener(dt);

  myspectrum = new float[ jingle.bufferSize() ];
  
  rectMode(CORNERS);
}

void draw()
{
  background(0);
  fill(255);
  stroke(0);
  
  fft.forward(jingle.mix);
  // avgWidth() returns the number of frequency bands each average represents
  // we'll use it as the width of our rectangles
  w = int(width/fft.avgSize());

  for(int i = 0; i < fft.avgSize(); i++)
  {
    rect(i*w, height, i*w + w, height - fft.getAvg(i)*5);
  }
  
  for(int i= 0; i < jingle.bufferSize(); i++)
    myspectrum[i] = fft.getBand(i);
  
  dt.draw();
  drawSpectral(myspectrum);
}

void keyPressed(){
    if (key == ' ')
        saveFrame();
}

void stop()
{
  jingle.close();
  minim.stop();
  super.stop();
}

View this code on GitHub

void drawSpectral(float[] spec)
{
  //==============================
  // SPECTRAL CENTROID
  //==============================
  float m1 = 0;
  float m0 = 0;

  for (int i = 0; i < spec.length; i++){
    m1 += i * spec[i];
    m0 += spec[i]; 
  }

  float centroid = 0.5;
  if (m0 != 0.0)
  {
    centroid = (m1 / m0) / (float) spec.length ;  
  }
  pushStyle();
    stroke(90,255,90);
    strokeWeight(3);
    line(centroid * width, 0 , centroid * width, height);
  popStyle();

  //==============================
  // SPECTRAL ROLLOFF
  //==============================
  float perc = 0.8;
  float[] sumWindow = new float [ spec.length ];
  float total = 0;	
  float sum = 0;
  float specRolloff = 0;
  boolean specdone = false;
  for( int i = 0; i< spec.length; i++)
  {
    sum += spec[i];
    sumWindow[i] = sum;
  }
  total = sumWindow[spec.length-1];

  for ( int i = spec.length-1; i > 1 ; i--){
    if (sumWindow[i] < 0.8 * total)
    {
      specRolloff = (float) i;
      specdone = true;
      break;
    }
  }
  if ( !specdone )
    specRolloff = float(spec.length - 1);
  specRolloff /= spec.length;

  pushStyle();
    stroke(89, 169, 210);
    line( specRolloff * width, 0, specRolloff * width, height);
  popStyle();

  //==============================
  // SPECTRAL COMPATCTNESS
  // code snippet from jAUDIO  
  //==============================
  float[] mag_spec = new float[ spec.length ];
  for (int i = 0; i < spec.length; i++)
  {
    mag_spec[i] = abs( spec[i] );
  }

  double compactness = 0.0;
  for (int i = 1; i < mag_spec.length - 1; i++) {
    if ((mag_spec[i - 1] > 0.0) && (mag_spec[i] > 0.0) && (mag_spec[i + 1] > 0.0)) 
    {
      compactness += Math .abs(
          20.0 * Math.log(mag_spec[i])
          - 20.0 * (Math.log(mag_spec[i - 1]) 
            + Math.log(mag_spec[i]) 
            + Math .log(mag_spec[i + 1])) 
          / 3.0);
    }
  }
  pushStyle();
    stroke(12,48, 96);
    // seems to evaluate between 2k and 9k so divide by 10000 as hack to normalize
    line ( (float)compactness / 10000 * width, 0, (float)compactness / 10000 * width , height);
  popStyle();

  //==============================
  // SPECTRAL FLATNESS
  // DOESN'T WORK -- geometric mean always evaluates to zero :(
  //==============================
  float flatness = 0;
  double geometricMean = spec[0];
  float arithmeticMean = sum;

  for ( int i = 1; i < spec.length; i++)
  {
        geometricMean *= (double) spec[i];
        if (spec[i] == 0.0)
        {
          println("WARNING: ZERO DETECTED " +frameCount);

        }
  }
  geometricMean = Math.pow(geometricMean , (1.0f / spec.length) );
  arithmeticMean /=  spec.length;
  
  flatness = (float)geometricMean / arithmeticMean ;
  println(flatness);
}

View this code on GitHub

class DrawTime implements AudioListener
{
  private float[] left;
  private float[] right;

  synchronized void samples(float[] samp)
  {
    left = samp;
  }

  synchronized void samples(float[] sampL, float[] sampR)
  {
    left = sampL;
    right = sampR;
  }

  synchronized void draw()
  {
    if (left != null && left.length > 0)
    {
      //RMS
      float rms = 0.0;

      for (int i = 0; i < left.length; i++)
        rms += (left[i] * left[i] );

      if (rms!= 0.0)
      {
        rms /= left.length;
        rms = sqrt(rms);
      }
      pushStyle();
          noFill();
          stroke (255, 90,90);
          line(0, height - rms*height, width, height - rms*height);
      popStyle();  

      // ZERO-CROSSING RATE (normalized)
      // detected / buffsize

      float zcr = 0;

      for (int i = 0; i < left.length - 1; i++)
      {
        if (left[i] > 0.0 && left[i + 1] < 0.0)
          zcr++;
        else if (left[i] < 0.0 && left[i + 1] > 0.0)
          zcr++;
        else if (left[i] == 0.0 && left[i + 1] != 0.0)
          zcr++;
      }
      zcr = zcr / (float) left.length;
      pushStyle();
          noFill();
          stroke (90, 90,255);
          line(0, height - zcr*height, width, height - zcr*height); 
      popStyle();  
    }
  }
}

View this code on GitHub

Day 4

Saturday September 04, 2010
Category: Creative Pact 2010

This one has been in the works for awhile. I have been looking at the minim BETA for a few days and now I feel like I am getting my head around it. Today I made my first UGen. I think I am going to submit it to the distribution. It is a byte swapping algorithm inspired by swap~ in zexy for PD. This is one of my favourite distortions. Very loud and very nasty. You’ve been warned.

Today I also finally delved into Processing’s method for exporting applets. So, I am not going to dump a whole lot of code in this post. If you want to see the code follow the links below.
The audio display is rendered as points. This is inspired by something I saw at MUTEK this year and is also the flavour of the visual material for Frank Bretschneider’s EXP. http://www.frankbretschneider.de/Web-Site/exp.html

Screenshot of software.
Screenshot of software.


/**
* Adam R. Tindale <br>
* <a href="http://www.adamtindale.com">www.adamtindale.com</a> <br>
* September 4, 2010 <br>
* <a href="http://www.inclusiveimprov.co.uk/doku.php/events:creativepact_2010">Creative Pact 2010</a><br>
*
* <p> 
* Experiment with MINIM. Uses UGen API and the AudioListener. DrawWave is a simple class that uses
* rect() like sytax to display a waveform in an area. Swap is a user space UGen that does simple
* byte swapping, one of my favourite effects from zexy in PD.
* </p>
*/

import ddf.minim.*;
import ddf.minim.ugens.*;

Minim minim;
LiveInput in;
AudioOutput out;
Swap fx1;
DrawWave renderer;

void setup(){
  size(400, 200);
  smooth();
  
  minim = new Minim(this);
  out = minim.getLineOut();
  in = new LiveInput( minim.getInputStream(out.getFormat().getChannels(), out.bufferSize(), out.sampleRate(), out.getFormat().getSampleSizeInBits()) ); 
  fx1 = new Swap();
  in.patch(fx1).patch(out);
 
  renderer = new DrawWave(0,0, width, height);
  out.addListener(renderer);
}

void draw(){
  noStroke();
  fill(0, 40);
  rect(0,0,width,height);
  renderer.draw();
}

void keyPressed(){
  if (key == ' ')
    saveFrame();
}

void stop()
{
  in.close();
  out.close();
  minim.stop();
  super.stop();
}

View this code on GitHub

//package ddf.minim.ugens; // to make into java object for inclusion in new minim

/** A UGen for byte swapping audio signals. Inspired by swap~ from 
 * Johannes M Zmoelnig's Zexy library for PureData. DANGER LOUD!
 * <p>
 * 
 * @author art
 */
// 
public class Swap extends UGen{

  public UGenInput audio;

  Swap()
  {
    audio = new UGenInput(InputType.AUDIO);
  }

  @Override
  protected void uGenerate (float[] channels)
  {
    if ( audio.isPatched() )
    {

      for (int i = 0; i < channels.length; i++){     
        // convert float to short 2^15       
        short temp = (short)( audio.getLastValues()[i] * 32768.);

        // byte swap
        int b1 = temp & 0xff;
        int b2 = (temp >> 8) & 0xff;
        temp = (short)(b1 << 8 | b2 << 0);

        // convert short back to a float
        channels[i] = temp * (1. / 32768.);
      } 
    }  
  }
}

View this code on GitHub

class DrawWave implements AudioListener
{
  private float[] left;
  private float[] right;
  private int x;
  private int y;
  private int width;
  private int height;
  private color c;
  private color bg;
  private boolean drawbackground;
  
  DrawWave(int xx, int yy, int ww, int hh)
  {
    left = null; 
    right = null;
    
    this.x = xx;
    this.y = yy;
    this.width = ww;
    this.height = hh;
    
    c = color (255);
    bg = color (30, 189, 210);
    drawbackground = false;
  }
  
  synchronized void samples(float[] samp)
  {
    left = samp;
  }
  
  synchronized void samples(float[] sampL, float[] sampR)
  {
    left = sampL;
    right = sampR;
  }
  
  synchronized void draw()
  {
    if ( left != null && right != null )
    {
      // playing nice by localizing style    
      pushStyle();
      stroke(c);
      
      if (drawbackground)
      {
        fill (bg);
        rect(this.x, this.y, this.width-1, this.height);
      }
      noFill();
       
      float inc = (float)this.width / left.length;
      
      float quarterheight = this.height / 4;
      float threequarterheight = quarterheight * 3;
  
      beginShape(POINTS);
      for (int step=0;step<left.length;step++) {
             vertex ( (inc*step) + this.x, left[step]* quarterheight + this.y + quarterheight);
      }
      endShape();

      beginShape(POINTS);
      for (int step=0;step<right.length;step++) {
             vertex ( (inc*step) + this.x, right[step]* quarterheight + this.y + threequarterheight);
      }
      endShape();
      
      popStyle();
    }    
  }
  
  /// setter methods
  public void setColour(color cc)
  {
     c = cc; 
  }
  
  public void background(boolean b)
  {
     drawbackground = b; 
  }
  
  public void setBackgroundColour(color cc)
  {
    bg = cc;
  }
}

View this code on GitHub

Day 3

Friday September 03, 2010
Category: Creative Pact 2010

Today was a challenge. I downloaded the BETA of MINIM so that I could try the new UGEN api. It is interesting but not fully featured yet. I saw a Granulator in there and I got excited. I wasn’t able to make any good sounds and I ran into some troubles with controlP5 and MINIM where they both had Controller classes and Events.
There is a crazy solution where the name of a controlP5 object can be declared as a global and the slider will update the global. I have to look further into why this works but it certainly minimizes the amount of code I have to write to make a basic GUI.
This example does a simple mapping of the BitCrush UGEN with a slider. It also has a display for the audio output. I would love to have access to the audio input too. More work to be done. I am learning a lot here.
Screenshot of software.
Screenshot of software.


import ddf.minim.AudioOutput;
import ddf.minim.Minim;
import ddf.minim.ugens.*;
import controlP5.*;

ControlP5 controlP5;
Slider glmin, glmax, gfmin, gfmax, gsmin, gsmax;
public float grainLengthMin, grainLengthMax, grainFadeMin, grainFadeMax, grainSpaceMin, grainSpaceMax;

Minim minim;
LiveInput in;
AudioOutput out;
Constant controls[] = new Constant[6];
GranulateRandom fx1 = new GranulateRandom();

void setup(){
  size(500, 400);
  minim = new Minim(this);
  out = minim.getLineOut();
  in = new LiveInput( minim.getInputStream(out.getFormat().getChannels(), out.bufferSize(), out.sampleRate(), out.getFormat().getSampleSizeInBits()) ); 
  
  controlP5 = new ControlP5(this);
  glmin = controlP5.addSlider("grainLengthMin",1,100,  15,height/3-80 , width-100,30);
  glmax = controlP5.addSlider("grainLengthMax",101,500,  15,height/3-40,  width-100,30);
  gsmin = controlP5.addSlider("grainSpaceMin", 0,10,  15,height/3  ,   width-100,30);
  gsmax = controlP5.addSlider("grainSpaceMax", 11,500,  15,height/3+40,  width-100,30);
  gfmin = controlP5.addSlider("grainFadeMin",  1,10,  15,height/3+80,  width-100,30);
  gfmax = controlP5.addSlider("grainFadeMax",  11,50,  15,height/3+120, width-100,30);
  
  glmin.setValue(4);
  glmax.setValue(400);
  gsmin.setValue(10);
  gsmax.setValue(40);
  gfmin.setValue(3);
  gfmax.setValue(40);
 
 
 for (int i = 0; i < controls.length; i++)
    controls[i] = new Constant(); 

 controls[0].patch (fx1.grainLenMin); 
 controls[1].patch (fx1.grainLenMax); 
 controls[2].patch (fx1.fadeLenMin); 
 controls[3].patch (fx1.fadeLenMax); 
 controls[4].patch (fx1.spaceLenMin); 
 controls[5].patch (fx1.spaceLenMax);  
 
 controls[0].setConstant (grainLengthMin); 
 controls[1].setConstant (grainLengthMax); 
 controls[2].setConstant (grainFadeMin); 
 controls[3].setConstant (grainFadeMax); 
 controls[4].setConstant (grainSpaceMin); 
 controls[5].setConstant (grainSpaceMax);  
 
 in.patch(fx1).patch(out);
}

void draw(){
  background(50);
  stroke( 255 );
  
 controls[0].setConstant (grainLengthMin); 
 controls[1].setConstant (grainLengthMax); 
 controls[2].setConstant (grainFadeMin); 
 controls[3].setConstant (grainFadeMax); 
 controls[4].setConstant (grainSpaceMin); 
 controls[5].setConstant (grainSpaceMax);  
  
  
  for( int i = 0; i < out.bufferSize() - 1; i++ )
  {
    float x1  =  map( i, 0, out.bufferSize(), 0, width );
    float x2  =  map( i+1, 0, out.bufferSize(), 0, width );
    line( x1, height*.75 + out.left.get(i)*50, x2, height*.75 + out.left.get(i+1)*50);
    line( x1, height*.75 + 50 + out.right.get(i)*50, x2, height*.75 + 50 + out.right.get(i+1)*50);
  }  
  controlP5.draw(); 
}

void stop()
{
  in.close();
  out.close();
  minim.stop();
  super.stop();
}

View this code on GitHub

Day 2

Thursday September 02, 2010
Category: Creative Pact 2010

I have been messing with Minim. This is a simple synthesis sketch that uses a few triangle waves represented by coloured circles and modifies colour by monitoring the pan (which is randomized a bit).
The really fun features seem to be in the BETA so I will play with that a bit tomorrow. I am anxious to try out the granulator and the bitcrusher.

Screenshot of software.
Screenshot of software.


import ddf.minim.*;
import ddf.minim.signals.*;
import ddf.minim.effects.*;

Minim minim;
AudioOutput out;
TriangleWave s1;
TriangleWave s2;
TriangleWave s3;
BandPass bpf;

float circlesize = 50;

void setup()
{
  size(400, 200);
  frameRate(24);
  minim = new Minim(this);
  out = minim.getLineOut(Minim.STEREO);
  
  bpf = new BandPass (500, 100, out.sampleRate() ) ;

  s1 = new TriangleWave(440, 0, out.sampleRate());
  s1.portamento(2000);
  out.addSignal(s1);
  
  s2 = new TriangleWave(450, 0, out.sampleRate());
  s2.portamento(2000);
  out.addSignal(s2);
  
  s3 = new TriangleWave(490, 0, out.sampleRate());
  s3.portamento(2000);
  out.addSignal(s3);
  
  out.addEffect(bpf);
  
  ellipseMode(CENTER);
  smooth();
  noStroke();
  
  s1.setPan(0);
  s2.setPan(1.0);
  s3.setPan(-1.0);
  
  //println(s1.pan() + " " + s2.pan() +" " + s3.pan() );
}

void draw()
{
  background(0);

  fill ( lerpColor (color(255,190,10), color(130,190,180), (s1.pan() + 1)*0.5 ));
  ellipse((s1.pan() * width/2) + width/2, height/2, s1.amplitude() * circlesize , s1.amplitude() * circlesize);
  
  fill ( lerpColor (color(255,190,10), color(130,190,180), (s2.pan() + 1)*0.5 ));
  ellipse((s2.pan() * width/2) + width/2, height/2, s2.amplitude() * circlesize , s2.amplitude() * circlesize);
  
  fill ( lerpColor (color(255,190,10), color(130,190,180), (s3.pan() + 1)*0.5 ));
  ellipse((s3.pan() * width/2) + width/2, height/2, s3.amplitude() * circlesize , s3.amplitude() * circlesize);
  
  if (s1.amplitude() < 0.3)
    s1.setAmp( s1.amplitude() + 0.01);

  if (s2.amplitude() < 0.3)
    s2.setAmp( s2.amplitude() + 0.01);
    
  if (s3.amplitude() < 0.3)
    s3.setAmp( s3.amplitude() + 0.01);
 
  s1.setPan( constrain(s1.pan() + random(-0.01,0.01) ,-1.0,1.0));
  s2.setPan( constrain(s2.pan() + random(-0.01,0.01) ,-1.0,1.0));
  s3.setPan( constrain(s3.pan() + random(-0.01,0.01) ,-1.0,1.0));

}

void mouseClicked(){
  s1.setFreq(s1.frequency() + random(-10,10) );
  s2.setFreq(s2.frequency() + random(-10,10) );
  s3.setFreq(s3.frequency() + random(-10,10) );
  saveFrame();
}

void stop()
{
  out.close();
  minim.stop();
  super.stop();
}

View this code on GitHub

Day 1

Thursday September 02, 2010
Category: Creative Pact 2010

My first sketch is a simple Lissajous curve out of a live audio input. I borrowed some code from a Minim example and a sketch from OpenProcessing.org.

I used the RMS values from the audio buffer to determine the sound and location of each plot. These changes aren’t radical but they add some flavour. Enjoy!

Screenshot of software.
Screenshot of software.

import ddf.minim.*;
import processing.video.*;

Minim minim;
AudioInput input;
WaveformRenderer waveform;

MovieMaker mm;

void setup()
{
  size(640, 480, P2D);
  frameRate(24);
  
  minim = new Minim(this);
  input = minim.getLineIn(Minim.STEREO, 512);
  waveform = new WaveformRenderer();
  input.addListener(waveform);

  mm = new MovieMaker(this, width, height, "mysketchoutput.mov", 24, MovieMaker.H263, MovieMaker.HIGH);
}

void draw()
{
  //background(0);
  fill(0,20);
  noStroke();
  rect(0,0,width,height);
  // see waveform.pde for an explanation of how this works
  waveform.draw();
  mm.addFrame();
}

void stop()
{
  // always close Minim audio classes when you are done with them
  input.close();
  // always stop Minim before exiting.
  minim.stop();
  super.stop();
   mm.finish();
}

void captureEvent(Capture myCapture) {
  myCapture.read();
}

class WaveformRenderer implements AudioListener
{
  private float[] left;
  private float[] right;
  
  color a = color (38,148,200);
  color b = color(200,148,38);
  
  WaveformRenderer()
  {
    left = null; 
    right = null;
  }
  
  synchronized void samples(float[] samp)
  {
    left = samp;
  }
  
  synchronized void samples(float[] sampL, float[] sampR)
  {
    left = sampL;
    right = sampR;
  }
  
  synchronized void draw()
  {
    if ( left != null && right != null )
    {
      noFill();

      float rms = 0;
      for (int i = 0 ; i < left.length; i++)
        rms += left[i];
      rms *= rms;
      //rms /= left.length;
      
      fill(lerpColor(a,b,rms*255));
  
      beginShape();
      for (int step=0;step<left.length;step++) {

             float l = 5-step;  
             int x=(int) (left[step]*l*Math.sin(l*Math.PI/left.length));
             int y=(int) (left[step]*l*Math.cos(l*Math.PI/left.length));
             vertex ( width/4 + x + rms, height/2 + y);
      }
      endShape();

      beginShape();
      for (int step=0;step<right.length;step++) {
             float l = 5-step;  
             int x=(int) (right[step]*l*Math.sin(l*Math.PI/right.length));
             int y=(int) (right[step]*l*Math.cos(l*Math.PI/right.length));
             vertex ( 0.75*width + x - rms, height/2 + y);
      }
      endShape();
    }
  }
}

View this code on GitHub



/*
// copy to setup() to activate
 mm = new MovieMaker(this, width, height, "mysketchoutput.mov",
                       frameRate, MovieMaker.H263, MovieMaker.HIGH);
// copy to the end of draw()
mm.addFrame();
*/


void mouseReleased(){
   println(frameRate);
}

void keyPressed(){
 if(key == ' ')
  saveFrame();

 if (key == 'f')
  println(frameRate); 

 if(key == 's' & mm != null)
    mm.finish();
}

View this code on GitHub



←   newer :: older   →