前端开发攻略---根据音频节奏实时绘制不断变化的波形图。深入剖析如何通过代码实现音频数据的可视化。
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 * devicePixelRatiocvs.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 } = cvsctx.clearRect(0, 0, width, height)if (!isInit && !isPlay) return// 获取频率数据并绘制波形图analyser.getByteFrequencyData(dateArray)const len = dateArray.length / 2.5ctx.fillStyle = '#266fff'const barWidth = width / len / 2for (let i = 0; i < len; i++) {const data = dateArray[i] // < 256const barHeight = (data / 255) * heightconst x1 = i * barWidth + width / 2const x2 = width / 2 - (i + 1) * barWidthconst y = height - barHeightctx.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 * devicePixelRatiocvs.height = (window.innerHeight / 2) * devicePixelRatio}initCvs()// 初始化,只需要做一次就可以了let isInit = falselet dateArray = nulllet analyser = nullaudioEle.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 } = cvsctx.clearRect(0, 0, width, height)if (!isInit) return// 让分析器节点分析出数据到数组中analyser.getByteFrequencyData(dateArray)const len = dateArray.length / 2.5ctx.fillStyle = '#266fff'const barWidth = width / len / 2for (let i = 0; i < len; i++) {const data = dateArray[i] // < 256const barHeight = (data / 255) * heightconst x1 = i * barWidth + width / 2const x2 = width / 2 - (i + 1) * barWidthconst y = height - barHeightctx.fillRect(x1, y, barWidth - 2, barHeight)ctx.fillRect(x2, y, barWidth - 2, barHeight)}}draw()</script> </html>
相关文章:

前端开发攻略---根据音频节奏实时绘制不断变化的波形图。深入剖析如何通过代码实现音频数据的可视化。
1、演示 2、代码分析 逐行解析 JavaScript 代码块: const audioEle document.querySelector(audio) const cvs document.querySelector(canvas) const ctx cvs.getContext(2d)这几行代码首先获取了 <audio> 和 <canvas> 元素的引用,并使用…...

【计算机毕业设计】基于Java+SSM的实战开发项目150套(附源码+演示视频+LW)
大家好!我是程序猿老A,感谢您阅读本文,欢迎一键三连哦。 🧡今天给大家分享150的Java毕业设计,基于ssm框架,这些项目都经过精心挑选,涵盖了不同的实战主题和用例,可做毕业设计和课程…...

