记录实现音频可视化

实现音频可视化

这里主要使用了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"

相关推荐
梦帮科技34 分钟前
GRAVIS v4.0:基于Web的极速套利架构设计与实时数据流实现
前端·人工智能·rust·自动化·区块链·智能合约·数字货币
爱勇宝1 小时前
办公资料反复修改、补传、交接混乱,我做了个桌面工具来解决这件事
前端·后端·程序员
微信开发api-视频号协议2 小时前
企业微信外部群开发自动化实践过程
java·前端·微信·自动化·企业微信·ipad
甲维斯2 小时前
Fable5:20美金的顶级设计师!
前端·人工智能
kyriewen2 小时前
我同时用了 Claude Code、Cursor 和 Codex,说说三个工具的真实差距——2026 年选错工具比不用 AI 更浪费时间
前端·ai编程·claude
Jackson__3 小时前
为了拯救我的腰椎和颈椎,我做了款浏览器插件!
前端·javascript·开源
闲猫3 小时前
Python FastAPI + SQLAlchemy 入门教程:从零搭建你的第一个 Web 应用
前端·python·fastapi
林小帅3 小时前
NestJS v11 + Prisma v7 ESM 迁移配置解析
前端·javascript·后端
IT_陈寒3 小时前
React的setState竟然不是立刻生效的,害我调试半天
前端·人工智能·后端
简简单单就是我_hehe3 小时前
前端埋点日志解决方案:完整 User-Agent 解析工具实现,爬虫识别、设备品牌、操作系统、浏览器版本全解析(附完整源码)
前端·爬虫