Web Audio API: Load, Filter, Gain, Play

For more info, see "Let's make some noise: Web Audio API" presentation made for Kharkiv Front-End Practice: http://flash-ripper.com/web-audio-api Track playing is "Poor Old Dirt Farmer" by Levon Helm

by enbette

HTML

<section>
     <h1>Load Sound, add LowPass Filter &amp; Gain - Web Audio API</h1>
 <span class="info">Loading track...</span> | <a href="#pause" class="bt-mute">Mute</a>

</section>
<section class="controls">
    <input type="range" min="0" max="1" step="0.01" value="1" class="volume-slider" />
    <label>Volume</label>
    <input type="range" min="0" max="1" step="0.01" value="1" class="freq-slider" />
    <label>Filter Frequency</label>
    <input type="range" min="0" max="1" step="0.01" value="0" class="q-slider" />
    <label>Filter Q</label>
    <input type="range" min="1" max="1000" step="0.01" value="0" class="filter-interval" />
    <label>Filter Animation [<a href="#shuffle" class="bt-shuffle">stop</a>]</label>
</section>
<footer>Info: "<a href="http://flash-ripper.com/web-audio-api">Let's make some noise: Web Audio API</a>" presentation for <a href="http://front-end.globallogic.com.ua/">Kharkiv Front-End Practice</a> made by <small><a href="http://facebook.com/rastislavr">Rastislavr</a>. Track is '<a href="https://www.youtube.com/watch?v=cBuJB218UvU">Poor Old Dirt Farmer</a>' by <a href="https://en.wikipedia.org/wiki/Levon_Helm">Levon Helm</a></small>

</footer>

CSS

/** IMPORTANT NOTICE TO WHOM IT MAY CONCERN 
 * CSS IS MINOR ONLY BASED ON THE BRILLIANT
 * https://css-tricks.com/styling-cross-browser-compatible-range-inputs-css/
 **/
 body {
    padding: 0.6em 0.5em 0 0.5em;
    font-size: 1.2em;
}
h1 {
    font-size: 1.7em;
    margin: 0 0 1em 0;
}
section {
    padding: 0.5em;
}
.controls {
    padding: 0em 0 0 3em;
}
footer {
    margin-top: 1em;
    font-size: 0.8em;
}
.volume-slider, .freq-slider, .q-slider {
    background: #fc0
}
label {
    display: inline-block;
    width: 50%;
    padding-left: 0.4em;
    font-size: 1.5em;
    font-weight: normal;
}
input[type=range] {
    -webkit-appearance: none;
    margin: 18px 0;
    width: 40%;
    display: inline-block;
}
input[type=range]:focus {
    outline: none;
}
input[type=range]::-webkit-slider-runnable-track {
    width: 100%;
    height: 16px;
    cursor: pointer;
    animate: 0.2s;
    box-shadow: 1px 1px 1px #ddd, 0px 0px 1px #0d0d0d;
    background: #ccc;
    border-radius: 0;
}
.volume-slider[type=range]::-webkit-slider-runnable-track {
    background: #d31;
}
.freq-slider[type=range]::-webkit-slider-runnable-track {
    background: #fc2;
}
.q-slider[type=range]::-webkit-slider-runnable-track {
    background: #3b1;
}
input[type=range]::-webkit-slider-thumb {
    background-color: #fco;
}
input[type=range]::-webkit-slider-thumb {
    box-shadow: 1px 1px 3px #555, 0px 0px 1px #999;
    border: 1px none #000000;
    height: 27px;
    width: 27px;
    border-radius: 6px;
    background: #fff;
    cursor: pointer;
    -webkit-appearance: none;
    margin-top: -6px;
}
input[type=range]:focus::-webkit-slider-runnable-track {
    background: #367ebd;
}
input[type=range]::-moz-range-track {
    width: 100%;
    height: 8.4px;
    cursor: pointer;
    animate: 0.2s;
    box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
    background: #3071a9;
    border-radius: 1.3px;
    border:...

JavaScript

/* global AudioContext, console */
(function () {
    'use strict';
    // Let's make some noise:
    var audioContext;
    // a gain node & filter node
    var gainNode;
    var filterNode;

    var shuffleTimeoutInterval;
    var params = {
        currentGain: 0.1,
        currentFilterFrequency: 1,
        currentFilterQ: 0,
        filterFrequencyMult: 7000,
        filterQualityMult: 30,
        shuffleTimeoutIntervalDuration: 5000
    };

    try {
        // Fix up for prefixing
        window.AudioContext = window.AudioContext || window.webkitAudioContext;
        audioContext = new AudioContext();
    } catch (e) {
        console.log('Web Audio API is not supported in this browser');
    }

    gainNode = audioContext.createGain();
    filterNode = audioContext.createBiquadFilter();

    // Create and specify parameters for the low-pass filterNode.
    // Low-pass filter. See BiquadFilterNode docs
    filterNode.type = 'lowpass';
    setFrequency(params.currentFilterFrequency);
    setQuality(params.currentFilterQ);

    function shiftParameters() {
        var f = Math.random();
        var q = Math.random();

        setFrequency(f);
        setQuality(q);

        sliderFreq.value = f;
        sliderQ.value = q;
    }

    function loadSomeNoise(url) {
        var request = new XMLHttpRequest();
        request.open('GET', url, true);
        request.responseType = 'arraybuffer';

        // Decode asynchronously
        request.onload = function () {
            audioContext.decodeAudioData(request.response, function (buffer) {
                playSound(buffer);
            }, function (error) {
                console.log(error);
            });
        };
        request.send();

        var info = document.querySelector('.info');

        function playSound(buffer) {
            // create a sound source
            var source = audioContext.createBufferSource();
            //...