Processing - A Fireworks Show

Author: Thomas Gonzalez



This is my first attempt at creating something in Processing which I started to work with a few days ago.  Originally my goal was to create a fireworks show that resembled what I saw this 4th of July on the Mall in Washington DC, with my wife, two boys, and my sisters family.  I had fond memories of that trip and was hoping to re-create it in some artwork.  I am not sure this qualifies as artwork, but when my three year old came into my office, saw this running and instantly exclaimed "Fireworks Daddy!  Auntie Kim!" I knew I had reached a modicum of success.

With Processing you can very rapidly iterate and experiment with sketches, this version is about my 5th iteration, after experimenting with some Handel (Classical) I settled on Radiohead (my favorite band.)  Each iteration had its own unique appeal, and some things happened quite by accident.  For instance the circles that form and shoot off were a result of tweaking one number by .01.  I continue to be impressed with the power of processing, and I will probably see if something similar can be done in Flash.   

I am also using this work to serve as partial inspiration for what I am doing within Degrafa and with the Flash Player.

You will need the java runtime installed and the appropriate security permissions to view this, also please be patient when it launches as it is loading up a 4mb song.    Click here to view.

 

2 Responses to “Processing - A Fireworks Show”

  1. Anonymous

    Hey Tom,
    that was really cool. I'm re-learning java in college now, but processing is so much more fun and I learn best by looking at other people's source codes. any chance you could let me see a tad so I can throw up some cool things for myself?
    email: testats@gmail.com
    fireworks away


  2. Thomas Gonzalez

    Here is the source code (for an earlier version) but all in one place. You will need your own sound file and have to import the Krister library. I have since moved on to the Minim sound library which is easier to work with:

    /**
    * Fireworks - a Sketch
    * by Tom Gonzalez.
    *
    * Hold down the "SPACE" bar for more fun.
    *
    * Song: Menuet
    * Composer: George Frideric Handel
    *
    */

    import krister.Ess.*;

    ArrayList systems;

    int timer=0;
    int lifeTime=220;
    int lastAdded;
    int systemCount=3;
    float cumFreq=0;
    AudioChannel myChannel;
    AudioFile myFile;
    AudioStream myStream;
    FFT myFFT;

    int bufferSize;
    int bufferDuration;

    void setup() {
    size(640,400);
    frameRate(30);
    colorMode(RGB,255,255,255,100);
    background(0);
    systems=new ArrayList();
    noStroke();
    smooth();

    // start up Ess
    Ess.start(this);

    /*
    myFile=new AudioFile();
    myFile.open("data/Menuet.mp3",0,Ess.READ);
    myStream=new AudioStream(256*1024);
    bufferSize=myStream.buffer.length;
    bufferDuration=1000;
    myStream.sampleRate(myFile.sampleRate);
    myFile.read(myStream);
    myStream.start();
    myFFT=new FFT(512);
    */

    // load "Intro.mp3" into a new Channel
    myChannel=new AudioChannel();
    myChannel.loadSound("Menuet.mp3");
    bufferSize=myChannel.buffer.length;
    bufferDuration=myChannel.ms(bufferSize);
    myFFT=new FFT(512);


    // start the sound looping forever
    myChannel.play(Ess.FOREVER);


    color c=color(int(random(200,255)),int(random(0,55)),int(random(0,55)));
    ParticleSystem ps= new ParticleSystem(int(random(100,300)),new Vector3D(random(0,width),random(0,height),random(0,10)),c,0,1);
    systems.add(ps);
    c=color(int(random(0,55)),int(random(0,55)),int(random(200,255)));
    ps= new ParticleSystem(int(random(100,300)),new Vector3D(random(0,width),random(0,height),random(0,10)),c,25,1);
    systems.add(ps);
    c=color(int(random(0,55)),int(random(200,255)),int(random(0,55)));
    ps= new ParticleSystem(int(random(100,300)),new Vector3D(random(0,width),random(0,height),random(0,10)),c,50,1);
    systems.add(ps);


    }



    void draw() {

    timer++;


    drawSpectrum();


    // int interval=int(random(0,100));

    // if (interval < 4) {
    // color c=color(int(random(0,255)),int(random(0,255)),int(random(0,255)));
    // ParticleSystem ps= new ParticleSystem(int(random(100,300)),new Vector3D(random(0,width),random(0,height),random(0,10)),c,int(random(0,20)));
    // systems.add(ps);
    // }

    //Run current systems
    for (int i=systems.size()-1;i>-1;i--) {
    ParticleSystem ps = (ParticleSystem) systems.get(i);
    if (ps.dead()==true) {
    systems.remove(ps);
    }
    else {
    ps.run();
    }
    }

    }


    void audioStreamWrite(AudioStream theStream) {
    // read the next chunk
    println("here");
    int samplesRead=myFile.read(myStream);
    }

    void drawSpectrum() {

    myFFT.getSpectrum(myChannel);
    float baseFreq=0;
    for (int i=0; i<256; i++) {
    cumFreq+=myFFT.spectrum[i];
    }


    // println(cumFreq);
    if (cumFreq > 12 && systems.size()<6) {
    int dur=timer-lastAdded;
    // println("duration " + dur);
    // int lif=int(150*float(dur/30));
    // println("lifetime " + lif);
    color c=color(int(random(0,255)),int(random(0,255)),int(random(0,255)));
    ParticleSystem ps= new ParticleSystem(300-dur*3,new Vector3D(random(0,width),random(0,height),random(0,10)),c,0,float(42/dur));
    systems.add(ps);
    cumFreq=0;
    lastAdded=timer;
    }
    }


    // A simple Particle class

    class Particle {
    Vector3D loc;
    Vector3D vel;
    Vector3D acc;
    float startRadius=10;
    float r;
    float timer;
    color _c;
    color startColor;
    public int lifeTime=220;
    float clearValue=12;
    int redDec;
    int blueDec;
    int greenDec;

    // One constructor
    Particle(Vector3D a, Vector3D v, Vector3D l, float r_) {
    acc = a.copy();
    vel = v.copy();
    loc = l.copy();
    _c=color(int(random(0,255)),int(random(0,255)),int(random(0,255)));
    startColor=_c;
    startRadius = r_;
    timer = lifeTime;
    }

    // Another constructor (the one we are using here)
    Particle(Vector3D l, color c, int d, float a) {

    lifeTime=d;
    acc = new Vector3D(random(-.07*a,.07*a),random(-0.01*a,0.1*a),0); //This determines how fast it falls or shoots out
    float seed=random(-3,3);
    vel = new Vector3D(cos(seed),sin(seed),1); //This determines what direction it initially spreads in
    loc = l.copy();
    startRadius = 10.0;
    timer = lifeTime;
    _c=c;
    startColor=_c;
    }


    void run() {

    redDec=int((255-red(startColor)) * random(0,timer)/lifeTime);
    blueDec=int((255-blue(startColor)) * random(0,timer)/lifeTime);
    greenDec=int((255-green(startColor)) * random(0,timer)/lifeTime);


    r=startRadius*(timer/lifeTime);

    clearValue=12;
    if ((timer/lifeTime) < random(0.5,1)) { //This creates the flicker as it dies
    _c=color(int(random(0,255)),int(random(0,255)),int(random(0,255)));
    clearValue=30;
    }


    clear();
    update();
    render();

    }

    // Method to update location
    void update() {
    vel.add(acc);
    loc.add(vel);
    timer--;
    }

    //Clears previous render
    void clear() {
    if (keyPressed==true && key==' ') return;
    noStroke();
    fill(0,clearValue);
    ellipse(loc.x,loc.y,r+5,r+5);
    }

    // Method to display
    void render() {

    int incr=int(150 * timer/lifeTime);
    _c=color(red(startColor)+redDec,green(startColor)+greenDec,blue(startColor)+blueDec);
    ellipseMode(CENTER);
    // stroke(_c,timer);
    fill(_c,timer);
    // line(loc.x,loc.y,loc.x+r,loc.y+r);
    // line(loc.x,loc.y+r,loc.x+r,loc.y);
    // line(loc.x,loc.y+r/2,loc.x+r,loc.y+r/2);
    // line(loc.x+r/2,loc.y,loc.x+r/2,loc.y+r);
    ellipse(loc.x,loc.y,r,r);
    }

    // Is the particle still useful?
    boolean dead() {
    if (timer <= 0.0) {
    // println("lifetime was " + lifeTime);
    return true;
    } else {
    return false;
    }
    }
    }


    // A class to describe a group of Particles
    // An ArrayList is used to manage the list of Particles

    class ParticleSystem {

    ArrayList particles; // An arraylist for all the particles
    Vector3D origin; // An origin point for where particles are birthed
    color colorTheme=0;
    public int delayTime=0; // How many draw cycles to wait until displaying
    int runCycle=0;
    int maxLifetime=200; //max lifetime of particle
    float acceleration=1;


    ParticleSystem(int num, Vector3D v, color c, int d, float a) {
    colorTheme=c;
    delayTime=d;
    acceleration=a;
    particles = new ArrayList(); // Initialize the arraylist
    origin = v.copy(); // Store the origin point
    for (int i = 0; i < num; i++) {
    particles.add(new Particle(origin,colorTheme, delayTime+int(random(maxLifetime*.7,maxLifetime)),acceleration)); // Add "num" amount of particles to the arraylist
    }
    }

    void run() {
    // Cycle through the ArrayList backwards b/c we are deleting
    runCycle++;
    if (runCycle < delayTime) return;
    for (int i = particles.size()-1; i >= 0; i--) {
    Particle p = (Particle) particles.get(i);
    p.run();
    if (p.dead()) {
    particles.remove(i);
    }
    }
    }

    void addParticle() {
    particles.add(new Particle(origin,colorTheme, delayTime+int(random(maxLifetime*.7,maxLifetime)),acceleration));
    }

    void addParticle(Particle p) {
    particles.add(p);
    }

    // A method to test if the particle system still has particles
    boolean dead() {
    if (particles.isEmpty()) {
    return true;
    } else {
    return false;
    }
    }

    }



    // Simple Vector3D Class

    public class Vector3D {
    public float x;
    public float y;
    public float z;

    Vector3D(float x_, float y_, float z_) {
    x = x_; y = y_; z = z_;
    }

    Vector3D(float x_, float y_) {
    x = x_; y = y_; z = 0f;
    }

    Vector3D() {
    x = 0f; y = 0f; z = 0f;
    }

    void setX(float x_) {
    x = x_;
    }

    void setY(float y_) {
    y = y_;
    }

    void setZ(float z_) {
    z = z_;
    }

    void setXY(float x_, float y_) {
    x = x_;
    y = y_;
    }

    void setXYZ(float x_, float y_, float z_) {
    x = x_;
    y = y_;
    z = z_;
    }

    void setXYZ(Vector3D v) {
    x = v.x;
    y = v.y;
    z = v.z;
    }
    public float magnitude() {
    return (float) Math.sqrt(x*x + y*y + z*z);
    }

    public Vector3D copy() {
    return new Vector3D(x,y,z);
    }

    public Vector3D copy(Vector3D v) {
    return new Vector3D(v.x, v.y,v.z);
    }

    public void add(Vector3D v) {
    x += v.x;
    y += v.y;
    z += v.z;
    }

    public void sub(Vector3D v) {
    x -= v.x;
    y -= v.y;
    z -= v.z;
    }

    public void mult(float n) {
    x *= n;
    y *= n;
    z *= n;
    }

    public void div(float n) {
    x /= n;
    y /= n;
    z /= n;
    }

    public void normalize() {
    float m = magnitude();
    if (m > 0) {
    div(m);
    }
    }

    public void limit(float max) {
    if (magnitude() > max) {
    normalize();
    mult(max);
    }
    }

    public float heading2D() {
    float angle = (float) Math.atan2(-y, x);
    return -1*angle;
    }

    public Vector3D add(Vector3D v1, Vector3D v2) {
    Vector3D v = new Vector3D(v1.x + v2.x,v1.y + v2.y, v1.z + v2.z);
    return v;
    }

    public Vector3D sub(Vector3D v1, Vector3D v2) {
    Vector3D v = new Vector3D(v1.x - v2.x,v1.y - v2.y,v1.z - v2.z);
    return v;
    }

    public Vector3D div(Vector3D v1, float n) {
    Vector3D v = new Vector3D(v1.x/n,v1.y/n,v1.z/n);
    return v;
    }

    public Vector3D mult(Vector3D v1, float n) {
    Vector3D v = new Vector3D(v1.x*n,v1.y*n,v1.z*n);
    return v;
    }

    public float distance (Vector3D v1, Vector3D v2) {
    float dx = v1.x - v2.x;
    float dy = v1.y - v2.y;
    float dz = v1.z - v2.z;
    return (float) Math.sqrt(dx*dx + dy*dy + dz*dz);
    }

    }


Leave a Reply