top of page

import ddf.minim.analysis.*;

import ddf.minim.*;

 

// Declare and construct three objects

Minim minim;

AudioPlayer test;

FFT fft;

 

// Declare an object to define the particles' movement

FlowField flowfield;

 

// Declare an array to store particles

ArrayList<Particle> particles;

 

boolean debug = false;

 

void setup() {

  size(1280, 720);

  background(0);

 

  // 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()); 

 

  // Loop the song

  test.loop();

 

  // Initialize and call the object

  flowfield = new FlowField(10);

  flowfield.update();

 

  // Initialize the array and store the particles

  particles = new ArrayList<Particle>();

  for (int i = 0; i < 10000; i++) {

    PVector start = new PVector(random(width), random(height));

    particles.add(new Particle(start, random(2, 8)));

  }

}

 

void draw() {

  // 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);

 

  // Call the update function of the movement

  flowfield.update();

 

  if (debug) flowfield.display();

 

  // Draw and munipulate the movement of particles

  for (Particle p : particles) {

    p.follow(flowfield);

    p.run();

  }

}

// Declare a particle class

public class Particle {

  // Set position, velocity and acceleration 

  PVector pos;

  PVector vel;

  PVector acc;

 

  // Declare an variable to store the previous position

  PVector previousPos;

 

  // Declare an variable as maximum speed

  float maxSpeed;

 

  // Store the information of the particles

  Particle(PVector start, float maxspeed) {

    maxSpeed = maxspeed;

    pos = start;

    vel = new PVector(0, 0);

    acc = new PVector(0, 0);

    previousPos = pos.copy();

  }

 

  // Define the movment of the particles

  void run() {

    update();

    edges();

    show();

  }

 

  // The update movement of the particles

  void update() {

    pos.add(vel);

    vel.limit(maxSpeed);

    vel.add(acc);

    acc.mult(0);

  }

 

  // Apply the force to the particles

  void applyForce(PVector force) {

    acc.add(force);

  }

 

  // Display the particles

  void show() {

    // Re-maps the variables according to the amplitude of the requested frequency band 7

    float alpha = map(fft.getBand(7), 0, 100, 30, 255);

 

    stroke(255, alpha);

    strokeWeight(0.5);

    line(pos.x, pos.y, previousPos.x, previousPos.y);

    //point(pos.x, pos.y);

    updatePreviousPos();

  }

 

  // Set the edges of the particles avoiding overflow

  void edges() {

    if (pos.x > width) {

      pos.x = 0;

      updatePreviousPos();

    }

    if (pos.x < 0) {

      pos.x = width;    

      updatePreviousPos();

    }

    if (pos.y > height) {

      pos.y = 0;

      updatePreviousPos();

    }

    if (pos.y < 0) {

      pos.y = height;

      updatePreviousPos();

    }

  }

 

  // Update previous position of the articles

  void updatePreviousPos() {

    this.previousPos.x = pos.x;

    this.previousPos.y = pos.y;

  }

 

  // The position of each particle

  void follow(FlowField flowfield) {

    int x = floor(pos.x / flowfield.scl);

    int y = floor(pos.y / flowfield.scl);

    int index = x + y * flowfield.cols;

 

    PVector force = flowfield.vectors[index];

    applyForce(force);

  }

}

// Declare a movement class

public class FlowField {

  // Declare an array as position of movement

  PVector[] vectors;

  int cols, rows;

 

  // Declare variables to control the increment of movement

  float inc = 0.1;

  float zoff = 0;

 

  // Declare the unit of the grid

  int scl;

 

  // Process each unit and place them in the array

  FlowField(int res) {

    scl = res;

    cols = floor(width / res) + 1;

    rows = floor(height / res) + 1;

    vectors = new PVector[cols * rows];

  }

 

  // Update the movement 

  void update() {

    float xoff = 0;

    for (int y = 0; y < rows; y++) { 

      float yoff = 0;

      for (int x = 0; x < cols; x++) {

        float angle = noise(xoff, yoff, zoff) * TWO_PI * 4;

 

        PVector v = PVector.fromAngle(angle);

        v.setMag(1);

        int index = x + y * cols;

        vectors[index] = v;

 

        xoff += inc;

      }

      yoff += inc;

    }

    zoff += 0.004;

  }

 

  // Display the particles 

  void display() {

    for (int y = 0; y < rows; y++) { 

      for (int x = 0; x < cols; x++) {

        int index = x + y * cols;

        PVector v = vectors[index];

 

        float alpha = map(fft.getBand(7), 0, 100, 0, 255);

 

        stroke(255, alpha);

        strokeWeight(0.1);

        pushMatrix();

        translate(x * scl, y * scl);

        rotate(v.heading());

        line(0, 0, scl, 0);

        popMatrix();

      }

    }

  }

}

bottom of page