前端开发攻略---根据音频节奏实时绘制不断变化的波形图。深入剖析如何通过代码实现音频数据的可视化。

1、演示

2、代码分析

逐行解析 JavaScript 代码块:

const audioEle = document.querySelector('audio')
const cvs = document.querySelector('canvas')
const ctx = cvs.getContext('2d')

这几行代码首先获取了 <audio> 和 <canvas> 元素的引用,并使用 getContext('2d') 方法获取了 Canvas 2D 上下文对象,以便后续在画布上进行绘图操作。

function initCvs() {
  cvs.width = window.innerWidth * devicePixelRatio
  cvs.height = (window.innerHeight / 2) * devicePixelRatio
}
initCvs()

initCvs 函数用于初始化画布的尺寸。它将画布的宽度设置为窗口宽度的倍数,高度设置为窗口高度的一半,同时乘以设备像素比 devicePixelRatio,以确保在不同设备上显示的效果一致。

let isInit = false
let dateArray = null
let analyser = null

这几行定义了一些状态变量,用于跟踪音频分析器的初始化状态、频率数据数组、分析器对象以及音频播放状态。

audioEle.addEventListener('play', function (e) {
  if (isInit) return
  // 初始化
  const audCtx = new AudioContext() // 创建音频上下文
  const source = audCtx.createMediaElementSource(audioEle) // 创建音频源节点
  analyser = audCtx.createAnalyser()
  analyser.fftSize = 512 // 设置 FFT 大小
  dateArray = new Uint8Array(analyser.frequencyBinCount) // 创建存储频率数据的数组
  source.connect(analyser)
  analyser.connect(audCtx.destination)

  isInit = true
})

这段代码是一个事件监听器,当音频开始播放时触发。在此事件处理程序中:

  • 首先检查是否已经初始化过分析器,如果是,则直接返回。
  • 创建 AudioContext 对象 audCtx,用于处理音频。
  • 使用 createMediaElementSource 方法创建音频源节点 source,将 <audio> 元素作为输入。
  • 创建 AnalyserNode 对象 analyser,用于分析音频频率数据。
  • 设置 AnalyserNode 的 fftSize 属性为 512,表示采样点数。
  • 创建一个 Uint8Array 数组 dateArray 用于存储频率数据。
  • 将音频源节点连接到分析器节点,然后将分析器节点连接到 AudioContext 的目标节点。
  • 最后设置状态变量 isInit 为 true,表示分析器已经初始化且音频正在播放。
