分享一个好玩的,音频可视化。一直以为这玩意的数据需要后端给,没想到前端也可以搞。
记录记录!!!
实现思路
首先创建音频的上下文new AudioContext()。然后创建音频节点和分析器来辅助进行音频数据获取。最后根据API要求将数据传入指定的容器中,然后使用canvas进行绘制即可。这里使用Uint8Array作为容器。具体请参考:AnalyserNode - Web API 接口 |MDN的 (mozilla.org)
具体实现
话不多说,直接上代码。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title></title>
</head>
<style>
*{
margin: 0;
padding: 0;
}
canvas{
margin: auto;
background-color: black;
}
</style>
<body>
<canvas id="canvas"></canvas>
<audio src="http://localhost:8081/1.mp3" controls></audio>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var audio = document.querySelector("audio");
function initCvs(){
canvas.width = window.innerWidth;
canvas.height = window.innerHeight / 2;
ctx.fillRect(0,0,canvas.width,canvas.height);
}
initCvs()
let isInit = false;
let array,analyser;
audio.onplay = function(){
if(isInit){
return;
}
audio.crossOrigin = "anonymous";
const audCtx = new AudioContext(); //创建音频上下文
const source = audCtx.createMediaElementSource(audio); //创建音频源节点
analyser = audCtx.createAnalyser();
analyser.fftSize = 512; //必须是2的n次幂
// //创建数组,来接收分析器节点的分析器数据
array = new Uint8Array(analyser.frequencyBinCount);
source.connect(analyser);
analyser.connect(audCtx.destination);
isInit = true;
}
function draw(){
requestAnimationFrame(draw);
const {width,height} = canvas;
ctx.clearRect(0,0,width,height);
if(!isInit) return;
// 当前频率数据复制到传递到array
analyser.getByteFrequencyData(array);
// 将音视频的波形或时域数据复制到array中
// analyser.getByteTimeDomainData(array);
let len = array.length / 2;
const barWidth = width / len / 2;
// 创建线性渐变
var grd = ctx.createLinearGradient(0, 0, 0, 200);
grd.addColorStop(0, "red");
grd.addColorStop(0.3, "#090");
grd.addColorStop(0.7, "green");
grd.addColorStop(1, "blue");
ctx.fillStyle = grd;
for(var i=0;i<len;i++){
const data = array[i];
const x = i*barWidth;
const x1 = x + (width / 2);
const x2 = (width / 2) - x;
const barHeight = (data / 255) * height;
const y = height - barHeight;
ctx.fillRect(x1,y,barWidth-3,barHeight);
ctx.fillRect(x2,y,barWidth-3,barHeight);
}
}
draw()
</script>
</body>
</html>
实现效果
实现样式比较简陋,可以自己根据具体业务来调整。哈哈