JavaScript
语言:
JaveScriptBabelCoffeeScript
确定
var output = document.getElementById('output'),
can = document.getElementById('c'),
ctx = can.getContext('2d'),
player = document.createElement('audio'),
audio = document.createElement('audio'),
context = new AudioContext(),
analyser = context.createAnalyser(),
animationFrame = null,
sensitivity = 8,
changeColor = true,
lastFrequencyData = [];
document.body.appendChild(player);
source = context.createMediaElementSource(audio);
source.connect(analyser);
function stopEvent(event) {
event.preventDefault();
event.stopPropagation();
}
function windowResize() {
can.width = window.innerWidth;
can.height = window.innerHeight;
ctx.fillStyle = randomColor({
alpha: 0.1
});
ctx.strokeStyle = randomColor({
alpha: 0.1
});
}
window.onresize = windowResize;
windowResize();
/**
* Reduce un array al tamaño deseado haciendo la media
* de las partes que quedan.
*
* Ejemplo para tamaño 2:
* [1, 1, 2, 2] => [1, 2]
* [2, 4, 5, 5] => [3, 5]
*/
function reduce(array, size) {
if (size >= array.length) {
return array;
}
var newArray = [],
step = parseInt(array.length / size);
for (var i = 0; i < array.length; i += step) {
var sum = 0;
for (var j = 0; j < step && (i + j) < array.length; j++) {
sum += array[i + j];
}
newArray.push(parseInt(sum / step));
}
return newArray;
}
function calculateCoordinates(frequencyData, colWidth, colHeight) {
return frequencyData.map((value, index) => ({
x: parseInt(index * colWidth, 10),
y: can.height - 10 - value * colHeight
}));
}
function getDelta(frequencyData) {
let delta = 0;
let valueCount = 0;
for (let i = 0; i < frequencyData.length; i++) {
if (frequencyData[i] > sensitivity) {
delta += Math.abs(frequencyData[i] - lastFrequencyData[i]);
valueCount += 1;
}
}
return parseInt(delta / valueCount, 10);
}
function renderFrame(audio, analyser) {
const valueCount = Math.min(can.width / 10, 32);
var colWidth = can.width / valueCount,
colHeight = can.height / 255;
var frequencyData = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(frequencyData);
reducedFrequencyData = reduce(frequencyData, valueCount);
const points = calculateCoordinates(reducedFrequencyData, colWidth, colHeight);
const delta = getDelta(frequencyData);
lastFrequencyData = frequencyData;
if (delta >= sensitivity && changeColor) {
ctx.fillStyle = randomColor({
alpha: 0.1
});
ctx.strokeStyle = randomColor({
alpha: 0.1
});
changeColor = false;
setTimeout(() => {
changeColor = true
}, 1000);
}
ctx.beginPath();
ctx.moveTo(-10, points[0].y);
for (var i = 1; i < points.length - 2; i++) {
const p1 = points[i];
const p2 = points[i + 1];
const x1 = p1.x;
const y1 = p1.y;
const xc = parseInt((p1.x + p2.x) / 2, 10);
const yc = parseInt((p1.y + p2.y) / 2, 10);
ctx.quadraticCurveTo(x1, y1, xc, yc);
}
ctx.quadraticCurveTo(
points[i].x,
points[i].y,
can.width + 10,
points[i + 1].y
);
ctx.lineTo(can.width + 10, can.height);
ctx.lineTo(-10, can.height);
ctx.closePath();
ctx.fill();
ctx.stroke();
if (audio.paused === false) {
animationFrame = requestAnimationFrame(function() {
renderFrame(audio, analyser);
});
}
}
function playAudio(url, name) {
audio.autoplay = player.autoplay = true;
audio.src = player.src = url;
audio.play();
player.play();
$('h1').html(name);
cancelAnimationFrame(animationFrame);
renderFrame(audio, analyser);
}
function dropAudio(event) {
stopEvent(event);
var file = event.originalEvent.dataTransfer.files[0],
url = URL.createObjectURL(file);
playAudio(url, file.name);
}
$(window)
.on('dragover', stopEvent)
.on('dragenter', stopEvent)
.on('drop', dropAudio);