Today I was so close to not making something but then I looked into logarithmic scales in FFTs and it was very easy to adapt yesterday’s code. I played a little bit more with the camera in OPENGL. Who knows what tomorrow will bring.


import ddf.minim.*;
import ddf.minim.analysis.*;
import javax.media.opengl.*;
import processing.opengl.*;
Minim minim;
AudioInput input;
FFT fft;
float[][] spectra;
int pointer;
int r;
void setup()
{
size(720,480,OPENGL);
hint(ENABLE_OPENGL_4X_SMOOTH);
smooth();
minim = new Minim(this);
input = minim.getLineIn(Minim.STEREO);
fft = new FFT(input.bufferSize(), input.sampleRate() );
fft.logAverages(22, 2);
spectra = new float[50][fft.avgSize()];
colorMode(HSB,1000);
}
void draw()
{
camera(width/2.0, height/10.0 + cos (r++/TWO_PI)*100, (height/2.0) / tan(PI*60.0 / 360.0) , width/2.0, height/2.0, 0, 0, 1, 0);
fft.forward(input.mix);
for (int i = 0 ; i < fft.avgSize() ; i++)
spectra[ pointer ][i] = fft.getAvg(i);
background(0);
noFill();
translate(0,height - 100);
for ( int q = 1 ; q <= 50 ; q++)
{
stroke(200,1000 - (q*20), 1000 - (q*20) );
beginShape();
for (int i = 0 ; i < fft.avgSize() ; i++)
curveVertex(i * (float)width/fft.avgSize() , spectra[ (pointer+q) % 50 ][i] * height );
endShape();
translate(0,0, -200);
}
pointer = (pointer + 1) % 50;
}
void keyPressed()
{
if (key == ' ')
saveFrame();
}
View this code on GitHub
I was hoping to have some success with ArrayLists today but I didn’t. I finally have the waterfall code down but it goes backwards from past to present instead of present to past. It looks kinda neat this way, though. I also added colour! For me, working in HSB seems to be more closely related to my headspace than RGB, so if I need colour I am going to stick to that for now.
This sketch uses linear averages of FFT which are really easy to compute and set up but the result is less than pleasing. I think tomorrow I will play with the log function and see if I can get something a little closer to what I think it should look like.


import ddf.minim.*;
import ddf.minim.analysis.*;
Minim minim;
AudioInput input;
FFT fft;
float[] newspectrum;
blob newblob;
ArrayList drawings;
int r;
void setup()
{
size(720,480,P3D);
smooth();
minim = new Minim(this);
input = minim.getLineIn(Minim.STEREO);
fft = new FFT(input.bufferSize(), input.sampleRate() );
drawings = new ArrayList();
colorMode(HSB,1000);
}
void draw()
{
fft.forward(input.mix);
background(0);
newspectrum = new float[fft.specSize()];
for (int i = 0 ; i < newspectrum.length ; i++)
newspectrum[i] = fft.getBand(i);
newblob = new blob(newspectrum);
drawings.add(newblob);
for(int i = 0 ; i < drawings.size() ; i++)
{
blob b = (blob)drawings.get(i);
b.drawme();
}
}
class blob
{
float[] f;
int z;
float size = 50;
blob(float[] points)
{
f = points;
}
void drawme()
{
pushMatrix();
translate(0,0,z--);
fill(20, 1000+z, 1000+z);
stroke(20,1000+z, 1000+z);
beginShape();
for(int i = 0 ; i < f.length ; i++)
curveVertex(i* width/f.length , f[i] *size);
endShape();
popMatrix();
}
}
View this code on GitHub
Today I messed around with some simple spectral displays and trying other parts of the Processing API. I have added curveVertex to my bag of tricks. This patch has two curvy lissajous spectral displays rotating in contrary motion and a set of bars representing linear spectral averages.
This was the first time I put some more interaction into a sketch. I have a key that changes the mode of the layering. I have been working on things and discovering stuff that I like about a sketch but often it goes away when I make the final thing that I like most. So, I made a little mistake in the process and kept it as an option by pressing the d key.
I still have to look into waterfall plots and buffering. Maybe tomorrow.


