import ddf.minim.*;
import ddf.minim.analysis.*;
// Declare and construct three objects
Minim minim;
AudioPlayer test;
FFT fft;
// An array named "stars" filled with 2000 elements made with the Star() class
Star[] stars = new Star[2000];
// A global variable "speed" useful to control the speed of stars
float speed;
void setup() {
size(1280, 720);
// Draws all geometry with smooth (anti-aliased) edges at level two
smooth(2);
// Initialize the object
minim = new Minim(this);
// Specify that we want the audio buffers of the AudioPlayer
// to be 1024 samples long because our FFT needs to have
// a power-of-two buffer size and this is a good size.
test = minim.loadFile("final.mp3", 1024);
// Create an FFT object that has a time-domain buffer
// the same size as test's sample buffer
// Note that this needs to be a power of two
// and that it means the size of the spectrum will be half as large.
fft = new FFT(test.bufferSize(), test.sampleRate());
// Play the song
test.play();
// Fill the array with a for loop;
// running 800 times, it creates a new star using the Star() class.
for (int i = 0; i < stars.length; i++) {
stars[i] = new Star();
}
}
void draw() {
// Clean the background in order to present new patterns
background(0);
// Perform a forward FFT on the samples in test's mix buffer,
// which contains the mix of both the left and right channels of the file
fft.forward(test.mix);
// Re-maps the speed according to the amplitude of the requested frequency band 7
speed = map(fft.getBand(7), 0, 100, 0, 300);
// Set center of screen as initial point
translate(width / 2, height / 2);
// Draw each star, running the "update" method to update its position and
// the "show" method to show it on the canvas.
for (int i = 0; i < stars.length; i++) {
stars[i].update();
stars[i].show();
}
}
class Star {
// Create variables to specify the x and y of each star.
float x;
float y;
// Create "z", a variable I'll use in a formula to modify the stars position.
float z;
// An other variable to store the previous value of the z variable.
// (the value of the z variable at the previous frame).
float pz;
// Specify the alpha of patterns.
float alpha;
Star() {
// Place values in the variables
x = random(-width / 2, width / 2);
y = random(-height / 2, height / 2);
// note: the z value can't exceed the width/2 (and height/2) value,
// beacuse I'll use "z" as divisor of the "x" and "y",
// whose values are also between "0" and "width/2".
z = random(width / 2);
// Set the previous position of "z" in the same position of "z",
// which it's like to say that the stars are not moving during the first frame.
pz = z;
}
void update() {
// In the formula to set the new stars coordinates
// I'll divide a value for the "z" value and the outcome will be
// the new x-coordinate and y-coordinate of the star.
// Which means if I decrease the value of "z" (which is a divisor),
// the outcome will be bigger.
// Wich means the more the speed value is bigger, the more the "z" decrease,
// and the more the x and y coordinates increase.
// Note: the "z" value is the first value I updated for the new frame.
z = z - speed;
// when the "z" value equals to 1, I'm sure the star have passed the
// borders of the canvas( probably it's already far away from the borders),
// so i can place it on more time in the canvas, with new x, y and z values.
// Note: in this way I also avoid a potential division by 0.
if (z < 1) {
z = width / 2;
x = random(-width /2, width / 2);
y = random(-height /2, height / 2);
pz = z;
}
}
void show() {
// Re-maps the alpha according to the amplitude of the requested frequency band 7
alpha = map(fft.getBand(7), 0, 100, 80, 255);
fill(255, alpha);
noStroke();
// with theese "map", I get the new star positions
// the division x / z get a number between 0 and a very high number,
// we map this number (proportionally to a range of 0 - 1), inside a range of 0 - width/2.
// In this way we are sure the new coordinates "sx" and "sy" move faster at each frame
// and which they finish their travel outside of the canvas (they finish when "z" is less than a).
float sx = map(x / z, 0, 1, 0, width / 2);
float sy = map(y / z, 0, 1, 0, height / 2);
// I use the z value to increase the star size between a range from 0 to 16.
float r = map(z, 0, width / 2, 5, 0);
ellipse(sx, sy, r, r);
// Here i use the "pz" valute to get the previous position of the stars,
// so I can draw a line from the previous position to the new (current) one.
float px = map(x / pz, 0, 1, 0, width / 2);
float py = map(y / pz, 0, 1, 0, height / 2);
// Placing here this line of code, I'm sure the "pz" value are updated after the
// coordinates are already calculated; in this way the "pz" value is always equals
// to the "z" value of the previous frame.
pz = z;
stroke(255, alpha);
line(px, py, sx, sy);
}
}