
This was the final applet in motion. Using the minim library for processing, each waveform is generated in realtime as the two sounds play over eachother creating a pretty chaotic sound, but there are some instances of overlapping patterns where the mashup works pretty well. In the third version of the code, the boolean of the two waveforms is generated, producing a new way to visualize the waveforms. View the youtube video here, but I really need to figure out a way to add sound to the video, silence doesn’t do it justice. Charlie Parker, Iggy Pop and Richard Wagner comparison + code:




import processing.dxf.*;
import ddf.minim.analysis.*;
import ddf.minim.*;
FFT fftLog1;
FFT fftLog2;
Waveform myRects;
Minim minim;
AudioPlayer groove1;
AudioPlayer groove2;
boolean record;
PFont font;
PFont fontoutline;
void setup(){
size(1200,600,P3D);
noStroke();
minim = new Minim(this);
groove1 = minim.loadFile(”groove_iggy.mp3″);
groove2 = minim.loadFile(”groove_wagner.mp3″);
groove1.loop();//repeat each song
groove2.loop();
font = loadFont(”HelveticaNeueLT-Bold-18.vlw”);
fontoutline = loadFont(”HelveticaNeueLT-Bold-18.vlw”);
fftLog1 = new FFT(groove1.bufferSize(),groove1.sampleRate()); //create the FFT logarithmic scale
fftLog2 = new FFT(groove2.bufferSize(),groove2.sampleRate());
fftLog1.logAverages(22,4); //adjust numbers to adjust spacing
fftLog2.logAverages(22,4);
float w1 = float ((fftLog1.avgSize()+fftLog2.avgSize())/2);
float x = w1;
float y = 0;
float z = 50;
myRects = new Waveform(x,y,z);
}
void draw(){
background(15);
directionalLight(126,126,126,sin(radians(frameCount)),cos(radians(frameCount)),1);
ambientLight(152,152,152);
for(int i = 0; i < fftLog1.avgSize(); i++){
int w = int(width/fftLog1.avgSize());
float zoom = 1;
float jitter = (max(fftLog1.getAvg(i)*200,fftLog2.getAvg(i)*200 )); //jitter in camera influenced by waveform
PVector foc = new PVector((myRects.x*.5+jitter*.5), myRects.y+jitter, 0);
PVector cam = new PVector(zoom, zoom, -zoom);
if (frameCount < 260){
camera(foc.x+cam.x,foc.y+(cam.y-1500*(cos(radians(-frameCount+60)))),foc.z+cam.z-400,
foc.x,foc.y,foc.z-100,
0,0,1);
//println(-1500*(cos(radians(-frameCount+60))));
}
else {
camera(foc.x+cam.x,foc.y+(cam.y+1418.278),foc.z+cam.z-400,foc.x,foc.y,foc.z-100,0,0,1);
}
}
fftLog1.forward(groove1.mix); //play each song
fftLog2.forward(groove2.mix);
myRects.update1(); //update each waveform+boolean
myRects.update2();
myRects.update3();
myRects.textdraw1(); //draw z height for song waveforms
myRects.textdraw2();
if(record){
beginRaw(DXF, "output.dxf");
}
// DXF will export the stuff drawn between here.
myRects.plotBoolean(); //create surfaces
myRects.plotTrace1();
myRects.plotTrace2();
if(record){
endRaw();
record = false;
println("Done DXF~!");
}
}
void stop() {
groove1.close(); // always close Minim audio classes when you finish with them
groove2.close();
minim.stop(); // always stop Minim before exiting
super.stop();
}
class Waveform{
float x,y,z;
PVector[] pts1 = new PVector[fftLog1.avgSize()];
PVector[] pts2 = new PVector[fftLog2.avgSize()];
PVector[] pts3 = new PVector[fftLog1.avgSize()]; //needed for boolean waveform
PVector[] trace1 = new PVector[0];
PVector[] trace2 = new PVector[0];
PVector[] trace3 = new PVector[0]; //needed for boolean waveform
Waveform(float incomingX, float incomingY, float incomingZ){
x = incomingX;
y = incomingY;
z = incomingZ;
}
void update1(){ //plot boolean waveform
plotB();
}
void plotB(){
for(int i = 0; i < fftLog1.avgSize(); i++){
int w = int(width/fftLog1.avgSize());
x = i*w-1050; //adjust the x position of the waveform here
y = frameCount*5;
z = height/4-fftLog1.getAvg(i)*10;
stroke(0);
point(x, y, z);
pts1[i] = new PVector(x, y, z);
//increase size of array trace by length+1
trace1 = (PVector[]) expand(trace1, trace1.length+1);
//always get the next to last
trace1[trace1.length-1] = new PVector(pts1[i].x, pts1[i].y, pts1[i].z);
}
}
void plotBoolean(){
stroke(255,80);
int inc = (fftLog1.avgSize()+fftLog2.avgSize())/2;
for(int i=1; i<(trace1.length+trace2.length)/2-inc; i++){ vertex(trace1[i].x, trace1[i].y, (max(trace1[i].z,trace2[i].z))+(min(trace1[i].z,trace2[i].z))); void update3(){ // plot first song's waveform void plot1(){ x = -2500+i*w; //adjust the x position of the waveform here stroke(0); void textdraw1(){ //plot first song's z height waveform for(int i =0; i textMode(SCREEN); for(int i=1; i void update2(){ //plot second song's waveform void plot2(){ x = i*w; //adjust the x position of the waveform here stroke(0); void textdraw2(){ textFont(font); void plotTrace2(){ for(int i=1; i void keyPressed() {
if(i%inc != 0){
beginShape(TRIANGLE_STRIP);
float value = (trace1[i].z*100);
float m = map(value, -500, 20000, 0, 255);
fill(m*2, 125, -m*2, 140);
int threshold = 15;
if (trace1[i].z
vertex(trace1[i-1].x, trace1[i-1].y, (max(trace1[i-1].z,trace2[i-1].z))+(min(trace1[i-1].z,trace2[i-1].z)));
vertex(trace1[i+inc].x, trace1[i+inc].y, (max(trace1[i+inc].z,trace2[i+inc].z))+(min(trace1[i+inc].z,trace2[i+inc].z)));
vertex(trace1[i-1+inc].x, trace1[i-1+inc].y,(max(trace1[i-1+inc].z,trace2[i-1+inc].z))+(min(trace1[i-1+inc].z,trace2[i-1+inc].z)));
endShape(CLOSE);
}
}
}
}
plot1();
}
for(int i = 0; i < fftLog1.avgSize(); i++){
int w = int(width/fftLog1.avgSize());
y = frameCount*5;
z = height/4-fftLog1.getAvg(i)*10;
point(x, y, z);
pts3[i] = new PVector(x, y, z);
//increase size of array trace by length+1
trace3 = (PVector[]) expand(trace3, trace3.length+1);
//always get the next to last
trace3[trace3.length-1] = new PVector(pts3[i].x, pts3[i].y, pts3[i].z);
}
}
textFont(font, 10);
float theX = screenX(pts3[i].x+5, pts3[i].y+5, pts3[i].z+5);
float theY = screenY(pts3[i].x+5, pts3[i].y+5, pts3[i].z+5);
fill(255);
text(round(fftLog1.getAvg(i)*100), theX, theY, 0);
if(frameCount>220){
textFont(fontoutline, 24);
fill(155);
text(”wagner”,200,500,0);
text(”iggy”,900,500,0);
text(”max(iggy-wagner)”,500,500,0);
}
}
}
void plotTrace1(){
stroke(255,80);
int inc = fftLog1.avgSize();
beginShape(TRIANGLE_STRIP);
float value = (trace3[i].z*100);
float m = map(value, -500, 20000, 0, 255);
fill(m*2, 125, -m*2, 140);
vertex(trace3[i].x, trace3[i].y, trace3[i].z);
vertex(trace3[i-1].x, trace3[i-1].y, trace3[i-1].z);
vertex(trace3[i+inc].x, trace3[i+inc].y, trace3[i+inc].z);
vertex(trace3[i-1+inc].x, trace3[i-1+inc].y, trace3[i-1+inc].z);
endShape(CLOSE);
}
}
}
plot2();
}
for(int i = 0; i < fftLog2.avgSize(); i++){
int w = int(width/fftLog2.avgSize());
y = frameCount*5;
z = height/4-fftLog2.getAvg(i)*10;
point(x, y, z);
pts2[i] = new PVector(x, y, z);
//increase size of array trace by length+1
trace2 = (PVector[]) expand(trace2, trace2.length+1);
//always get the next to last
trace2[trace2.length-1] = new PVector(pts2[i].x, pts2[i].y, pts2[i].z);
}
}
for(int i =0; i
float theX = screenX(pts2[i].x+5, pts2[i].y+5, pts2[i].z+5);
float theY = screenY(pts2[i].x+5, pts2[i].y+5, pts2[i].z+5);
fill(255);
text(round(fftLog2.getAvg(i)*100), theX, theY, 0);
}
}
stroke(255,80);
int inc = fftLog2.avgSize();
beginShape(TRIANGLE_STRIP);
float value = (trace2[i].z*100);
float m = map(value, -500, 20000, 0, 255);
fill(m*2, 125, -m*2, 140);
vertex(trace2[i].x, trace2[i].y, trace2[i].z);
vertex(trace2[i-1].x, trace2[i-1].y, trace2[i-1].z);
vertex(trace2[i+inc].x, trace2[i+inc].y, trace2[i+inc].z);
vertex(trace2[i-1+inc].x, trace2[i-1+inc].y, trace2[i-1+inc].z);
endShape(CLOSE);
}
}
}
}
// use a key press so that it doesn't make a million files
if (key == 'r') record = true;
}reply