Introduction: Sound Fruit - How to Make a Sculptural Audio Visualizer
Sound Fruit is a project I did to study a free graphic scripting software called Processing. It consists of a little program that translates a mp3-file into a 3-dimensional object in .dxf format. The exported object is essentially an expression of sound, frozen in time. Depending on what sound you feed it, it will vary in its shape, giving every fruit a unique form. In the example shown I used the song "Rolling with the Punches" by The Blue Stones as a test.
The exported file can be opened in another 3d program, looked at, printed, or whatever you can think of! Potentially, you could print it hollow, wire it with an LED or two and make a cute little lamp.
Here is a video showing it in action:
Sound.Fruit - Sculptural Audio Visualizer from Tao C on Vimeo.
You need Processing to open the program. It's free, it's fun, and it can be downloaded here.
If you only want to use the program, you only need to follow the first 3 steps.
For people who are interested in the sketch itself, I'm explaining the details of the script starting from step 4. During my learning process I struggled quite a bit with finding good information about more advanced concepts and I had to piece together a lot of the information from obscure corners of the internet. I hope you will find this instructable useful in your own programming. This program is not a finished product yet and I'm still working on it, so if there are any suggestions or questions, feel free to comment. I'm barely more than a beginner myself, so any tips are greatly appreciated!
Many thanks to Brad Borevitz, who helped me a great deal in understanding programming and its application within the visual arts.
EDIT: I have added scale functionality and replaced the original .zip package with the updated one. Please redownload if you have the old version.
To scale down, press the 'n' key, to scale up, press 'm'.
Step 1: Run the Sketch
Make sure you have Processing installed on your computer. Download the attached file, unzip it and you will see a number of .pde files. Double-click the one named "soundfruit_sketch.pde" to open the main file. In the sketch window, you will see a play-button in the top left corner. Click it to run the sketch.
Attachments
Step 2: How to Use the Program
In the bottom right corner, there are two buttons. The play-button pauses/starts the music. The music will loop once it finishes. The record-button takes a "snapshot" of the object and exports it as a .dxf-file. Once it's recorded, the dxf-file will be in the main folder of the sketch. That's it. Simple as that.
Step 3: How to Imprint Your Own Sounds
Go into the folder, and you should see a file named "punches.mp3". This is the file that is played when the program runs. The sound-data that you want to run has to be a .mp3-file, so convert it if it's not. You have 2 options to put it into the program:
1. Rename your file to "punches.mp3" and simply replace it with the one in the "data" folder.
2. Copy your file into the "data" folder, go into the sketch and change the following line:
thinking = minim.loadFile("punches.mp3", 1024);
to
thinking = minim.loadFile("yourfilename.mp3", 1024);
Step 4: Setting Up Global Parameters
//The program uses 3 built-in libraries, the minim libraries are used for sound analysis, while the processing.dxf library //allows you to "record" 3d objects.
import ddf.minim.analysis.*;
import ddf.minim.*;
import processing.dxf.*;
//These parameters control how the fruit behaves and its resolution and appearance.
int m = 6; //logavg 1 controls distribution of spectrum
int n = 6; //logavg 2 controls amplitude of spectrum
int ptDensity = 200; //density of circle around y-axis
float r; //radius
//Setup for the "scan" movement.
float beta = 0; //angle
int idx = 0; //index
//sound setup needed to play the mp3 file.
Minim minim;
FFT fft;
AudioInput in;
AudioPlayer thinking;
//The fruit is essentially a sphere that is divided into UV coordinates. This array stores the coordinates from each point on //the surface, allowing the fruit to memorize the highs and lows registered in the previous cycle.
PVector [][] coords;
The following parameters create the record button functionality.
RecordButton recIt;
int recX, recY, recSize;
boolean recHit = false;
boolean record = false;
color recFill, recHighlight;
int waveSize = 0;
boolean waveHit = false;
int waveFade = 255;
//play button setup
PlayButton playIt;
int playX, playY, playSize;
boolean playHit = false;
color playFill, playHighlight;
boolean play = true;
Step 5: Setting Up the Program
//defines the size of program window and also that the program operates in a 3 dimensional space.
size(displayWidth, (displayHeight-20), P3D);
//sound creation - loads and plays the file included with the sketch.
minim = new Minim(this);
thinking = minim.loadFile("punches.mp3", 1024);
thinking.loop();
fft = new FFT(thinking.bufferSize(), thinking.sampleRate());
fft.logAverages(m, n);
//In order to create a deformable sphere, I could not use the built-in sphere() function as it does not allow me to access //the point coordinates that make up the sphere. For that reason, I looked up the mathematical formula for spheres on //some math-discussion boards, which gave me the XYZ coordinates for every point, which would be stored in the array //that was set up before-hand.
r = width/50; //radius
beta = TWO_PI/ptDensity; //y-axis rotation
coords = new PVector [ptDensity+1][fft.avgSize()];
float x, y, z;
for (int i = 0;i float u = (i*TWO_PI/ptDensity);
for (int j = 0;j float v = (PI/coords[i].length)*j-PI/2;
// x = r * cos(theta);
// y = r * sin(theta);
x=r* sin(u)* cos(v);
y=r * cos(u) * cos(v);
z= r * sin(v);
coords[i][j] = new PVector(x, y, z);
println(u + " " + v + " " + coords[i][j]);
}
}
//playbutton parameters
playX = width-100;
playY = height-100;
playSize = 30;
ellipseMode(CENTER);
playFill = color(5);
playHighlight = color(200);
//create play button
playIt = new PlayButton();
//recbutton parameters
recX = width-60;
recY = height-100;
recSize = 30;
//ellipseMode(CENTER);
recFill = color(5);
recHighlight = color(200);
//create play button
recIt = new RecordButton();
}
Step 6: Shaping the Fruit
idx = (idx+1)%(ptDensity);
// calculate current row
for (int i = 0; i<fft.avgSize(); i++) {
float theta = (PI/fft.avgSize())*i-PI/2;
//the current row translates sound by picking up the sound spectrum and stretching it to fit on a half circle. the value at //each interval of the spectrum then translates into a magnitude change, radiating from the center of the sphere.
float add = (coords[idx][i].mag() + (0.05*(r+modFactor(i)*fft.getAvg(i))));
coords[idx][i].setMag(add);
}
//this double for-loop draws the half-circle and rotates it around the fruit, creating a scanner that adds to the distance from each point to the center.
for (int j = 0; j<(ptDensity); j++) { //loop rotates half circle around y-axis to form sphere
//the beginShape() function spans all points on the object and creates the actual surface that makes up the object.
beginShape(QUAD_STRIP);
for (int i = 0; i<fft.avgSize(); i++) { //this loop draws the half circle
// float theta = (PI/fft.avgSize())*i-PI/2;
noStroke();
// stroke(map(fft.getAvg(i), 0, fft.avgSize(), 0, 256), 50, 55);
fill(map(fft.getAvg(i), 0, fft.avgSize(), 0, 256), 50, 55);
vertex(coords[j][i].x, coords[j][i].y, coords[j][i].z);
if (j == ptDensity-1) {
vertex(coords[0][i].x, coords[0][i].y, coords[0][i].z);
}
else {
vertex(coords[j+1][i].x, coords[j+1][i].y, coords[j+1][i].z);
} //create quadstrip-compatible geometry
}
endShape(CLOSE);
}