/* 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();
// set sound to play as the source
source.buffer = buffer;
// create the audio graph
// connect source -> filterNode -> gainNode -> destination
source.connect(filterNode);
filterNode.connect(gainNode);
gainNode.connect(audioContext.destination);
setInterlav(params.shuffleTimeoutIntervalDuration);
// play
source.start(0);
info.innerHTML = 'Track: Poor-Old-Dirt-Farmer.mp3';
}
}
// Gain Slider
function setVolume(value) {
gainNode.gain.value = value;
}
// Frequency Slider
function setFrequency(value) {
filterNode.frequency.value = value * params.filterFrequencyMult;
}
// Q Slider
function setQuality(value) {
filterNode.Q.value = value * params.filterQualityMult;
}
function setInterlav(value) {
params.shuffleTimeoutIntervalDuration = value;
clearInterval(shuffleTimeoutInterval);
shuffleTimeoutInterval = setInterval(shiftParameters, params.shuffleTimeoutIntervalDuration);
}
var sliderVolume = document.querySelector('.volume-slider');
var sliderFreq = document.querySelector('.freq-slider');
var sliderQ = document.querySelector('.q-slider');
var sliderInterval = document.querySelector('.filter-interval');
// Set listeners:
sliderVolume.addEventListener('input', function (e) {
setVolume(e.target.value);
});
sliderInterval.addEventListener('input', function (e) {
setInterlav(e.target.value);
});
sliderFreq.addEventListener('input', function (e) {
setFrequency(e.target.value);
});
sliderQ.addEventListener('input', function (e) {
setQuality(e.target.value);
});
document.querySelector('.bt-shuffle').addEventListener('click', function (e) {
clearInterval(shuffleTimeoutInterval);
});
// Mute
document.querySelector('.bt-mute').addEventListener('click', function (e) {
e.preventDefault();
var text = e.target.innerHTML;
if (text === 'Mute') {
params.currentGain = gainNode.gain.value;
setVolume(0);
e.target.innerHTML = 'Un-mute';
} else {
setVolume(params.currentGain);
e.target.innerHTML = 'Mute';
}
});
//
loadSomeNoise('http://flash-ripper.com/toys/fradio/mp3/Poor-Old-Dirt-Farmer.mp3');
})();
<section>
<h1>Load Sound, add LowPass Filter & 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>
/** 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: 0.2px solid #010101;
}
input[type=range]::-moz-range-thumb {
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
border: 1px solid #000000;
height: 36px;
width: 16px;
border-radius: 3px;
background: #ffffff;
cursor: pointer;
}
input[type=range]::-ms-track {
width: 100%;
height: 8.4px;
cursor: pointer;
animate: 0.2s;
background: transparent;
border-color: transparent;
border-width: 16px 0;
color: transparent;
}
input[type=range]::-ms-fill-lower {
background: #2a6495;
border: 0.2px solid #010101;
border-radius: 2.6px;
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
}
input[type=range]::-ms-fill-upper {
background: #3071a9;
border: 0.2px solid #010101;
border-radius: 2.6px;
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
}
input[type=range]::-ms-thumb {
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
border: 1px solid #000000;
height: 36px;
width: 16px;
border-radius: 3px;
background: #ffffff;
cursor: pointer;
}
input[type=range]:focus::-ms-fill-lower {
background: #3071a9;
}
input[type=range]:focus::-ms-fill-upper {
background: #367ebd;
}
External resources loaded into this fiddle: