记录实现音频可视化

实现音频可视化

这里主要使用了web audio api和canvas来实现的(当然也可以使用svg,因为canvas会有失帧的情况,svg的写法如果有大佬会的话,可以滴滴我一下)

背景

最近听音乐的时候,看到各种动效,突然好奇这些音频数据是如何获取并展示出来的,于是花了几天功夫去研究相关的内容,这里只是给大家一些代码实例,具体要看懂、看明白,还是建议大家大家结合相关api来阅读这篇文章。

参考资料地址:Web Audio API - Web API 接口参考 | MDN (mozilla.org)

实现思路

首先画肯定是用canvas去画,关于音频的相关数据(如频率、波形)如何去获取,需要去获取相关audio的DOM 或通过请求处理去拿到相关的音频数据,然后通过Web Audio API 提供相关的方法来实现。(当然还要考虑要音频请求跨域的问题,留在最后。)

一个简单而典型的 web audio 流程如下(取自MDN):

xml 复制代码
1.创建音频上下文<br>
2.在音频上下文里创建源 --- 例如 <audio>, 振荡器,流<br>
3.创建效果节点,例如混响、双二阶滤波器、平移、压缩<br>
4.为音频选择一个目的地,例如你的系统扬声器<br>
5.连接源到效果器,对目的地进行效果输出<br>

上代码

xml 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      body {
        background-color: #000;
      }
      div {
        width: 100%;
        border-top: 1px solid #fff;
        padding-top: 50px;
        display: flex;
        justify-content: center;
      }
    </style>
  </head>
  <body>
    <canvas></canvas>
    <div>
      <audio src="./1.mp3" controls></audio>
    </div>
    <script>
      // 获取音频组件
      const audioEle = document.querySelector("audio");
      // 获取canvas元素
      const cvs = document.querySelector("canvas");
      // 创建canvas上下文
      const ctx = cvs.getContext("2d");

      // 初始化canvas的尺寸
      function initCvs() {
        cvs.width = window.innerWidth;
        cvs.height = window.innerHeight / 2;
      }
      initCvs();

      // 音频的步骤 音频源 ==》分析器 ===》输出设备

      //是否初始化
      let isInit = false;
      let dataArray, analyser;
      audioEle.onplay = function () {
        if (isInit) return;
        // 初始化
        const audCtx = new AudioContext(); //创建一个音频上下文
        const source = audCtx.createMediaElementSource(audioEle); //创建音频源节点
        analyser = audCtx.createAnalyser(); //拿到分析器节点
        analyser.fftSize = 512; // 时域图变换的窗口大小(越大越细腻)默认2048
        // 创建一个数组,接受分析器分析回来的数据
        dataArray = new Uint8Array(analyser.frequencyBinCount); // 数组每一项都是一个整数 接收数组的长度,因为快速傅里叶变换是对称的,所以除以2
        source.connect(analyser); // 将音频源节点链接到输出设备,否则会没声音哦。
        analyser.connect(audCtx.destination); // 把分析器节点了解到输出设备
        isInit = true;
      };

      // 绘制,把分析出来的波形绘制到canvas上
      function draw() {
        requestAnimationFrame(draw);
        // 清空画布
        const { width, height } = cvs;
        ctx.clearRect(0, 0, width, height);
        // 先判断音频组件有没有初始化
        if (!isInit) return;
        // 让分析器节点分析出数据到数组中
        analyser.getByteFrequencyData(dataArray);
        const len = dataArray.length / 2.5;
        const barWidth = width / len / 2; // 每一个的宽度
        ctx.fillStyle = "#78C5F7";
        for (let i = 0; i < len; i++) {
          const data = dataArray[i]; // <256
          const barHeight = (data / 255) * height; // 每一个的高度
          const x1 = i * barWidth + width / 2;
          const x2 = width / 2 - (i + 1) * barWidth;
          const y = height - barHeight;
          ctx.fillRect(x1, y, barWidth - 2, barHeight);
          ctx.fillRect(x2, y, barWidth - 2, barHeight);
        }
      }
      draw();
    </script>
  </body>
</html>

我这里只用了简单的柱状图,还有什么其他的奇思妙想,至于怎么把数据画出来,就凭大家的想法了。

关于请求音频跨域问题解决方案

1 .因为我这里是简单的html,音频文件也在同一个文件夹但是如果直接用本地路径打开本地文件是会报跨域的问题,所以我这里是使用Open with Live Server就可以了

2 .给获取的audio DOM添加一条属性即可 audio.crossOrigin ='anonymous'

或者直接在 aduio标签中 加入 crossorigin="anonymous"

相关推荐
m0_593758101 分钟前
firefox 136.0.4版本离线安装MarkDown插件
前端·firefox
掘金一周4 分钟前
金石焕新程 >> 瓜分万元现金大奖征文活动即将回归 | 掘金一周 4.3
前端·人工智能·后端
三翼鸟数字化技术团队22 分钟前
Vue自定义指令最佳实践教程
前端·vue.js
Jasmin Tin Wei1 小时前
蓝桥杯 web 学海无涯(axios、ecahrts)版本二
前端·蓝桥杯
圈圈编码1 小时前
Spring Task 定时任务
java·前端·spring
转转技术团队1 小时前
代码变更暗藏危机?代码影响范围分析为你保驾护航
前端·javascript·node.js
Mintopia1 小时前
Node.js高级实战:自定义流与Pipeline的高效数据处理 ——从字母生成器到文件管道的深度解析
前端·javascript·node.js
Mintopia1 小时前
Three.js深度解析:InstancedBufferGeometry实现动态星空特效 ——高效渲染十万粒子的底层奥秘
前端·javascript·three.js
北凉温华1 小时前
强大的 Vue 标签输入组件:基于 Element Plus 的 ElTagInput 详解
前端
原生高钙1 小时前
LLM大模型对话框实践:大文件的分片上传
前端