BoxySean sent me a link to SuperDraw yesterday and I was really blown away. Then I looked at who was responsible and it made a lot of sense. So today I thought I would try and do some 3D drawing using sound levels. I originally tried to make some shapes and have them connect and then I realized I would have to come up with a smart system for stacking shapes. That might be another day. For now I have a little reactive audio drawing tool that I can expand on in the future.


import ddf.minim.*;
Minim minim;
AudioInput in;
int r;
ArrayList shapes = new ArrayList();
void setup()
{
size(720,480, P3D);
hint(ENABLE_OPENGL_4X_SMOOTH);
minim = new Minim(this);
in = minim.getLineIn(Minim.STEREO, 512);
shapes.add( new PVector(10,20,30) );
stroke(240,50);
fill(180,100);
}
void draw()
{
background(0);
shapes.add ( new PVector ( in.mix.level()*width , in.mix.level()*height, 10*log(in.mix.level()) ) );
translate(width/2, height/2);
rotateY((float)r++/300);
beginShape();
for ( int i = 0 ; i < shapes.size() ; i++ )
{
float[] p1 = ( (PVector)shapes.get(i) ).array();
vertex( p1[0], p1[1] ,p1[2] );
}
endShape();
}
void mousePressed()
{
saveFrame();
}
View this code on GitHub
Today I had an idea to see if I could kaleidoscope an image or make a mirror. This was something I was thinking of as a way to illustrate mono signals and then I could modify the images as the signals diverged. I played around with rotating a bit and then remembered that it could get ugly and convoluted so I did a bit of googling and the Processing forums showed a gem: scale(). I can set the scale to negative values in either the x or y dimension (or z if you want to get crazy) and then move the image accordingly and all is fine.
I set up minim to blend a noise image into my scene if there is an onset and then I played around with rotating boxes again. Look, it isn’t black and white!


import ddf.minim.*;
Minim minim;
AudioInput in;
PImage img;
PGraphics graph;
int r;
void setup()
{
size(720,480,P2D);
minim = new Minim(this);
in = minim.getLineIn(Minim.STEREO, 512);
img = createImage(width,height, ARGB);
graph = createGraphics(width/2, height, P2D);
graph.smooth();
graph.beginDraw();
graph.background( color (290, 39, 111, 80));
graph.stroke(200);
for (int i = 0 ; i < 30 ; i++)
graph.line(0,0,random(graph.width/2, graph.width) , random(graph.height/2, graph.height));
graph.endDraw();
img.loadPixels();
for (int i = 0 ; i < img.pixels.length ; i++)
img.pixels[i] = color( sin(random (0,TWO_PI)) *122 + 122);
img.updatePixels();
}
void draw()
{
background(sin((float)frameCount/20) * 20 + 20 );
image (graph,0,0);
graph.beginDraw();
graph.stroke(200);
graph.rotate(r++);
graph.rect(graph.width/2, graph.height/2, 40,40);
graph.endDraw();
pushMatrix();
scale(-1.0, 1.0);
image(graph,-width,0);
popMatrix();
if ( in.mix.level() > 0.1 )
{
blend(img, 0,0,width,height, 0,0, width,height, DODGE);
saveFrame();
}
}
void mouseClicked ()
{
saveFrame();
}
void stop()
{
in.close();
minim.stop();
super.stop();
}
View this code on GitHub
No sound today. I was thinking of making something that might look like a Shepard’s Tone and I came up with this simple idea of a complex polygon that expands outwards into the viewer. I got it going and then I thought it would be cool for it to be endless. I will have to think how I can do that practically. I have a feeling it will borrow some waterfall code and test to see if vertices are out of visual range and then put them back into the pile. I think I will need to sleep on that one.


import javax.media.opengl.*;
import processing.opengl.*;
int r;
int numberoflines = 9000;
float[] x = new float [numberoflines];
float[] y = new float [numberoflines];
float[] z = new float [numberoflines];
void setup(){
size(720,480, OPENGL);
hint(ENABLE_OPENGL_4X_SMOOTH);
smooth();
fill(240,30);
stroke(140,40);
for (int i = 0 ; i < numberoflines ; i++)
{
x[i] = random(-width/2, width/2);
y[i] = random(-height/2, height/2);
z[i] = random(0,500);
}
}
void draw(){
background(0);
translate(width/2, height/2,-500);
rotate((float)r++/800);
noFill();
strokeWeight(4);
beginShape();
for (int i = 0; i < x.length; i++)
{
vertex( x[i], y[i], z[i]);
}
endShape();
for (int i = 0; i < x.length; i++)
{
x[i] += random(-1,1);
y[i] += random(-1,1);
z[i] += random(-1,1);
z[i] += random( (float) i * .001);
}
}
void mouseClicked(){
saveFrame();
}
View this code on GitHub
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
← newer
::
older →