STM32H7的MPU学习和应用示例
STM32H7的MPU学习记录 什么是MPU?MPU的三种内存类型内存映射MPU保护区域以及优先级 MPU的寄存器XN位AP位TEX、C、B、S位SRD 位SIZE 位CTRL 寄存器的各个位 示例总结 什么是MPU? MPU(Memory Protection Unit,内存保护单元…...

964: 数细胞
样例: 解法: 1.遍历矩阵 2.判断矩阵[i][j],若是未标记细胞则遍历相邻所有未标记细胞并标记,且计数 实现:遍历相邻所有未标记细胞 以DFS实现: function dfs(当前状态) {if (终止条件) {}vis[标记当前状…...

流程图步骤条
1.结构 <ul class"stepUl"> <li class"stepLi" v-for"(item, index) in stepList" :key"index"> <div class"top"> <p :class"{active: currentState > item.key}">{{ item.value }}…...
GPT知识库浅析
一、引言 上篇文章《GPT简介及应用》介绍了GPT的应用场景,里面提到GPT bot的基本使用:基于GPT训练好的数据,回答用户的问题。 但在使用过程中,如果用户的问题里面出现最新的术语,就会出现这种提示: 截至我…...
SpringMVC--SpringMVC的视图
目录 1. 总述 2. ThymeleafView视图 3. 转发视图 4. 重定向视图 5. 视图控制器view-controller 1. 总述 在SpringMVC框架中,视图(View)是一个非常重要的概念,它负责将模型数据(Model)展示给用户。简单…...

Datax,hbase与mysql数据相互同步
参考文章:datax mysql 和hbase的 相互导入 目录 0、软件版本说明 1、hbase数据同步至mysql 1.1、hbase数据 1.2、mysql数据 1.3、json脚本(hbase2mysql.json) 1.4、同步成功日志 2、mysql数据同步至hbase 1.1、hbase数据 1.2、mysql…...
ubuntu spdlog 封装成c++类使用
安装及编译方法:ubuntu spdlog 日志安装及使用_spdlog_logger_info-CSDN博客 h文件: #ifndef LOGGING_H #define LOGGING_H#include <iostream> #include <cstring> #include <sstream> #include <string> #include <memor…...

【C语言】——字符串函数的使用与模拟实现(上)
【C语言】——字符串函数 前言一、 s t r l e n strlen strlen 函数1.1、函数功能1.2、函数的使用1.3、函数的模拟实现(1)计数法(2)递归法(3)指针 - 指针 二、 s t r c p y strcpy strcpy 函数2.1、函数功能…...

数据库(1)
目录 1.什么是事务?事务的基本特性ACID? 2.数据库中并发一致性问题? 3.数据的隔离等级? 4.ACID靠什么保证的呢? 5.SQL优化的实践经验? 1.什么是事务?事务的基本特性ACID? 事务指…...
VirtualBox - 与 Win10 虚拟机 与 宿主机 共享文件
原文链接 https://www.cnblogs.com/xy14/p/10427353.html 1. 概述 需要在 宿主机 和 虚拟机 之间交换文件复制粘贴 貌似不太好使 2. 问题 设置了共享文件夹之后, 找不到目录 3. 环境 宿主机 OS Win10开启了 网络发现 略虚拟机 OS Win10开启了 网络发现 略Virtualbox 6 4…...
深入浅出 useEffect:React 函数组件中的副作用处理详解
useEffect 是 React 中的一个钩子函数,用于处理函数组件中的副作用操作,如发送网络请求、订阅消息、手动修改 DOM 等。下面是 useEffect 的用法总结: 基本用法 import React, { useState, useEffect } from react;function Example() {cons…...

《QT实用小工具·十九》回车跳转到不同的编辑框
1、概述 源码放在文章末尾 该项目实现通过回车键让光标从一个编辑框跳转到另一个编辑框,下面是demo演示: 项目部分代码如下: #ifndef WIDGET_H #define WIDGET_H#include <QWidget>namespace Ui { class Widget; }class Widget : p…...

基本的数据类型在16位、32位和64位机上所占的字节大小
1、目前常用的机器都是32位和64位的,但是有时候会考虑16位机。总结一下在三种位数下常用的数据类型所占的字节大小。 数据类型16位(byte)32位(byte)64位(byte)取值范围char111-128 ~ 127unsigned char1110 ~ 255short int / short222-32768~32767unsigned short222…...

关注招聘 关注招聘 关注招聘
🔥关注招聘 🔥关注招聘 🔥关注招聘 🔥开源产品: 1.农业物联网平台开源版 2.充电桩系统开源版 3.GPU池化软件(AI人工智能训练平台/推理平台) 开源版 产品销售: 1.农业物联网平台企业版 2.充电桩系统企业…...

Django框架设计原理
相信大多数的Web开发者对于MVC(Model、View、Controller)设计模式都不陌生,该设计模式已经成为Web框架中一种事实上的标准了,Django框架自然也是一个遵循MVC设计模式的框架。不过从严格意义上讲,Django框架采用了一种更…...

Linux ARM平台开发系列讲解(QEMU篇) 1.2 新添加一个Linux kernel设备树
1. 概述 上一章节我们利用QEMU成功启动了Linux kernel,但是细心的小伙伴就会发现,我们用默认的defconfig是没有找到设备树源文件的,但是又发现kernel启动时候它使用了设备树riscv-virtio,qemu,这是因为qemu用了一个默认的设备树文件,该章节呢我们就把这个默认的设备树文件…...

OSPF动态路由实验(思科)
华为设备参考: 一,技术简介 OSPF(Open Shortest Path First)是一种内部网关协议,主要用于在单一自治系统内决策路由。它是一种基于链路状态的路由协议,通过链路状态路由算法来实现动态路由选择。 OSPF的…...

MyBatis 等类似的 XML 映射文件中,当传入的参数为空字符串时,<if> 标签可能会导致 SQL 语句中的条件判断出现意外结果。
问题 传入的参数为空字符串,但还是根据参数查询了。 原因 在 XML 中使用 标签进行条件判断时,需要明确理解其行为。在 MyBatis 等类似的 XML 映射文件中, 标签通常用于动态拼接 SQL 语句的条件部分。当传入的参数 riskLevel 为空字符串时…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
IGP(Interior Gateway Protocol,内部网关协议)
IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...

uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...