Adam's Blog
×

Day 13

Tuesday September 14, 2010
Category: Creative Pact 2010

Today I am working with a visual idea that I want to turn into music. I have a blurry scene where the action moves up and a sine wave moves down. It is a start.

I am using a stack blur from quasimondo. It is super fast and it looks ok. Not quite as pleasurable as a gaussian but way faster. I also got bit on a pointer reference thing when converting a PGraphics to a PImage. Be careful! PGraphics is a subclass of PImage and you can assign one to the other thanks to inheritance but to copy the actual image from one to the other you have to use the get() method  and then things will behave like you expect. Thanks to the javadocs for Processing.

I have linked code at the bottom.
Screenshot of software.
Screenshot of software.


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

Minim minim;
AudioOutput out;
SineWave sine;

PGraphics graph;
PImage img;
int r;
boolean mybool;
float[] points;
int x;
void setup()
{
  size(720,480,P2D); 
  
  graph = createGraphics(720,480,P2D);
  img = createImage(720,480, RGB);
  
  points = new float[400];  
  for ( int i = 0 ; i < 100; i++)  
  {
    points[i] = width/2 + random(-width/2, width/2) ; 
    points[i+100] = height/2 + random(-height/2, height/2) ;
    points[i+200] = width/2 + random(-width/2, width/2) ; 
    points[i+300] = height/2 + random(-height/2, height/2) ;  
  }
  
  smooth();
  
 
  
 minim = new Minim(this);
 out = minim.getLineOut(Minim.STEREO);
 sine = new SineWave(440, 0.5, out.sampleRate());
 sine.portamento(200); 
 out.addSignal(sine);
}

void draw()
{
  graph.beginDraw();
  graph.background(0);
  graph.noStroke();
  graph.fill(255);
  
  graph.rect(0,0,width,height/2 + x--);
  
  for (int i = 0; i < points.length ; i++)
     points[i] += random(-2,2);
  
  graph.stroke(255);
  graph.strokeWeight(1.4);
  
  for ( int i = 0 ; i < 100; i++)  
    graph.line( points[i] , points[i+100], points[i+200], points[i+300] );
    
  graph.endDraw();
  
  img = graph.get();

  fastBlur(img, 10);
  img.filter(POSTERIZE,3);
  fastBlur(img,4);
  image(img,0,0);
  
  sine.setFreq(440 + x);

}

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

View this code on GitHub

// Stack Blur v1.0
//
// Author: Mario Klingemann <mario@quasimondo.com>
// http://incubator.quasimondo.com

void fastBlur(PImage img, int radius){
  if (radius<1){
    return;
  }
  int w=img.width;
  int h=img.height;
  int wm=w-1;
  int hm=h-1;
  int wh=w*h;
  int div=radius+radius+1;
  int a[]=new int[wh]; // i've added this
  int r[]=new int[wh];
  int g[]=new int[wh];
  int b[]=new int[wh];
  int asum,rsum,gsum,bsum,x,y,i,p,p1,p2,yp,yi,yw; // and the asum here
  int vmin[] = new int[max(w,h)];
  int vmax[] = new int[max(w,h)];
  int[] pix=img.pixels;
  int dv[]=new int[256*div];
  for (i=0;i<256*div;i++){
     dv[i]=(i/div);
  }

  yw=yi=0;

  for (y=0;y<h;y++){
    asum=rsum=gsum=bsum=0; // asum
    for(i=-radius;i<=radius;i++){
	p=pix[yi+min(wm,max(i,0))];
	asum+=(p>>24) & 0xff;
	rsum+=(p & 0xff0000)>>16;
	gsum+=(p & 0x00ff00)>>8;
	bsum+= p & 0x0000ff;
    }
    for (x=0;x<w;x++){
	a[yi]=dv[asum];
	r[yi]=dv[rsum];
	g[yi]=dv[gsum];
	b[yi]=dv[bsum];

	if(y==0){
	  vmin[x]=min(x+radius+1,wm);
	  vmax[x]=max(x-radius,0);
	} 
	p1=pix[yw+vmin[x]];
	p2=pix[yw+vmax[x]];
	
	asum+=((p1>>24) & 0xff)-((p2>>24) & 0xff); // asum
	rsum+=((p1 & 0xff0000)-(p2 & 0xff0000))>>16;
	gsum+=((p1 & 0x00ff00)-(p2 & 0x00ff00))>>8;
	bsum+= (p1 & 0x0000ff)-(p2 & 0x0000ff);
	yi++;
    }
    yw+=w;
  }

  for (x=0;x<w;x++){
    asum=rsum=gsum=bsum=0;
    yp=-radius*w;
    for(i=-radius;i<=radius;i++){
	yi=max(0,yp)+x;
	asum+=a[yi]; // asum
	rsum+=r[yi];
	gsum+=g[yi];
	bsum+=b[yi];
	yp+=w;
    }
    yi=x;
    for (y=0;y<h;y++){
	pix[yi] = (dv[asum]<<24) | (dv[rsum]<<16) | (dv[gsum]<<8) | dv[bsum]; 
	if(x==0){
	  vmin[y]=min(y+radius+1,hm)*w;
	  vmax[y]=max(y-radius,0)*w;
	} 
	p1=x+vmin[y];
	p2=x+vmax[y];
	
	asum+=a[p1]-a[p2]; // asum
	rsum+=r[p1]-r[p2];
	gsum+=g[p1]-g[p2];
	bsum+=b[p1]-b[p2];

	yi+=w;
    }
  }
} 

View this code on GitHub

Day 12

Sunday September 12, 2010
Category: Creative Pact 2010

I was again playing with GLGraphics and had a happy accident. I added some more shaders to a sketch and got these swirling worlds. I think this is something I am going to keep. I did something I thought I understood and came up with these great visuals for some reason. This illustrates to me that I need a little more theory before I dig deeper with shaders. Some other time.
My big problem is that I haven’t added audio so I am diverting a bit from my original idea at the beginning of the month.  Tomorrow I will refocus.

Screenshot of software.
Screenshot of software.

import javax.media.opengl.*;
import processing.opengl.*;
import codeanticode.glgraphics.*;

GLSLShader shader;
GLModel model;
int numPoints = 1024;
int r;
float[] coords;
float[] colors;
boolean mybool = true;

float denominator = 4000;

void setup()
{
    // DVD resolution
    size(720, 480, GLConstants.GLGRAPHICS);
    hint( DISABLE_OPENGL_2X_SMOOTH );  
    hint( ENABLE_OPENGL_4X_SMOOTH );  
    
    
    model = new GLModel(this, numPoints, GLModel.QUAD_STRIP, GLModel.DYNAMIC);
    //model.setBlendMode(SUBTRACT);    
    model.initColors();
    coords = new float[4 * numPoints];
    colors = new float[4 * numPoints];
    for (int i = 0; i < numPoints; i++)
    {
        for (int j = 0; j < 3; j++) 
          coords[4 * i + j] = height * random(-1, 1);
        coords[4 * i + 3] = 1.0; // The W coordinate of each point must be 1.
        for (int j = 0; j < 3; j++) 
          colors[4 * i + j] = random(0, 1);
        colors[4 * i + 3] = 0.9;      
    }    
     model.updateVertices(coords);  
     model.updateColors(colors);
     
     shader = new GLSLShader(this, "fishvert.glsl", "fishfrag.glsl");
}

void draw()
{
  GLGraphics renderer = (GLGraphics)g;
  renderer.beginGL();
  
  translate(width/2, height/2);

  background(160);
  if (mybool)
  {
    rotateY((float)r++/denominator);
    rotateX((float)r/denominator);
  }
  else
  {
    rotateY( (float)r/denominator - PI) ;
    rotateX( (float)r/denominator - PI) ;
  }
  shader.start(); // Enabling shader.
  
  model.render();
  
  shader.stop(); // Disabling shader.

  renderer.endGL();  
}

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

void mousePressed()
{
  mybool = !mybool;
}

