简单的音频可视化实现
音乐播发器: APlayer
利用 web 自带的AudioContext 里面的 Analyser 分析器 获取实时音频数据
效果
核心代码
function renderFrame() {
//每次绘制时查看当前选择的绘图类型
let currentType = selectTypeDom.options[selectTypeDom.selectedIndex].value;
renderFrameIsRunning = true;
// 每次绘制都记得要重新设置一下画布高宽
canvasElement.width = canvasContainer.clientWidth;
canvasElement.height = canvasContainer.clientHeight;
//每次绘制时清空画布
canvasCtx.clearRect(0,0, canvasElement.width, canvasElement.height);
switch(currentType){
case "spectrum":{
// 更新频率数据
// analyser.getByteFrequencyData(dataArray);
analyser.getByteFrequencyData(dataArray);
// console.log(dataArray);
// 计算一下每个柱子的宽度
let barWidth = canvasElement.width/bufferLength;
let HEIGHT = canvasElement.height;
//bufferLength表示柱形图中矩形的个数
for (let i = 0, x = 0; i < bufferLength; i++) {
// 根据频率映射一个矩形高度
// barHeight = dataArray[i];
// barHeight = (dataArray[i] + 140) * 2; // getFloatFrequencyData() 方法获取的单位为分贝 在数字音频数据中 这些值都是负值 这里加个140进行转换好绘制频谱
barHeight = dataArray[i] * 1.5;
// 根据每个矩形高度映射一个背景色
// let r = barHeight + 25 * (i / bufferLength);
// let g = 250 * (i / bufferLength);
// let b = 100;
// 每个矩形的颜色为了更好的控制过渡这里使用hsl
// H取值最大225 根据高度比例来获取对应的颜色值
let h =225 - barHeight/HEIGHT * 225;
let s = '100%';
let l = '50%';
// 绘制一个矩形,并填充背景色
// canvasCtx.fillStyle = "rgb(" + r + "," + g + "," + b + ")";
canvasCtx.fillStyle = "hsl(" + h + "," + s + "," + l + ")";
canvasCtx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight);
x += barWidth + 1;
}
}
break;
case "circle":{
// 圆形的音频波形
// 设置线条颜色
let oW = canvasElement.width;
let oH = canvasElement.height;
let color1 = canvasCtx.createLinearGradient(oW/2, oH/2-10, oW/2, oH/2-150);
color1.addColorStop(0, "#1E90FF");
color1.addColorStop(.25, "#FF7F50");
color1.addColorStop(.5, "#8A2BE2");
color1.addColorStop(.75, "#4169E1");
color1.addColorStop(1, "#00FFFF");
let color2 = canvasCtx.createLinearGradient(0,0,oW,oH);
color2.addColorStop(0,"#1E90FF");
color2.addColorStop(.25,"#FFD700");
color2.addColorStop(.5, "#8A2BE2");
color2.addColorStop(.75, "#4169E1");
color2.addColorStop(1, "#FF0000");
let outPut= new Uint8Array(360);
let du = 2; //角度
let r = 200; //半径
let w = 2; //宽
analyser.getByteFrequencyData(outPut);
for(let i=0; i<360;i++)
{
let value = ((outPut[i]))/10;
canvasCtx.beginPath();
canvasCtx.lineWidth =w;
let Rv1 = (r - value);
let Rv2 = (r + value);
let currentRadius = Math.PI/180*(i*du);
canvasCtx.moveTo((Math.sin((i*du)/180*Math.PI)*Rv1 + oW/2), -Math.cos((i*du)/180*Math.PI)*Rv1 + oH/2);
canvasCtx.lineTo((Math.sin(currentRadius)*Rv2 + oW/2), - Math.cos(currentRadius)*Rv2+ oH/2);
canvasCtx.strokeStyle= color1; // 线条颜色
canvasCtx.stroke();
}
// 设置字体样式
canvasCtx.font = "20px 华文楷体";
canvasCtx.fillStyle = color2;
canvasCtx.textAlign = "center";
canvasCtx.textBaseline = "middle";
// 绘制文字
canvasCtx.fillText(ap.list.audios[ap.list.index].name, oW/2, oH/2);
}
break;
default:
break;
}
if(!isPlay){
renderFrameIsRunning = false;
return;
}
requestAnimationFrame(renderFrame);
}