CODE //
EXPLORE //
CREATE //
01
Building Musical Worlds

Audio - Visual

Next we'll be adding visual & sound indication to our organisms actions. First let's create a quick visual object.

Visuals

Head to the file VISUAL.js. There, let's update the constructor function to look like this, setting a size, position and alpha transparency as its properties:


function Visual(x, y, size) {
    this.settings = visualSettings;
    this.position = new Point(x, y);
    this.size = size * scale;
    this.alpha = 100;
}
        

Now, we'll write the update method to grow and fade the visual every frame, until it fades out entirely, at which point we remove it.


Visual.prototype.update = function() {
    // fade and grow //
    this.alpha -= 2;
    this.size++;

    // destroy when fully faded //
    if (this.alpha <= 0) {
        removeFromArray(this, visuals);
    }
};
        

Next, we'll update the draw method to create a pair of expanding circles:


Visual.prototype.draw = function() {
    // drawing style //
    ctx.globalAlpha = this.alpha/100;
    ctx.strokeStyle = this.settings.color;
    ctx.lineWidth = 4 * scale;

    // draw circles //
    ctx.beginPath();
    ctx.arc(this.position.x, this.position.y, this.size, 0, TAU);
    ctx.moveTo(this.position.x + this.size + 10, this.position.y);
    ctx.arc(this.position.x, this.position.y, this.size + 10, 0, TAU);
    ctx.stroke();
    ctx.globalAlpha = 1;
};
        

Then we need to head to MAIN.js and create an instance generate function for visual, and call update & draw on its instances, as we've done before.

Within the draw function add:


for (var i=0; i<visuals.length; i++) {
    visuals[i].draw();
}
        

Within the update function add:


for (var i=0; i<visuals.length; i++) {
    visuals[i].update();
}
        

Update the function generateVisual to look like:


function generateVisual(position, size) {
    visuals.push( new Visual(position.x, position.y, size * 2) );
}
        

Finally, go to the file ORGANISM1.js and update its kill method to include the function generateVisual:


Organism1.prototype.kill = function() {
    removeFromArray(this, org1);
    var area = 30 * scale;
    generateSpores(this.size * 0.72, this.position.x - area, this.position.y - area, this.position.x + area, this.position.y + area);
    generateVisual(this.position, this.size);
};
        

And do the same in the file SPORES.js:


Spore.prototype.kill = function() {
    removeFromArray(this, spores);
    generateVisual(this.position, this.size);
};
        

Now we have some nice visual indications of the organism events. Let's look at adding sounds.

Audio

We'll be using the Web Audio API which is a powerful & exciting way that we can use javascript to create and control sound right in the browser. We'll be creating a function which randomly picks a note from a musical scale and plays it whenever an organism breeds or dies.

The Web Audio API works by letting us create a source of sound, connecting it to effects, and connecting those effects to our output, which in most cases is our computer speakers/headphones.

Go to the file AUDIO.js. You'll see that some of the basic setup has been done for you, and there's an existing function called setupAudio which sets up our musical scale and overall sound volume, as well as a delay effect which we'll be connecting our random sounds to. We're using a javascript library called tone.js to make things a little simpler.

Below that function let's modify the function called soundEvent. We're going to create an oscillator as our sound source, which allows us to generate a tone at a given pitch. We'll be connecting that to a gain node, which allows us to effect the volume. We connect the gain to our output.


function soundEvent() {

    // create the oscillator and gain nodes //
    var osc = new Tone.Oscillator();
    var amp = audioCtx.createGain();

    // connect the oscillator and gain to the output //
    osc.connect(amp);
    amp.connect(output);
}
        

We want to add a few more things to this function, first we want to randomise a note, we can use tombola to select a note from our scale at random. We also want to start the sound and schedule some changes. First we want to quickly ramp up the volume (attack), then after a while smoothly reduce it again (release). Controlling the volume of a sound like this is described as its envelope. Then we want to stop the sound once its played its duration.


function soundEvent(volume, attack, release) {

    // configure the time and pitch //
    var now = audioCtx.currentTime;
    var duration = attack + release;
    var note = tune.note(tombola.item(whiteNotes));

    // create the oscillator and gain nodes //
    var osc = new Tone.Oscillator(note);
    var amp = audioCtx.createGain();

    // connect the oscillator and gain to the output //
    osc.connect(amp);
    amp.connect(output);

    // setup the volume envelope //
    amp.gain.setValueAtTime(0, now);
    amp.gain.linearRampToValueAtTime(volume, now + attack);
    amp.gain.exponentialRampToValueAtTime(0.00001, now + duration);

    // start the sound and schedule it stopping //
    osc.start();
    osc.stop('+' + (duration * 1.1));
}
        

Finally, go to the file ORGANISM1.js and update its kill method to include the function soundEvent:


Organism1.prototype.kill = function() {
    removeFromArray(this, org1);
    var area = 30 * scale;
    generateSpores(this.size * 0.72, this.position.x - area, this.position.y - area, this.position.x + area, this.position.y + area);
    generateVisual(this.position, this.size);
    soundEvent(this.settings.soundVolume, this.settings.soundAttack, this.settings.soundRelease);
};
        

And do the same in the file SPORES.js:


Spore.prototype.kill = function() {
    removeFromArray(this, spores);
    generateVisual(this.position, this.size);
    soundEvent(this.settings.soundVolume, this.settings.soundAttack, this.settings.soundRelease);
};
        

Open up index.html in the browser one more time and take a listen. Note that Firefox currently doesn't handle envelopes well, so Chrome or Safari recommended.

Further Learning:
developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API
tonejs.github.io/
Back
Up Next: Conclusion