(function() {
var onDOMContentLoaded = function() {
window.AudioContext = window.AudioContext || window.webkitAudioContext;
try {
// Create the instance of AudioContext
var context = new AudioContext();
} catch (error) {
window.alert(error.message + ' : Please use Chrome or Safari.');
return;
}
// for createObjectURL
window.URL = window.URL || window.webkitURL;
// for HTMLAudioElement
var audio = null;
// for legacy browsers
context.createGain = context.createGain || context.createGainNode;
// Create the instance of GainNode
var gain = context.createGain();
// Create the instance of BiquadFilterNode
var filter = context.createBiquadFilter();
// for playback rate (HTMLAudioElement)
var playbackRate = document.getElementById('range-playback-rate').valueAsNumber;
// Start / Pause Button
var controlButton = document.getElementById('button-control-audio');
// for drawing sound wave (spectrum)
// Create the instance of AnalyserNode
var analyser = context.createAnalyser();
analyser.minDecibels = -100;
analyser.maxDecibels = 0;
var canvas = document.querySelector('canvas');
var canvasContext = canvas.getContext('2d');
var timerid = null;
// Frequency resolution
var fsDivN = context.sampleRate / analyser.fftSize;
// This value is the number of samples during 500 Hz
var n500Hz = Math.floor(500 / fsDivN);
var drawWave = function() {
var width = canvas.width;
var height = canvas.height;
var paddingTop = 20;
var paddingBottom = 20;
var paddingLeft = 30;
var paddingRight = 30;
var innerWidth = width - paddingLeft - paddingRight;
var innerHeight = height - paddingTop - paddingBottom;
var innerBottom = height - paddingBottom;
var range = analyser.maxDecibels - analyser.minDecibels; // 70 dB
// Get data for drawing spectrum (dB)
var spectrums = new Float32Array(analyser.frequencyBinCount / 4);
analyser.getFloatFrequencyData(spectrums);
// Clear previous data
canvasContext.clearRect(0, 0, width, height);
// Draw spectrum (dB)
canvasContext.beginPath();
for (var i = 0, len = spectrums.length; i < len; i++) {
var x = Math.floor((i / len) * innerWidth) + paddingLeft;
var y = Math.floor(-1 * ((spectrums[i] - analyser.maxDecibels) / range) * innerHeight) + paddingTop;
if (i === 0) {
canvasContext.moveTo(x, y);
} else {
canvasContext.lineTo(x, y);
}
if (i % n500Hz === 0) {
var text = (500 * (i / n500Hz)) + ' Hz'; // index -> frequency
// Draw grid (X)
canvasContext.fillStyle = 'rgba(255, 0, 0, 1.0)';
canvasContext.fillRect(x, paddingTop, 1, innerHeight);
// Draw text (X)
canvasContext.fillStyle = 'rgba(255, 255, 255, 1.0)';
canvasContext.font = '12px "Times New Roman"';
canvasContext.fillText(text, (x - (canvasContext.measureText(text).width / 2)), (height - 3));
}
}
canvasContext.strokeStyle = 'rgba(0, 0, 255, 1.0)';
canvasContext.lineWidth = 2;
canvasContext.lineCap = 'round';
canvasContext.lineJoin = 'miter';
canvasContext.stroke();
// Draw grid and text (Y)
for (var i = analyser.minDecibels; i <= analyser.maxDecibels; i += 10) {
var gy = Math.floor(-1 * ((i - analyser.maxDecibels) / range) * innerHeight) + paddingTop;
// Draw grid (Y)
canvasContext.fillStyle = 'rgba(255, 0, 0, 1.0)';
canvasContext.fillRect(paddingLeft, gy, innerWidth, 1);
// Draw text (Y)
canvasContext.fillStyle = 'rgba(255, 255, 255, 1.0)';
canvasContext.font = '12px "Times New Roman"';
canvasContext.fillText((i + ' dB'), 3, gy);
}
timerid = window.setTimeout(drawWave, 20);
};
var setupAudio = function(src) {
// Clear previous audio
if (audio instanceof HTMLAudioElement) {
audio.pause();
audio = null;
controlButton.innerHTML = '<span class="icon-start"></span>';
}
// Create the instance of HTMLAudioElement
audio = new Audio(src);
audio.setAttribute('controls', true);
// Create the instance of MediaElementAudioSourceNode after "onloadstart" event
audio.addEventListener('loadstart', function(event) {
window.alert('Start "' + event.type + '" !!');
// Create the instance of MediaElementAudioSourceNode
var source = context.createMediaElementSource(audio);
// MediaElementAudioSourceNode (Input) -> BiquadFilterNode (Filter) -> GainNode (Volume) -> AnalyserNode (Visualization) -> AudioDestinationNode (Output)
source.connect(filter)
filter.connect(gain);
gain.connect(analyser);
analyser.connect(context.destination);
}, false);
audio.addEventListener('play', function() {
drawWave();
controlButton.innerHTML = '<span class="icon-pause"></span>';
}, false);
audio.addEventListener('pause', function() {
if (timerid !== null) {
window.clearTimeout(timerid);
timerid = null;
}
controlButton.innerHTML = '<span class="icon-start"></span>';
}, false);
};
/*
* Event Listener
*/
// File Uploader
document.querySelector('[type="file"] + button').addEventListener(EventWrapper.CLICK, function() {
document.querySelector('[type="file"]').click();
}, false);
document.querySelector('[type="file"]').addEventListener('change', function(event) {
var uploader = this;
var progressArea = document.getElementById('progress-file-upload-audio');
// Get the instance of File (extends Blob)
var file = event.target.files[0];
if (!(file instanceof File)) {
window.alert('Please upload file.');
} else if (file.type.indexOf('audio') === -1) {
window.alert('Please upload audio file.');
} else {
setupAudio(window.URL.createObjectURL(file));
}
}, false);
// Start or Pause audio
controlButton.addEventListener(EventWrapper.CLICK, function() {
if (audio instanceof HTMLAudioElement) {
if (audio.paused) {
audio.playbackRate = playbackRate;
audio.play();
} else {
audio.pause();
}
}
}, false);
// Control Volume
document.getElementById('range-volume').addEventListener('input', function() {
var min = gain.gain.minValue || 0;
var max = gain.gain.maxValue || 1;
if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) {
gain.gain.value = this.valueAsNumber;
document.getElementById('output-volume').textContent = this.value;
}
}, false);
// Control playBackRate
document.getElementById('range-playback-rate').addEventListener('input', function() {
if (audio instanceof HTMLAudioElement) {
audio.playbackRate = playbackRate = this.valueAsNumber;
} else {
playbackRate = this.valueAsNumber;
}
document.getElementById('output-playback-rate').textContent = this.value;
}, false);
// Select type
document.getElementById('select-filter').addEventListener('change', function() {
filter.type = (typeof filter.type === 'string') ? this.value : this.selectedIndex;
}, false);
// Control frequency
document.getElementById('range-frequency').addEventListener('input', function() {
var min = filter.frequency.minValue || 10;
var max = filter.frequency.maxValue || (context.sampleRate / 2);
if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) {
filter.frequency.value = this.valueAsNumber;
document.getElementById('output-frequency').textContent = this.value;
}
}, false);
// Control detune
document.getElementById('range-detune').addEventListener('input', function() {
var min = filter.detune.minValue || -4800;
var max = filter.detune.maxValue || 4800;
if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) {
filter.detune.value = this.valueAsNumber;
document.getElementById('output-detune').textContent = this.value;
}
}, false);
// Control Q
document.getElementById('range-Q').addEventListener('input', function() {
var min = filter.Q.minValue || 0.0001;
var max = filter.Q.maxValue || 1000;
if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) {
filter.Q.value = this.valueAsNumber;
document.getElementById('output-Q').textContent = this.value;
}
}, false);
// Control gain
document.getElementById('range-filter-gain').addEventListener('input', function() {
var min = filter.gain.minValue || -40;
var max = filter.gain.maxValue || 40;
if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) {
filter.gain.value = this.valueAsNumber;
document.getElementById('output-filter-gain').textContent = this.value;
}
}, false);
};
if ((document.readyState === 'interactive') || (document.readyState === 'complete')) {
onDOMContentLoaded();
} else {
document.addEventListener('DOMContentLoaded', onDOMContentLoaded, true);
}
})();
function EventWrapper(){
}
(function(){
var click = '';
var start = '';
var move = '';
var end = '';
// Touch Panel ?
if (/iPhone|iPad|iPod|Android/.test(navigator.userAgent)) {
click = 'click';
start = 'touchstart';
move = 'touchmove';
end = 'touchend';
} else {
click = 'click';
start = 'mousedown';
move = 'mousemove';
end = 'mouseup';
}
EventWrapper.CLICK = click;
EventWrapper.START = start;
EventWrapper.MOVE = move;
EventWrapper.END = end;
})();