当前位置: 首页 > news >正文

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

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 代码块&#xff1a; const audioEle document.querySelector(audio) const cvs document.querySelector(canvas) const ctx cvs.getContext(2d)这几行代码首先获取了 <audio> 和 <canvas> 元素的引用&#xff0c;并使用…...

【计算机毕业设计】基于Java+SSM的实战开发项目150套(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f9e1;今天给大家分享150的Java毕业设计&#xff0c;基于ssm框架&#xff0c;这些项目都经过精心挑选&#xff0c;涵盖了不同的实战主题和用例&#xff0c;可做毕业设计和课程…...

STM32H7的MPU学习和应用示例

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

964: 数细胞

样例&#xff1a; 解法&#xff1a; 1.遍历矩阵 2.判断矩阵[i][j]&#xff0c;若是未标记细胞则遍历相邻所有未标记细胞并标记&#xff0c;且计数 实现&#xff1a;遍历相邻所有未标记细胞 以DFS实现&#xff1a; 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的应用场景&#xff0c;里面提到GPT bot的基本使用&#xff1a;基于GPT训练好的数据&#xff0c;回答用户的问题。 但在使用过程中&#xff0c;如果用户的问题里面出现最新的术语&#xff0c;就会出现这种提示&#xff1a; 截至我…...

SpringMVC--SpringMVC的视图

目录 1. 总述 2. ThymeleafView视图 3. 转发视图 4. 重定向视图 5. 视图控制器view-controller 1. 总述 在SpringMVC框架中&#xff0c;视图&#xff08;View&#xff09;是一个非常重要的概念&#xff0c;它负责将模型数据&#xff08;Model&#xff09;展示给用户。简单…...

Datax,hbase与mysql数据相互同步

参考文章&#xff1a;datax mysql 和hbase的 相互导入 目录 0、软件版本说明 1、hbase数据同步至mysql 1.1、hbase数据 1.2、mysql数据 1.3、json脚本&#xff08;hbase2mysql.json&#xff09; 1.4、同步成功日志 2、mysql数据同步至hbase 1.1、hbase数据 1.2、mysql…...

ubuntu spdlog 封装成c++类使用

安装及编译方法&#xff1a;ubuntu spdlog 日志安装及使用_spdlog_logger_info-CSDN博客 h文件&#xff1a; #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、函数的模拟实现&#xff08;1&#xff09;计数法&#xff08;2&#xff09;递归法&#xff08;3&#xff09;指针 - 指针 二、 s t r c p y strcpy strcpy 函数2.1、函数功能…...

数据库(1)

目录 1.什么是事务&#xff1f;事务的基本特性ACID&#xff1f; 2.数据库中并发一致性问题&#xff1f; 3.数据的隔离等级&#xff1f; 4.ACID靠什么保证的呢&#xff1f; 5.SQL优化的实践经验&#xff1f; 1.什么是事务&#xff1f;事务的基本特性ACID&#xff1f; 事务指…...

VirtualBox - 与 Win10 虚拟机 与 宿主机 共享文件

原文链接 https://www.cnblogs.com/xy14/p/10427353.html 1. 概述 需要在 宿主机 和 虚拟机 之间交换文件复制粘贴 貌似不太好使 2. 问题 设置了共享文件夹之后, 找不到目录 3. 环境 宿主机 OS Win10开启了 网络发现 略虚拟机 OS Win10开启了 网络发现 略Virtualbox 6 4…...

深入浅出 useEffect:React 函数组件中的副作用处理详解

useEffect 是 React 中的一个钩子函数&#xff0c;用于处理函数组件中的副作用操作&#xff0c;如发送网络请求、订阅消息、手动修改 DOM 等。下面是 useEffect 的用法总结&#xff1a; 基本用法 import React, { useState, useEffect } from react;function Example() {cons…...

《QT实用小工具·十九》回车跳转到不同的编辑框

1、概述 源码放在文章末尾 该项目实现通过回车键让光标从一个编辑框跳转到另一个编辑框&#xff0c;下面是demo演示&#xff1a; 项目部分代码如下&#xff1a; #ifndef WIDGET_H #define WIDGET_H#include <QWidget>namespace Ui { class Widget; }class Widget : p…...

基本的数据类型在16位、32位和64位机上所占的字节大小

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

关注招聘 关注招聘 关注招聘

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

Django框架设计原理

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

Linux ARM平台开发系列讲解(QEMU篇) 1.2 新添加一个Linux kernel设备树

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

OSPF动态路由实验(思科)

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

MyBatis 等类似的 XML 映射文件中,当传入的参数为空字符串时,<if> 标签可能会导致 SQL 语句中的条件判断出现意外结果。

问题 传入的参数为空字符串&#xff0c;但还是根据参数查询了。 原因 在 XML 中使用 标签进行条件判断时&#xff0c;需要明确理解其行为。在 MyBatis 等类似的 XML 映射文件中&#xff0c; 标签通常用于动态拼接 SQL 语句的条件部分。当传入的参数 riskLevel 为空字符串时…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

对WWDC 2025 Keynote 内容的预测

借助我们以往对苹果公司发展路径的深入研究经验&#xff0c;以及大语言模型的分析能力&#xff0c;我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际&#xff0c;我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测&#xff0c;聊作存档。等到明…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

wpf在image控件上快速显示内存图像

wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像&#xff08;比如分辨率3000*3000的图像&#xff09;的办法&#xff0c;尤其是想把内存中的裸数据&#xff08;只有图像的数据&#xff0c;不包…...

什么是VR全景技术

VR全景技术&#xff0c;全称为虚拟现实全景技术&#xff0c;是通过计算机图像模拟生成三维空间中的虚拟世界&#xff0c;使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验&#xff0c;结合图文、3D、音视频等多媒体元素…...

【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验

Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...