前端音频可视化Web Audio实现示例详解

目录
  • 背景
  • 实现思路
  • 实现
    • 一、频率图
    • 二、实时频率图
    • 关于请求音频跨域问题解决方案
  • 总结

背景

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

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

实现思路

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

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

  • 创建音频上下文
  • 在音频上下文里创建源 — 例如 <audio>, 振荡器,流
  • 创建效果节点,例如混响、双二阶滤波器、平移、压缩
  • 为音频选择一个目的地,例如你的系统扬声器

连接源到效果器,对目的地进行效果输出

实现

一、频率图

实现第一种类型,首先我们需要通过fetch或xhr来获取一个线上音频的数据,这里以fetch为例;

 //创建一个音频上下文、考虑兼容性问题
 let audioCtx = new (window.AudioContext || window.webkitAudioContext)();
 //添加一个音频源节点
 let source = audioCtx.createBufferSource();
//res.arrayBuffer是将数据转换为arrayBuffer格式
 fetch(url).then((res) => res.arrayBuffer()).then((res) => {
        //decodeAudioData是将arrayBuffer格式数据转换为audioBuffer
        audioCtx.decodeAudioData(res).then((buffer) => {
          // decodeAudioData解码完成后,返回一个AudioBuffer对象
          // 绘制音频波形图
          draw(buffer);
          // 连接音频源
          source.buffer = buffer;
          source.connect(audioCtx.destination);
          // 音频数据处理完毕
        });
      });

需要明白的是,source.connect(audioCtx.destination)是将音频源节点链接到输出设备,否则会没声音哦。那么现在有了数据、我们只需要通过canvas将数据画出来即可。

function draw(buffer) {
  // buffer.numberOfChannels返回音频的通道数量,1即为单声道,2代表双声道。这里我们只取一条通道的数据
  let data = [];
  let originData = buffer.getChannelData(0);
  // 存储所有的正数据
  let positives = [];
  // 存储所有的负数据
  let negatives = [];
  // 先每隔50条数据取1条
  for (let i = 0; i < originData.length; i += 50) {
    data.push(originData[i]);
  }
  // 再从data中每10条取一个最大值一个最小值
  for (let j = 0, len = data.length / 10; j < len; j++) {
    let temp = data.slice(j * 10, (j + 1) * 10);
    positives.push(Math.max(...temp));
    negatives.push(Math.min(...temp));
  }
  if (canvas.getContext) {
    let ctx = canvas.getContext("2d");
    canvas.width = positives.length;
    let x = 0;
    let y = 75;
    let offset = 0;
    var grd = ctx.createLinearGradient(0, 0, canvas.width, 0);
    // 为渐变添加颜色,参数1表示渐变开始和结束之间的位置(用0至1的占比表示),参数2位颜色
    grd.addColorStop(0, "yellow");
    grd.addColorStop(0.5, "red");
    grd.addColorStop(1, "blue");
    ctx.fillStyle = grd;
    ctx.beginPath();
    ctx.moveTo(x, y);
    // 横坐标上方绘制正数据,下方绘制负数据
    // 先从左往右绘制正数据
    // x + 0.5是为了解决canvas 1像素线条模糊的问题
    for (let k = 0; k < positives.length; k++) {
      ctx.lineTo(x + k + 0.5, y - 50 * positives[k]);
    }
    // 再从右往左绘制负数据
    for (let l = negatives.length - 1; l >= 0; l--) {
      ctx.lineTo(x + l + 0.5, y + 50 * Math.abs(negatives[l]));
    }
    // 填充图形
    ctx.fill();
  }
}

[参考文章](Web Audio - 绘制音频图谱

二、实时频率图

实现第二种类型,获取实时频率,用到的API与第一种有区别,但流程一直,都是通过一个音频源节点通过连接达到效果。只不过在连接的中间加入了一个分析器analyser,在将分析器连接到输出设备。

    const audio =document.querySelector('audio')
    //解决音频跨域问题
    audio.crossOrigin ='anonymous'
    const  canvas =document.querySelector('canvas')
    const ctx=canvas.getContext("2d")
        function initCanvas(){
        //初始化canvas
            canvas.width=window.innerWidth*devicePixelRatio
            canvas.height=(window.innerHeight/2)*devicePixelRatio
        }
        initCanvas()
        //将数据提出来
        let dataArray,analyser;
        //播放事件
        audio.onplay=function(){
            //创建一个音频上下文实例
            const audioCtx=new (window.AudioContext || window.webkitAudioContext)();
            //添加一个音频源节点
            const source=audioCtx.createMediaElementSource(audio);
            //分析器节点
             analyser=audioCtx.createAnalyser();
            //fft分析器  越大 分析越细
            analyser.fftSize=512
            //创建一个无符号字节的数组
             dataArray=new Uint8Array( analyser.frequencyBinCount);
            //音频源节点 链接分析器
            source.connect(analyser)
            //分析器链接输出设备
            analyser.connect(audioCtx.destination,)
        }

那么接下来至于怎么把数据画出来,就凭大家的想法了。

            requestAnimationFrame(draw)
            //
            const {width ,height}=canvas;
            ctx.clearRect(0,0,width,height)
            //分析器节点分析出的数据到数组中
            ctx.fillStyle='#78C5F7'
           ctx.lineWidth = 2;
            ctx.beginPath();
            //getByteFrequencyData,分析当前音频源的数据 装到dataArray数组中去
            //获取实时数据
            analyser.getByteFrequencyData(dataArray)
            // console.log(dataArray);
            const len =dataArray.length;
            const barWidth=width/len;
            let x=0;
            for(let i=0;i<len;i++){
                const data=dataArray[i];
                const barHeight=data/255*height;
                // ctx.fillRect(x,y,barWidth,height)
        let v = dataArray[i] / 128.0;
        let y = v * height/2;
        if(i === 0) {
            ctx.moveTo(x, y);
        } else {
            ctx.lineTo(x, y);
        }
        x += barWidth;
            }
            // ctx.lineTo(canvas.width, canvas.height/2);
            ctx.stroke();
        }
        draw();

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

