(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 the instance of AudioBufferSourceNode
var source = null;
// for legacy browsers
context.createGain = context.createGain || context.createGainNode;
// Create the instance of GainNode
var gain = context.createGain();
var drawAudio = function(canvas, data, sampleRate) {
var canvasContext = canvas.getContext('2d');
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 middle = (innerHeight / 2) + paddingTop;
// Sampling period
var period = 1 / sampleRate;
// This value is the number of samples during 50 msec
var n50msec = Math.floor(50 * Math.pow(10, -3) * sampleRate);
// This value is the number of samples during 60 sec
var n60sec = Math.floor(60 * sampleRate);
// Clear previous data
canvasContext.clearRect(0, 0, width, height);
// Draw audio wave
canvasContext.beginPath();
for (var i = 0, len = data.length; i < len; i++) {
// 50 msec ?
if ((i % n50msec) === 0) {
var x = Math.floor((i / len) * innerWidth) + paddingLeft;
var y = Math.floor(((1 - data[i]) / 2) * innerHeight) + paddingTop;
if (i === 0) {
canvasContext.moveTo(x, y);
} else {
canvasContext.lineTo(x, y);
}
}
// 60 sec ?
if ((i % n60sec) === 0) {
var sec = i * period; // index -> time
var text = Math.floor(sec) + ' sec';
// 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 = '16px "Times New Roman"';
canvasContext.fillText(text, (x - (canvasContext.measureText(text).width / 2)), (height - 3));
}
}
canvasContext.strokeStyle = 'rgba(0, 0, 255, 1.0)';
canvasContext.lineWidth = 0.5;
canvasContext.lineCap = 'round';
canvasContext.lineJoin = 'miter';
canvasContext.stroke();
// Draw grid (Y)
canvasContext.fillStyle = 'rgba(255, 0, 0, 1.0)';
canvasContext.fillRect(paddingLeft, middle, innerWidth, 1);
canvasContext.fillRect(paddingLeft, paddingTop, innerWidth, 1);
canvasContext.fillRect(paddingLeft, innerBottom, innerWidth, 1);
// Draw text (Y)
canvasContext.fillStyle = 'rgba(255, 255, 255, 1.0)';
canvasContext.font = '16px "Times New Roman"';
canvasContext.fillText(' 1.00', 3, paddingTop);
canvasContext.fillText(' 0.00', 3, middle);
canvasContext.fillText('-1.00', 3, innerBottom);
};
// Trigger 'ended' event
var trigger = function() {
var event = document.createEvent('Event');
event.initEvent('ended', true, true);
if (source instanceof AudioBufferSourceNode) {
source.dispatchEvent(event);
}
};
// This funciton is executed after getting ArrayBuffer of audio data
var startAudio = function(arrayBuffer) {
// The 2nd argument for decodeAudioData
var successCallback = function(audioBuffer) {
// The 1st argument (audioBuffer) is the instance of AudioBuffer
// Get audio binary data for drawing wave
var channelLs = new Float32Array(audioBuffer.length);
var channelRs = new Float32Array(audioBuffer.length);
console.log('numberOfChannels : ' + audioBuffer.numberOfChannels);
// Stereo ?
if (audioBuffer.numberOfChannels > 1) {
// Stereo
channelLs.set(audioBuffer.getChannelData(0));
channelRs.set(audioBuffer.getChannelData(1));
drawAudio(document.querySelectorAll('canvas')[0], channelLs, audioBuffer.sampleRate);
drawAudio(document.querySelectorAll('canvas')[1], channelRs, audioBuffer.sampleRate);
} else if (audioBuffer.numberOfChannels > 0) {
// Monaural
channelLs.set(audioBuffer.getChannelData(0));
drawAudio(document.querySelectorAll('canvas')[0], channelLs, audioBuffer.sampleRate);
} else {
window.alert('The number of channels is invalid.');
return;
}
// If there is previous AudioBufferSourceNode, program stops previous audio
if ((source instanceof AudioBufferSourceNode) && (source.buffer instanceof AudioBuffer)) {
// Execute onended event handler
trigger();
source = null;
}
// Create the instance of AudioBufferSourceNode
source = context.createBufferSource();
// for legacy browsers
source.start = source.start || source.noteOn;
source.stop = source.stop || source.noteOff;
// Set the instance of AudioBuffer
source.buffer = audioBuffer;
// Set parameters
source.playbackRate.value = document.getElementById('range-playback-rate').valueAsNumber;
source.loop = document.querySelector('[type="checkbox"]').checked;
// AudioBufferSourceNode (Input) -> GainNode (Volume) -> AudioDestinationNode (Output)
source.connect(gain);
gain.connect(context.destination);
// Start audio
source.start(0);
// Set Callback
source.onended = function(event) {
// Remove event handler
source.onended = null;
document.onkeydown = null;
// Stop audio
source.stop(0);
console.log('STOP by "on' + event.type + '" event handler !!');
// Audio is not started !!
// It is necessary to create the instance of AudioBufferSourceNode again
// Cannot replay
// source.start(0);
};
// Stop audio
document.onkeydown = function(event) {
// Space ?
if (event.keyCode !== 32) {
return;
}
// Execute onended event handler
trigger();
return false;
};
};
// The 3rd argument for decodeAudioData
var errorCallback = function(error) {
if (error instanceof Error) {
window.alert(error.message);
} else {
window.alert('Error : "decodeAudioData" method.');
}
};
// Create the instance of AudioBuffer (Asynchronously)
context.decodeAudioData(arrayBuffer, successCallback, errorCallback);
};
/*
* File Uploader
*/
document.getElementById('file-upload-audio').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 {
// Create the instance of FileReader
var reader = new FileReader();
reader.onprogress = function(event) {
if (event.lengthComputable && (event.total > 0)) {
var rate = Math.floor((event.loaded / event.total) * 100);
progressArea.textContent = rate + ' %';
}
};
reader.onerror = function() {
window.alert('FileReader Error : Error code is ' + reader.error.code);
uploader.value = '';
};
// Success read
reader.onload = function() {
var arrayBuffer = reader.result; // Get ArrayBuffer
startAudio(arrayBuffer);
uploader.value = '';
progressArea.textContent = file.name;
};
// Read the instance of File
reader.readAsArrayBuffer(file);
}
}, 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 (source instanceof AudioBufferSourceNode) {
var min = source.playbackRate.minValue || 0;
var max = source.playbackRate.maxValue || 1024;
if ((this.valueAsNumber >= min) && (this.valueAsNumber <= max)) {
source.playbackRate.value = this.valueAsNumber;
}
}
document.getElementById('output-playback-rate').textContent = this.value;
}, false);
// Toggle loop
document.querySelector('[type="checkbox"]').addEventListener(EventWrapper.CLICK, function() {
if (source instanceof AudioBufferSourceNode) {
source.loop = this.checked;
}
}, 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;
})();