import ddf.minim.*;
import ddf.minim.analysis.*;
Minim minim;
AudioInput input;
FFT fft;
boolean darkness = false;
int r;
void setup()
{
size(720,480,P2D);
smooth();
minim = new Minim(this);
input = minim.getLineIn(Minim.STEREO);
fft = new FFT(input.bufferSize(), input.sampleRate() );
fft.linAverages(10);
background(0);
}
void draw()
{
fft.forward(input.mix);
noStroke();
fill(0,19);
rect(0,0,width,height);
stroke(input.mix.level() * 255);
strokeWeight(.1);
pushMatrix();
translate(width/4,height/4);
rotate(PI - (float)r/100);
beginShape();
for (int i = 0 ; i < fft.avgSize(); i++)
{
fill( fft.getBand(i) * 255 , 40);
curveVertex(sin ( (float)i/fft.avgSize() * 2 *TWO_PI) *fft.getBand(i) * width/2 , cos( (float)i/fft.avgSize() * 2 * TWO_PI) * fft.getBand(i) * height/2 );
}
endShape(CLOSE);
popMatrix();
pushMatrix();
translate(width/4*3,height/4*3);
rotate(PI + (float)r++/100);
beginShape();
for (int i = 0 ; i < fft.avgSize(); i++)
{
fill( fft.getBand(i) * 255 , 40);
curveVertex(sin ( (float)i/fft.avgSize() * 2 *TWO_PI) *fft.getBand(i) * width/2 , cos( (float)i/fft.avgSize() * 2 * TWO_PI) * fft.getBand(i) * height/2 );
}
endShape(CLOSE);
popMatrix();
int spacing = width / fft.avgSize();
if (!darkness)
stroke(180);
for (int i = 0 ; i < fft.avgSize(); i++)
{
strokeWeight(fft.getBand(i) * 50);
line( spacing * i + spacing/2, 0, spacing * i + spacing/2, height);
}
}
void stop()
{
input.close();
minim.stop();
super.stop();
}
void keyPressed()
{
if (key == ' ')
saveFrame();
if (key == 'd' | key == 'D' )
darkness = !darkness;
}
View this code on GitHub
Today is a simple patch that does a spectral lissajous plot. Enjoy!


import javax.media.opengl.*;
import processing.opengl.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
Minim minim;
AudioInput input;
FFT fft;
float a;
void setup()
{
size(720,480,OPENGL);
hint(ENABLE_OPENGL_4X_SMOOTH);
minim = new Minim(this);
input = minim.getLineIn(Minim.STEREO);
fft = new FFT(input.bufferSize(), input.sampleRate() );
fft.linAverages(10);
background(0);
}
void draw()
{
fft.forward(input.mix);
noStroke();
fill(0,19);
rect(0,0,width,height);
stroke(255);
strokeWeight(1);
translate(width/2,height/2);
beginShape();
for (int i = 0 ; i < fft.avgSize(); i++)
{
vertex(sin (fft.getBand(i) * i/fft.avgSize()) * width/2 , cos(fft.getBand(i) * i/fft.avgSize()) * height/2 );
}
endShape();
}
void stop()
{
input.close();
minim.stop();
super.stop();
}
void keyPressed()
{
if (key == ' ')
saveFrame();
}
View this code on GitHub
Today I almost forgot to do my piece. I have been watching a lot of Alva Noto so today is my stab at a classic bass drum gesture. A black screen with a mouse click that fires a bass drum sample and flashes a white screen that fades. I didn’t think an image of a white or black screen was worth a screenshot, so enjoy the code.
import javax.media.opengl.*;
import processing.opengl.*;
import ddf.minim.*;
import ddf.minim.ugens.*;
Minim minim;
AudioOutput out;
Oscil o;
Damp env;
float a;
void setup()
{
size(720,480,OPENGL);
hint(ENABLE_OPENGL_4X_SMOOTH);
minim = new Minim(this);
out = minim.getLineOut(Minim.STEREO);
env = new Damp();
o = new Oscil(50,1.0, Waves.SINE);
o.patch(env).patch(out);
fill(0);
noStroke();
rect(0,0,width,height);
}
void draw()
{
noStroke();
fill(0,6);
rect(0,0,width,height);
}
void mouseClicked()
{
fill(255);
rect(0,0,width,height);
o.setPhase(0);
env.activate();
}
View this code on GitHub
Whew! Here is a quick patch based upon a circle that draws brightness based on the level according to FFT analysis. I can see this moving and rotating in the future but for today I have something done.
I think I am going to start looking at saving frames and doing waterfall like displays so you can see into the past. That should be fun.


import javax.media.opengl.*;
import processing.opengl.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
Minim minim;
FFT fft;
AudioInput input;
float[] points;
int numberofpoints;
void setup()
{
size(720,480,OPENGL);
hint(ENABLE_OPENGL_4X_SMOOTH);
minim = new Minim(this);
input = minim.getLineIn(Minim.STEREO, 512);
fft = new FFT(input.bufferSize(), input.sampleRate() );
numberofpoints = fft.specSize();
points = new float[numberofpoints];
for ( int i = 0 ; i < numberofpoints/2; i++)
{
points[i] = sin( (float)i/numberofpoints*2 * TWO_PI) * height/2 + width/2;
points[i+numberofpoints/2] = cos( (float)i/numberofpoints*2 * TWO_PI) * height/2 + height/2;
}
noStroke();
fill(0);
rect(0,0,width,height);
}
void draw()
{
fill(0,5);
noStroke();
rect(0,0,width,height);
fill(255);
float audiolevel = input.mix.level();
fft.forward(input.mix);
strokeWeight(5);
for ( int i = 0 ; i < numberofpoints/2; i++)
{
stroke( fft.getBand(i) * 100);
point( points[i] , points[i+numberofpoints/2] );
}
}
void mousePressed()
{
noStroke();
fill(255);
rect(0,0,width,height);
}
void keyPressed()
{
if (key == ' ')
saveFrame();
}
void stop()
{
input.close();
minim.stop();
super.stop();
}
View this code on GitHub
Today was a good day. I have settled on 720x480 resolution for now so I can do things in native DVD resolution and hopefully make some nice looking video at the end of this experiment. I came up with an idea of circle that responds to audio. I made it respond to volume for brightness and I rendered the circle with a crude particle system. I also added some Alva Noto like flashing for fun.


import javax.media.opengl.*;
import processing.opengl.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
Minim minim;
FFT fft;
AudioInput input;
PGraphics graph;
PImage img;
int r;
float[] points;
int x;
int numberofpoints = 50000;
void setup()
{
size(720,480,OPENGL);
hint(ENABLE_OPENGL_4X_SMOOTH);
points = new float[numberofpoints];
for ( int i = 0 ; i < numberofpoints/2; i++)
{
points[i] = sin( (float)i/numberofpoints*2 * TWO_PI) * height/2 + width/2;
points[i+numberofpoints/2] = cos( (float)i/numberofpoints*2 * TWO_PI) * height/2 + height/2;
}
minim = new Minim(this);
input = minim.getLineIn(Minim.STEREO, 512);
noStroke();
fill(0);
rect(0,0,width,height);
}
void draw()
{
fill(0,5);
noStroke();
rect(0,0,width,height);
fill(255);
for (int i = 0; i < points.length ; i++)
points[i] += random(-2,2);
float audiolevel = input.mix.level();
stroke(audiolevel*500);
strokeWeight(1);
for ( int i = 0 ; i < numberofpoints/2; i++)
point( points[i] , points[i+numberofpoints/2] );
}
void mousePressed()
{
noStroke();
fill(255);
rect(0,0,width,height);
}
void keyPressed()
{
if (key == ' ')
saveFrame();
}
void stop()
{
input.close();
minim.stop();
super.stop();
}
View this code on GitHub
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.


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
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];
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;
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;
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);
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];
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];
rsum+=r[p1]-r[p2];
gsum+=g[p1]-g[p2];
bsum+=b[p1]-b[p2];
yi+=w;
}
}
}
View this code on GitHub
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.


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()
{
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.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;
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();
model.render();
shader.stop();
renderer.endGL();
}
void keyPressed()
{
if (key == ' ')
saveFrame();
}
void mousePressed()
{
mybool = !mybool;
}
View this code on GitHub
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.

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);
renderer.model(myshape);
renderer.endGL();
}
void keyPressed()
{
if (key == ' ')
saveFrame();
}
void mousePressed()
{
r++;
}
GLModel newmodel ( )
{
ArrayList vertices = new ArrayList();
for (int i = 0; i < 400; i++)
{
vertices.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);
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
← newer
::
older →