Skip to content

Instantly share code, notes, and snippets.

@plasticmind
Created December 12, 2019 04:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save plasticmind/707e65d61cbe57baa49cc9c5a4748844 to your computer and use it in GitHub Desktop.
Save plasticmind/707e65d61cbe57baa49cc9c5a4748844 to your computer and use it in GitHub Desktop.
Cubes Visualization for Processing
import ddf.minim.*;
import ddf.minim.analysis.*;
Minim minim;
AudioPlayer song;
FFT fft;
// Group frequency bands into 3 zones
// Note: dropping the top 64% of the frequency
// bandwidth since we can't hear it
float specLow = 0.03; // 3%
float specMid = 0.125; // 12.5%
float specHi = 0.20; // 20%
// Create scores for the 3 zones
float scoreLow = 0;
float scoreMid = 0;
float scoreHi = 0;
// Track old scores for value ramping
float oldScoreLow = scoreLow;
float oldScoreMid = scoreMid;
float oldScoreHi = scoreHi;
// Rate at which the score decreases
float scoreDecreaseRate = 8;
// Initialize cube function
int nbCubes;
Cube[] cubes;
// Initialize wall function
int nbMurs = 500;
Mur[] murs;
public void settings() {
pixelDensity(displayDensity());
smooth(8);
//size(1280,720,OPENGL);
fullScreen(P3D);
}
void setup()
{
// Initialize minim library
minim = new Minim(this);
// Load the song
song = minim.loadFile("sinewaves.mp3");
// Load the FFT object for spectral evaluation
fft = new FFT(song.bufferSize(), song.sampleRate());
// Connect cubes to frequencies
nbCubes = (int)(fft.specSize()*(specHi*1.25));
cubes = new Cube[nbCubes];
// All the walls
murs = new Mur[nbMurs];
// Create cubes
for (int i = 0; i < nbCubes; i++) {
cubes[i] = new Cube();
}
// Create walls
for (int i = 0; i < nbMurs; i+=4) {
murs[i] = new Mur(0, height/2, 10, height);
}
for (int i = 1; i < nbMurs; i+=4) {
murs[i] = new Mur(width, height/2, 10, height);
}
for (int i = 2; i < nbMurs; i+=4) {
murs[i] = new Mur(width/2, height, width, 10);
}
for (int i = 3; i < nbMurs; i+=4) {
murs[i] = new Mur(width/2, 0, width, 10);
}
// Additional settings
frameRate(60);
background(0);
// Start the song
song.play(0);
}
void draw()
{
// Advance th // Move forward our evaluation of the song 1 "step"
fft.forward(song.mix);
// # Calculate zone scores for this frame
// Save old values (for easing)
oldScoreLow = scoreLow;
oldScoreMid = scoreMid;
oldScoreHi = scoreHi;
// - Reset values
scoreLow = 0;
scoreMid = 0;
scoreHi = 0;
// - Calculate lows
for(int i = 0; i < fft.specSize()*specLow; i++) {
scoreLow += fft.getBand(i);
}
// - Calculate mids
for(int i = (int)(fft.specSize()*specLow); i < fft.specSize()*specMid; i++) {
scoreMid += fft.getBand(i);
}
// - Calculate highs
for(int i = (int)(fft.specSize()*specMid); i < fft.specSize()*specHi; i++) {
scoreHi += fft.getBand(i);
}
// - Ease downward ramping of our zone scores based on decay rate
if (oldScoreLow > scoreLow) {
scoreLow = oldScoreLow - scoreDecreaseRate;
}
if (oldScoreMid > scoreMid) {
scoreMid = oldScoreMid - scoreDecreaseRate;
}
if (oldScoreHi > scoreHi) {
scoreHi = oldScoreHi - scoreDecreaseRate;
}
// # Create a "global" score that calculates the percieved intensity of all zones
float scoreGlobal = (0.66*scoreLow + 0.8*scoreMid + 1*scoreHi)*1.1;
// Set subtle background color based on intensity
background(scoreLow/100, scoreMid/100, scoreHi/100);
// Create Cubes for each frequency band
for(int i = 0; i < nbCubes; i++)
{
// Value of the frequency band
float bandValue = fft.getBand(i);
// Color hue and opacity changes based on overall scores
cubes[i].display(scoreLow, scoreMid, scoreHi, bandValue, scoreGlobal*2);
}
// Walls lines, store preceding band value (and next) to connect them together
float previousBandValue = fft.getBand(0);
// Distance between each line point, negative because on the z dimension
float dist = -10;
// Multiply the height by this constant
float heightMult = 4;
// Look through each band
for(int i = 1; i < fft.specSize(); i++)
{
// Value of the frequency band, we multiply the bands farther away so that they are more visible.
float bandValue = fft.getBand(i)*(1 + (i/50));
// Color selection based on sound types
stroke(100+scoreLow, 100+scoreMid, 100+scoreHi, 255-i);
strokeWeight(1 + (scoreGlobal/500));
// lower left line
line(0, height-(previousBandValue*heightMult), dist*(i-1), 0, height-(bandValue*heightMult), dist*i);
line((previousBandValue*heightMult), height, dist*(i-1), (bandValue*heightMult), height, dist*i);
line(0, height-(previousBandValue*heightMult), dist*(i-1), (bandValue*heightMult), height, dist*i);
// upper left line
line(0, (previousBandValue*heightMult), dist*(i-1), 0, (bandValue*heightMult), dist*i);
line((previousBandValue*heightMult), 0, dist*(i-1), (bandValue*heightMult), 0, dist*i);
line(0, (previousBandValue*heightMult), dist*(i-1), (bandValue*heightMult), 0, dist*i);
// lower right line
line(width, height-(previousBandValue*heightMult), dist*(i-1), width, height-(bandValue*heightMult), dist*i);
line(width-(previousBandValue*heightMult), height, dist*(i-1), width-(bandValue*heightMult), height, dist*i);
line(width, height-(previousBandValue*heightMult), dist*(i-1), width-(bandValue*heightMult), height, dist*i);
// lower right line
line(width, (previousBandValue*heightMult), dist*(i-1), width, (bandValue*heightMult), dist*i);
line(width-(previousBandValue*heightMult), 0, dist*(i-1), width-(bandValue*heightMult), 0, dist*i);
line(width, (previousBandValue*heightMult), dist*(i-1), width-(bandValue*heightMult), 0, dist*i);
// Save the band value for the next loop
previousBandValue = bandValue;
}
// Wall rectangles
for(int i = 0; i < nbMurs; i++)
{
float intensity = fft.getBand(i%((int)(fft.specSize()*specHi)));
murs[i].display(scoreLow, scoreMid, scoreHi, intensity, scoreGlobal);
}
}
// Class for cubes floating in space
class Cube {
// Z position of spawn and maximum Z position
float startingZ = -10000;
float maxZ = 1000;
// Position values
float x, y, z;
float rotX, rotY, rotZ;
float sumRotX, sumRotY, sumRotZ;
// Constructor
Cube() {
// Make the cube appear at a random location
x = random(0, width);
y = random(0, height);
z = random(startingZ, maxZ);
// Give the cube a random rotation
rotX = random(0, 1);
rotY = random(0, 1);
rotZ = random(0, 1);
}
void display(float scoreLow, float scoreMid, float scoreHi, float intensity, float scoreGlobal) {
// Color and opacity determined by intensity of the band
color displayColor = color(scoreLow*0.67, scoreMid*0.67, scoreHi*0.67, intensity*5);
fill(displayColor, 255);
// Color lines based on individual intensity of the cube
color strokeColor = color(255, 150-(20*intensity));
stroke(strokeColor);
strokeWeight(0.5 + (scoreGlobal/400));
// Creating a transformation matrix to perform rotations, enlargements
pushMatrix();
// Displacement
translate(x, y, z);
// Calculation of rotation as a function of intensity for the cube
sumRotX += intensity*(rotX/1000);
sumRotY += intensity*(rotY/1000);
sumRotZ += intensity*(rotZ/1000);
// Apply rotation
rotateX(sumRotX);
rotateY(sumRotY);
rotateZ(sumRotZ);
// Creation of the box, variable size depending on the intensity for the cube
box(150+(intensity/2));
// Apply matrix
popMatrix();
// Z displacement
z+= (1+(intensity/5)+(pow((scoreGlobal/150), 2)));
// Replace the box at the back when it is no longer visible
if (z >= maxZ) {
x = random(0, width);
y = random(0, height);
z = startingZ;
}
}
}
// Class to display the lines on the sides
class Mur {
// Min/max Z position
float startingZ = -10000;
float maxZ = 50;
// Position values
float x, y, z;
float sizeX, sizeY;
// Constructor
Mur(float x, float y, float sizeX, float sizeY) {
// Line positioning
this.x = x;
this.y = y;
// Random z depth
this.z = random(startingZ, maxZ);
// Size is determined because the walls on the floors have a different size than those on the sides
this.sizeX = sizeX;
this.sizeY = sizeY;
}
// Display function
void display(float scoreLow, float scoreMid, float scoreHi, float intensity, float scoreGlobal) {
//Color determined by low, medium and high sounds
color displayColor = color(scoreLow*0.67, scoreMid*0.67, scoreHi*0.67, scoreGlobal);
//Make lines disappear in the distance to give an illusion of fog
fill(displayColor, ((scoreGlobal-5)/1000)*(255+(z/25)));
noStroke();
// First band
pushMatrix();
// Displace
translate(x, y, z);
// Scale
if (intensity > 100) intensity = 100;
scale(sizeX*(intensity/100), sizeY*(intensity/100), 20);
// Create a box
box(1);
popMatrix();
// Second band, the one that is still the same size
displayColor = color(scoreLow*0.5, scoreMid*0.5, scoreHi*0.5, scoreGlobal);
fill(displayColor, (scoreGlobal/5000)*(255+(z/25)));
// Transform matrix
pushMatrix();
// Displace
translate(x, y, z);
// Scale
scale(sizeX, sizeY, 10);
// Create box
box(1);
popMatrix();
// Z displacement
z+= (pow((scoreGlobal/150), 2));
if (z >= maxZ) {
z = startingZ;
}
}
}
void keyPressed() {
final int k = keyCode;
// Pause sketch
if (k == 'P' || k == 'p') {
if (looping) {
song.pause();
noLoop();
} else {
song.loop();
loop();
}
}
// Rewind song
if (k == 'R' || k == 'r') {
song.rewind();
song.play();
}
// Quit sketch
if (k == 'Q' || k == 'q') {
exit();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment