drxlr.com

The Story

When the redesign of the Drexler site began in late 2016 the goal was to create a system that could be evolved through temporary concepts. As soon as the dust settled we began both building upon and simplifying the previous iteration.

drxlr.com

Once the adjustments were in place for this recent update we found that the front page needed closure. A suggestion to include a message below the work feed lead to the last-minute idea of featuring an interactive piece at the very end. Recalling chats about having a "trademark sound" on the site, it felt appropriate to give it a playful treatment with an audio component.

The Setup

1. Tone.js

First an instance of a Tone.js instrument is created.

  var instrument = new Tone.Synth();
var synthJSON = {
    "oscillator": {
        "type": "fatcustom",
        "partials" : [0.2, 1, 0.3, 0.5, .1],
        "spread" : 30,
        "count" : 3
    },
    "envelope": {
        "attack": 0.001,
        "decay": 1.6,
        "sustain": 0,
        "release": 1.6
    }
};
instrument.set(synthJSON);
var effect1, effect2;
var effect1 = new Tone.Distortion();
effect1JSON = {
    "distortion" : 0.8,
    "wet": 0.4
};
effect1.set(effect1JSON);
var effect2 = new Tone.PingPongDelay();
effect2JSON = {
    "delayTime" : "8n", 
    "feedback" : 0.2,
    "wet": 0.5
};
effect2.set(effect2JSON);
instrument.connect(effect1);
effect1.connect(effect2);
effect2.connect(Tone.Master);
function deep_dispose() {
    if(effect1 != undefined && effect1 != null) {
        effect1.dispose();
        effect1 = null;
    }
    if(effect2 != undefined && effect2 != null) {
        effect2.dispose();
        effect2 = null;
    }
    if(effect3 != undefined && effect3 != null) {
        effect3.dispose();
        effect3 = null;
    }
    if(instrument != undefined && instrument != null) {
        instrument.dispose();
        instrument = null;
    }
}
instrument.connect(Tone.Master);
instrument.set('volume', -10);

note: this tool helped generate the synth settings

2. Interactivity

In this case we are working with an SVG that has a fixed number of shapes that are set to trigger different notes and colors when hovered as defined here.

  var colors = ['#f9ed32','#43f3b7','#f29bc1','#ce9f59','#f29bc1','#ce9f59','#f9ed32','#43f3b7'];
var notes = ['A3', 'D3', 'C#3', 'D4', 'A3', 'E3', 'A4', 'C#4'];

The bounds of each shape gets compared with the cursor/touch coordinates to turn the element into a strumable synthesizer rendered completely in the browser.

  $(document).on('mousemove touchstart touchmove', function(e) {
    if(e.type=='mousemove'){
        x = e.pageX;
        y = e.pageY;
    } else{
        x = e.originalEvent.touches[0].pageX; 
        y = e.originalEvent.touches[0].pageY; 
    }
    note.each(function(){
        $this = $(this)[0];
        l = $this.getBoundingClientRect().left;
        t = $this.getBoundingClientRect().top;
        w = $this.getBoundingClientRect().width;
        h = $this.getBoundingClientRect().height;
        if(x >= l && x <= (l + w) && y >= t && y <= (t + h)){
            trigger($(this)[0]);
        }
    })
});

note: getBoundingClientRect is needed for SVG elements

The following function fires when the cursor/touch position intersect with a shape's bounds with the note and color determined by the position of the element.

  function trigger(key){
    $key = $(key);
    n = $key.index();
    instrument.triggerAttackRelease(notes[n], .6);
    body.css('background',colors[n]);
    $key.addClass('trigger');
    setTimeout(function(){$(key).removeClass('trigger');},400);
}

The Result

A fun easter egg for our visitors to happen upon for a real-time, nostalgic audio/visual experience. See it in action by going to drxlr.com and scrolling to the bottom of the front page.

The Takeaway

The full potential of Tone.js is far beyond this demo. Some additional logic was needed to account for browsers without Web Audio API support, but performance/sound is impressively consistent.


2,894 2 14