View this code on GitHub

Day 11

Sunday September 12, 2010
Category: Creative Pact 2010

Today was a bit of a bust. I tried writing some GLSL shaders using GLGraphics and didn’t have much luck. I have been wanting to dig into the library for awhile but haven’t had time, so today was the day. I was able to get some simple frag shaders going but blurs weren’t working. I upgraded to the new version only to find new functionality came with a new API. The patch I made works but crashes after 10 seconds or so. When I have more time I will look further into the issue or post it on the forums but for now I just have a day to make something.

Screenshot of software.

import javax.media.opengl.*;
import processing.opengl.*;
import codeanticode.glgraphics.*;

GLSLShader shader;
GLModel myshape;

int r;

void setup()
{
    size(640, 480, GLConstants.GLGRAPHICS);

    shader = new GLSLShader(this, "toonvert.glsl", "Pixelate.glsl");
}

void draw()
{
    myshape = newmodel();
  GLGraphics renderer = (GLGraphics)g;
  renderer.beginGL();
  translate(width/2, height/2);
  
  background(180);

  rotateY((float)r/100);
  //shader.start(); // Enabling shader.
  //shader.setVecUniform("camera_pos", 0, 0, 0);
  
  renderer.model(myshape);
 //shader.stop(); // Disabling shader.
  renderer.endGL();  
}

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

void mousePressed()
{
  r++;
}

GLModel newmodel ( )
{
  ArrayList vertices = new ArrayList();
  //ArrayList normals = new ArrayList();
  for (int i = 0; i < 400; i++)
  {
    //strokeWeight(random(3));
    //line(random(width),random(height), random(width), random(height));
    vertices.add(new PVector(random(width)-width/2,random(height)-height/2, random(width)-width/2));
    //normals.add(new PVector(random(width)-width/2,random(height)-height/2, random(width)-width/2));
  }  
  GLModel model = new GLModel(this, vertices.size() , LINES, GLModel.DYNAMIC );
  model.updateVertices(vertices);  
  
  //model.initNormals();  
  //model.updateNormals(normals);  
  
  //model.initColors();
 // model.setColors(0,0,0,255);  
  
  return model;
}

View this code on GitHub

GLModel createTorus(float outerRad, float innerRad, int numc, int numt, int r, int g, int b, int a, String texName) {
  GLModel model;  
  GLTexture tex;
  
  ArrayList vertices = new ArrayList();
  ArrayList normals = new ArrayList();  
  ArrayList texcoords = new ArrayList();
  
  float x, y, z, s, t, u, v;
  float nx, ny, nz;
  float a1, a2;
  int idx = 0;
  for (int i = 0; i < numc; i++) {
    for (int j = 0; j <= numt; j++) {
      for (int k = 1; k >= 0; k--) {
         s = (i + k) % numc + 0.5;
         t = j % numt;
         u = s / numc;
         v = t / numt;
         a1 = s * TWO_PI / numc;
         a2 = t * TWO_PI / numt;
         
         x = (outerRad + innerRad * cos(a1)) * cos(a2);
         y = (outerRad + innerRad * cos(a1)) * sin(a2);
         z = innerRad * sin(a1);
         
         nx = cos(a1) * cos(a2); 
         ny = cos(a1) * sin(a2);
         nz = sin(a1);
         
         vertices.add(new PVector(x, y, z));
         normals.add(new PVector(nx, ny, nz));         
         texcoords.add(new PVector(u, v));
      }
    }
  }
  
  model = new GLModel(this, vertices.size(), QUAD_STRIP, GLModel.STATIC);
  model.updateVertices(vertices);  
  
  if (texName != null && !texName.equals("")) {
    tex = new GLTexture(this, texName);
    model.initTextures(1);
    model.setTexture(0, tex);
    model.updateTexCoords(0, texcoords);
  }
  
  model.initNormals();
  model.updateNormals(normals);  

  model.initColors();
  model.setColors(r, g, b, a);

  return model;  
}

View this code on GitHub

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


←   newer :: older   →