给获取的audio DOM添加一条属性即可

   audio.crossOrigin ='anonymous'

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

总结

虽然现在已经有很多开源的对于音频相关的库,但如果真正的想要去了解,去学习音频相关的东西。必须要去深入学习相关的Web Audio API,当然这里只是用了其中两种的方法去实现Web Audio去实现可视化,算是一个基础入门,对于文中的createBufferSource,createMediaElementSource,createAnalyser,AudioContext,arrayBuffer,decodeAudioData等等相关的API都需要去了解,在可视化方面,还有多种多样的方式去绘制动画,如WebGL。对音频的处理也不只是在可视化方面。

以上就是前端音频可视化Web Audio实现示例详解的详细内容,更多关于Web Audio音频可视化的资料请关注我们其它相关文章!

(0)

相关推荐

  • 前端框架ECharts dataset对数据可视化的高级管理

    目录 dataset 管理数据 dataset 管理数据 提供一份数据. 声明一个 X 轴,类目轴(category).默认情况下,类目轴对应到声明多个 bar 系列,默认情况下,每个系列会自动对应到 dataset 的每一列. option = { legend: {}, tooltip: {}, dataset: { // source: [ ['product', '2015', '2016', '2017'], ['Matcha Latte', 43.3, 85.8, 93.7], ['

  • JS前端可视化GraphQL使用详解

    目录 正文 什么是 GraphQL? 什么是 GraphiQL? 开始 结尾 正文 了解事物幕后的运作方式往往有好处,但并非总是如此. 因为不必使事情过于复杂.而可视化图形界面在处理这么一个场景中,是首当其冲的. 在本文中,我将带你了解如何使用 GraphiQL 来辅助 GraphQL 的开发. 什么是 GraphQL? 在我们谈论 GraphiQL 之前,让我们先谈谈 GraphQL. GraphQL 是一种用于应用程序编程接口 (API) 的开源数据查询和操作语言,也是一种使用现有数据完成查

  • 前端可视化搭建组件值与联动实现详解

    目录 正文 组件值 值联动 描述联动行为 用持续联动实现一次性联动 总结 正文 组件联动是指几个组件相互关联.也就是当一个组件状态变化时,其他组件可以响应. 组件联动是多对多关系的,且目的分为一次性与持续性: 多对多关系:即一个组件可以同时被多个组件联动:多个组件可以同时联动一个组件. 一次性与持续性:一次性事件可以被覆盖,持续性事件会同时生效,且要考虑叠加关系. 一定程度上,持续性事件可以覆盖一次性事件的场景:组件永远响应最后一个过来的事件即可. 接下来我们引入 组件值 与 值联动 两个概念,

  • JS前端可视化canvas动画原理及其推导实现

    目录 前言 动画的本质 动画的实现 动画的推导 小结 前言 到目前为止我们的 fabric.js 雏形已经有了,麻雀虽小五脏俱全,我们不仅能够在画布上自由的添加物体,同时还实现了点选和框选,并且能够对它们做一些变换,不过只有变换这个操作还不够灵活,要是能够让物体动起来就好了,于是就引入了这个章节的主题:动画,以及动画最核心的一个问题,如何保证在不同的电脑上达到同样的动画效果?然后说干就干,立马开撸. 虽然我写的是系列文章,但每个章节单独食用是木问题的,所以,请放心大胆的看

  • Python开发自定义Web框架的示例详解

    目录 开发自定义Web框架 1.开发Web服务器主体程序 2.开发Web框架主体程序 3.使用模板来展示响应内容 4.开发框架的路由列表功能 5.采用装饰器的方式添加路由 6.电影列表页面的开发案例 开发自定义Web框架 接收web服务器的动态资源请求,给web服务器提供处理动态资源请求的服务.根据请求资源路径的后缀名进行判断: 如果请求资源路径的后缀名是.html则是动态资源请求, 让web框架程序进行处理. 否则是静态资源请求,让web服务器程序进行处理. 1.开发Web服务器主体程序 1.

  • TypeScript前端上传文件到MinIO示例详解

    目录 什么是MinIO? 本地Docker部署测试服务器 上传的API TypeScript实现 1. XMLHttpRequest 2. Fetch API 3. Axios 从后端获取临时上传链接 上传文件 踩过的坑 1. presignedPutObject方式上传提交的方法必须得是PUT 2. 直接发送File即可 3. 使用Axios上传的时候,需要自己把Content-Type填写成为file.type 示例代码 什么是MinIO? MinIO 是一款高性能.分布式的对象存储系统.

  • JavaScript进阶之前端文件上传和下载示例详解

    目录 文件下载 1.通过a标签点击直接下载 2.open或location.href 3.Blob和Base64 文件上传 文件上传思路 File文件 上传单个文件-客户端 上传文件-服务端 多文件上传-客户端 大文件上传-客户端 大文件上传-服务端 文件下载 1.通过a标签点击直接下载 <a href="https:xxx.xlsx" rel="external nofollow" download="test">下载文件</

  • js前端上传文件缩略图技巧示例详解

    目录 引言 文件对象简介 Blob File FileReader FormData 文件对象之间的关系 缩略图的实现 总结 引言 通常情况下,前端提交给服务器的数据格式为JSON格式,但很多时候用户想上传自己的头像.视频等,这些非文本数据的时候,就不能直接以JSON格式上传到后端了. 当我们要获取用户上传的文件,可以使用input表单项,将type属性值设置为“file”. <form action=""> <input type="file"

  • .NET Core 2.0迁移小技巧之web.config 配置文件示例详解

    前言 相信大家应该都知道.NET Core现在不再支持原来的web.config配置文件了,取而代之的是json或xml配置文件.官方推荐的项目配置方式是使用appsettings.json配置文件,这对现有一些重度使用web.cofig配置的项目迁移可能是不可接受的. 但是好消息是,我们是可以直接在.NET Core 2.0项目种利用上现有的web.config的.本文将详细介绍.NET Core 2.0迁移之web.config 配置文件的相关内容,下面话不多说了,来一起看看详细的介绍吧.

  • Java Web关键字填空示例详解

    (1)在TestServletRequest中将名为“param”,值为“HelloWorld”的信息存入request范围内,并利用请求转发方式转向另一个Servlet——AnotherServlet.在AnotherServlet中,从request范围内读取param的值.请将下面的Servlet程序补充完整. 文件名:TestServletRequest.java @WebServlet("/TestServletRequest") public class TestServl

  • 微前端之Web组件自定义元素示例详解

    目录 我们知道的 Web组件使用 名称规范 组件传参数并可以写模板包括js和css Shadow Dom 影子节点 类中的构造函数和钩子函数 getter/setter属性和属性反射 扩展原生 HTML 我们知道的 第一:我们熟知的HTML标签有 a, p, div, section, ul, li, h2, article, head, body, strong, video, audio 等等 第二:我们知道,a标签是链接,p标签是段落,div是块级,h2是字体,strong 是粗体,vid

  • SSM框架整合JSP中集成easyui前端ui项目开发示例详解

    目录 前言 EasyUI下载与配置 页面美化 运行结果 总结与问题 前言 前端的UI框架很多,如bootsrap.layui.easyui等,这些框架提供了大量控件供开发人员使用,我们无需花费太大的精力,使得我们的页面具有专业标准,使用起来也很简单.所有的前端框架使用方式基本上大同小异,以下使用easyui作为UI框架做一演示,个人认为easyui提供的控件比较好看. EasyUI下载与配置 使用EasyUI,必须下载其js包,下载官网地址:https://www.jeasyui.cn/ 下载j

  • Python制作可视化报表的示例详解

    大家好,我是小F- 在数据展示中使用图表来分享自己的见解,是个非常常见的方法. 这也是Tableau.Power BI这类商业智能仪表盘持续流行的原因之一,这些工具为数据提供了精美的图形解释. 当然了,这些工具也有着不少缺点,比如不够灵活,无法让你自己创建设计. 当你对图表展示要求定制化时,编程也许就比较适合你,比如Echarts.D3.js. 今天小F给大家介绍一个用Python制作可视化报表的案例,主要是使用到Dash+Tailwindcss. 可视化报表效果如下,水果销售情况一览~ Das

  • Python+pyaudio实现音频控制示例详解

    简介 PyAudio是一个跨平台的音频处理工具包,使用该工具包可以在Python程序中播放和录制音频,也可以产生wav文件等 安装 pip install PyAudio 注意:使用该命令安装时可能会报错,报错内容如下: 针对该问题,我们使用whl文件进行安装,首先在网址下面找到以下文件并下载,根据自己的python版本及计算机系统下载相应文件即可. 下载完成后,切换到文件所在目录,使用如下命令安装即可 pip3 install PyAudio-0.2.11-cp38-cp38-win_amd6

随机推荐