一、HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Audio Visualizer</title>
<link rel="stylesheet" type="text/css" href="visualizer.css"/>
<script type="text/javascript" src="visualizer.js"></script>
</head>
<body>
<div id="content">
<input type="file" id="file" accept="audio/*"/>
<canvas id="canvas"></canvas>
<audio id="audio" controls></audio>
</div>
</body>
</html>
二、CSS
/*visualizer.css*/
#file {
position: fixed;
top: 10px;
left: 10px;
z-index: 100;
}
#canvas {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
audio {
position: fixed;
left: 10px;
bottom: 10px;
width: calc(100% - 20px);
}
三、JS
// visualizer.js
window.onload = function () {
var file = document.getElementById("file");
var audio = document.getElementById("audio");
file.onchange = function () {
//part1: 画布
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
//part2: 音频
var files = this.files;//声音文件
audio.src = URL.createObjectURL(files[0]);
audio.load();
//part3: 分析器
var AudCtx = new AudioContext();//音频内容
var src = AudCtx.createMediaElementSource(audio);
var analyser = AudCtx.createAnalyser();
src.connect(analyser);
analyser.connect(AudCtx.destination);
analyser.fftSize = 128;//快速傅里叶变换, 必须为2的N次方
var bufferLength = analyser.frequencyBinCount;// = fftSize * 0.5
//part4: 变量
var barWidth = (WIDTH / bufferLength) - 1;//间隔1px
var barHeight;
var dataArray = new Uint8Array(bufferLength);//8位无符号定长数组
//part5: 动态监听
function renderFrame() {
requestAnimationFrame(renderFrame);//方法renderFrame托管到定时器,无限循环调度,频率<16.6ms/次
context.fillStyle = "#000";//黑色背景
context.fillRect(0, 0, WIDTH, HEIGHT);//画布拓展全屏,动态调整
analyser.getByteFrequencyData(dataArray);//获取当前时刻的音频数据
//part6: 绘画声压条
var x = 0;
for (var i = 0; i < bufferLength; i++) {
var data = dataArray[i];//int,0~255
var percentV = data / 255;//纵向比例
var percentH = i / bufferLength;//横向比例
barHeight = HEIGHT * percentV;
//gbk,0~255
var r = 255 * percentV;//值越大越红
var g = 255 * percentH;//越靠右越绿
var b = 50;
context.fillStyle = "rgb(" + r + "," + g + "," + b + ")";
context.fillRect(x, HEIGHT - barHeight, barWidth, barHeight);
x += barWidth + 1;//间隔1px
}
}
renderFrame();
//part7: 播放声音
audio.play();
};
};