LOADING...

加载过慢请开启缓存(浏览器默认开启)

loading

音频数据可视化

2022/8/30

简单的音频可视化实现

音乐播发器: APlayer
利用 web 自带的AudioContext 里面的 Analyser 分析器 获取实时音频数据

blhx

blhx

效果

核心代码

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);
}
img_show