function draw() {
  requestAnimationFrame(draw)
  // 清空画布
  const { width, height } = cvs
  ctx.clearRect(0, 0, width, height)
  if (!isInit && !isPlay) return
  // 获取频率数据并绘制波形图
  analyser.getByteFrequencyData(dateArray)
  const len = dateArray.length / 2.5
  ctx.fillStyle = '#266fff'
  const barWidth = width / len / 2
  for (let i = 0; i < len; i++) {
    const data = dateArray[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()

draw 函数用于绘制波形图,通过 requestAnimationFrame 实现动画效果。在函数中:

  • 首先清空画布。
  • 检查分析器是否已初始化并且音频正在播放,如果不是,则直接返回。
  • 使用 analyser.getByteFrequencyData 方法获取频率数据,并存储在 dateArray 中。
  • 计算每个柱状条的宽度和高度,并根据频率数据绘制柱状图形。

3、全部代码

<!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: #ffffff;
        display: flex;
        justify-content: center;
        align-items: center;
        flex-direction: column;
      }
      * {
        margin: 0;
        padding: 0;
      }
      canvas {
        border-bottom: 1px solid #266fff;
      }
    </style>
  </head>
  <body>
    <canvas></canvas>
    <audio src="./123.mp3" controls></audio>
  </body>
  <script>
    const audioEle = document.querySelector('audio')
    const cvs = document.querySelector('canvas')
    const ctx = cvs.getContext('2d')
    // 初始化canvas尺寸
    function initCvs() {
      cvs.width = window.innerWidth * devicePixelRatio
      cvs.height = (window.innerHeight / 2) * devicePixelRatio
    }
    initCvs()

    // 初始化,只需要做一次就可以了
    let isInit = false
    let dateArray = null
    let analyser = null

    audioEle.addEventListener('play', function (e) {
      if (isInit) return
      // 初始化
      const audCtx = new AudioContext() // 创建音频上下文
      const source = audCtx.createMediaElementSource(audioEle) // 创建音频源节点
      // 什么叫音频源节点?节点其实就是音频处理的一个环节。音频可能有很多环节 比如说修音 比如说混响 比如说把音调高调低这些都是处理环节
      // 每一个环节就是一个节点 在这些节点当中有一种叫源节点 表示我们音频数据的来源
      analyser = audCtx.createAnalyser()
      analyser.fftSize = 512 // 2的n次幂。数值越大越细腻
      // 创建数组 用于接收分析器节点的分析数据
      dateArray = new Uint8Array(analyser.frequencyBinCount) // 数组里面的每一项都是一个无符号的8位整数
      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(dateArray)
      const len = dateArray.length / 2.5
      ctx.fillStyle = '#266fff'
      const barWidth = width / len / 2
      for (let i = 0; i < len; i++) {
        const data = dateArray[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>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/536502.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Quartz + SpringBoot 实现分布式定时任务

文章目录 前言一、分布式定时任务解决方案二、Quartz是什么&#xff1f;1.quartz简介2.quartz的优缺点 二、Quartz分布式部署总结 前言 因为应用升级&#xff0c;由之前的单节点微服务应用升级为集群微服务应用&#xff0c;所以之前的定时任务Spring Scheduled不再适用了&…

进程等待waitwaitpid

文章目录 进程等待进程等待的必要性进程等待的方法waitwaitpidstatus 非阻塞等待 进程等待 任何子进程&#xff0c;在退出的情况下&#xff0c;一般必须要被父进程等待 进程等待的必要性 1.父进程通过等待&#xff0c;解决子进程退出的僵尸问题&#xff0c;回收系统资源。 2.…

基于springboot实现知识管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现知识管理系统演示 摘要 随着信息互联网信息的飞速发展&#xff0c;无纸化作业变成了一种趋势&#xff0c;针对这个问题开发一个专门适应师生作业交流形式的网站。本文介绍了知识管理系统的开发全过程。通过分析企业对于知识管理系统的需求&#xff0c;创建了…

012:vue结合纯CSS实现蛇形流程图/步骤条

文章目录 1. 实现效果2. 实现代码 1. 实现效果 2. 实现代码 <template><div class"container"><div v-for"(item, index) in list" class"grid-item"><div class"step">step{{index1}}</div></div&…

大厂Java笔试题之对完全数的处理

题目&#xff1a;完全数&#xff08;Perfect number&#xff09;&#xff0c;又称完美数或完备数&#xff0c;是一些特殊的自然数。 它所有的真因子&#xff08;即除了自身以外的约数&#xff09;的和&#xff08;即因子函数&#xff09;&#xff0c;恰好等于它本身。 例如&…

赋能力量,幸福花开 ——罗湖区懿米阳光开启全职妈妈社工培育计划

最美人间四月天&#xff0c;不负春光不负卿。 四月&#xff0c;迎来了全国社会工作师考试报名的日子&#xff0c;罗湖区全职妈妈妇联与罗湖区阳光妈妈妇联在服务过程中发现&#xff0c;全职妈妈们有获得社会工作师职业资格证的需求&#xff0c;为了更好地针对这一需求&#xf…

YOLOv5原创优化 : loss优化 | 一种新的自适应阈值焦点损失函数loss,增强目标特征,助力红外小目标暴力涨点

💡💡💡问题点:注意到红外小目标图像中目标与背景之间存在极大的不平衡,这使得模型更加关注背景特征而不是目标特征 💡💡💡解决对策:提出了一种新的自适应阈值焦点损失函数,该函数将目标和背景解耦,并利用自适应机制来调整损失权重,迫使模型将更多的注意力分配…

vs调试教程

官网链接&#xff1a; Microsoft Learn&#xff1a;培养开拓职业生涯新机遇的技能通过文档和培训习得技术技能、获得认证并与社区建立联系https://learn.microsoft.com/zh-cn/调试教程 调试器文档 - Visual Studio (Windows) | Microsoft Learn浏览文档&#xff0c;以帮助你使…

大厂Java笔试题之与7有关的数

题目&#xff1a;输出 1到n之间 的与 7 有关数字的个数。 一个数与7有关是指这个数是 7 的倍数&#xff0c;或者是包含 7 的数字&#xff08;如 17 &#xff0c;27 &#xff0c;37 ... 70 &#xff0c;71 &#xff0c;72 &#xff0c;73...&#xff09; 比如输入20&#xff0c;…

Laravel/Lumen 中使用 Echo + Socket.IO-Client 实现网页即时通讯广播

此处以 Lumen 9 框架为例说明如何调试通过 Echo 服务端以及客户端 安装 Redis composer require illuminate/redis&#xff0c;如果安装失败需要根据当前框架版本指定所需 Redis 版本&#xff0c;例如&#xff1a;composer require illuminate/redis "^9.0" Broa…

室外超声波自动气象站设备

TH-CQX10随着科技的进步和气象学的发展&#xff0c;气象监测设备已经从传统的有人值守模式转变为自动化、智能化的无人值守模式。室外超声波自动气象站设备就是这一转变的杰出代表。以下是室外超声波自动气象站设备的原理、应用及其优势&#xff1a; 1、室外超声波自动气象站设…

使用 Axios 处理 AxiosError 的三种常见方法

在使用 Axios 时处理 AxiosError 有几种常见的方法: 使用 try-catch 语句捕获异常: try {const response await axios.get(/api/data);// 处理响应数据 } catch (error) {if (error.response) {// 请求成功但状态码不在 2xx 范围console.log(error.response.data);console.l…

2024比特币减半,Web3的“1995时刻”即将到来

随着比特币减半的到来&#xff0c;加密货币市场迎来了一个关键的转折点。2024年的比特币减半不仅是对比特币供应和挖矿激励的一次重大调整&#xff0c;更是对整个Web3应用领域产生深远影响的事件。 首先&#xff0c;比特币减半的事件本身就为市场带来了一种稀缺性的概念&#…

绝地求生:AUG爆裂弹球黑货箱:街机动漫风格大家会喜欢吗?

大好&#xff0c;我闲游盒&#xff01; 4.10更新后&#xff0c;AUG的新成长型也出来了&#xff0c;更新后我觉得AUG变好用了一点&#xff0c;不知道大家有没有感觉出来&#xff1f; 宝箱概率 本期主角 AUG-爆裂弹球&#xff08;紫色配粉红色&#xff09; 本次的AUG我才升到5级…

蓝桥备赛——组合数、其他技巧

对字符串进行permutations排列组合 from itertools import permutations a abc #对字符串进行permutations排列组合 for i in permutations(a,3):x .join(i)print (x,end ) print (\n------------------------------------) permutations后面的参数&#xff0c;第一个表示…

vue简单使用一(vue的声明)

首先引入vue的js文件&#xff1a; <script src"js/vue.js" type"application/javascript"></script> vue.js文件去vue官网下载即可 html代码 <div class"vuePro"><div> vue的属性信息都得放在这个标签下面哪怕是同级也是…

CSS的属性【all:inherit】有什么奥秘?

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

Scrapy框架内存泄漏问题及解决

说明&#xff1a;仅供学习使用&#xff0c;请勿用于非法用途&#xff0c;若有侵权&#xff0c;请联系博主删除 作者&#xff1a;zhu6201976 一、问题背景及原因 官方文档&#xff1a;Debugging memory leaks — Scrapy 2.11.1 documentation Scrapy是一款功能强大的网络爬虫框…

12个建筑数据分析典型用例

建筑企业面临着众多挑战&#xff0c;包括紧迫的期限、预算限制和复杂的监管要求。 然而&#xff0c;很明显&#xff0c;数据分析可以成为克服这些障碍的重要工具。 建筑行业是数据最密集的市场之一&#xff0c;这就是为什么越来越需要更好的建筑分析和大数据管理。 通过大数据…

【简单讲解下Symfony框架】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…
最新文章