我们经常看到在听乐音的时候,会有音谱图随着音乐的节奏不断变化给人视觉上的享受,那么我们通过js来实现以下这个效果,下面是简单的效果图

首先我们需要有一个绘制音频的函数

function draw() {    // 请求下一帧动画    animationId = requestAnimationFrame(draw);
// 获取音频频谱数据 analyser.getByteFrequencyData(dataArray);
// 清空画布 ctx.fillStyle = 'black'; ctx.fillRect(0, 0, canvas.width, canvas.height);
// 计算每个频谱条的宽度 var barWidth = (canvas.width / bufferLength) * 2.5; var barHeight; var x = 0;
// 遍历频谱数据数组,绘制频谱条 for (var i = 0; i < bufferLength; i++) { // 计算频谱条的高度 barHeight = dataArray[i] / 255 * canvas.height;
// 根据频谱条的索引值计算颜色(彩虹色) var hue = i / bufferLength * 360; ctx.fillStyle = 'hsl(' + hue + ', 100%, 50%)';
// 绘制频谱条矩形 ctx.fillRect(x, canvas.height - barHeight, barWidth, barHeight);
// 更新下一个频谱条的起始位置 x += barWidth + 1; }}

这个函数是用于绘制频谱图的核心部分。它使用requestAnimationFrame()方法来请求下一帧动画,并将自身作为回调函数。这样可以不断更新频谱图。

在函数内部,analyser.getByteFrequencyData(dataArray)用于获取当前的音频频谱数据,将数据存储在dataArray数组中。

然后,画布被清空,使用黑色填充整个画布。

接下来,通过计算每个频谱条的宽度,以及根据频谱数据计算每个频谱条的高度,来确定频谱条的绘制参数。

然后,使用彩虹色调的渐变来设置频谱条的颜色,颜色的HSL值根据频谱条的索引值计算。

最后,在画布上绘制每个频谱条的矩形,每个矩形之间留有间距。

通过不断调用requestAnimationFrame()方法并在每一帧更新频谱图,可以实现连续的动画效果。

接下来我们需要分析一下音频
 document.getElementById('playButton').addEventListener('click', function() {
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
analyser = audioContext.createAnalyser();
analyser.fftSize = 2048; audioElement = document.createElement('audio');
audioElement.src = '1.mp3';
audioElement.controls = true;
audioElement.style.display = 'none'; document.body.appendChild(audioElement); var source = audioContext.createMediaElementSource(audioElement);
source.connect(analyser);
analyser.connect(audioContext.destination); bufferLength = analyser.frequencyBinCount;
dataArray = new Uint8Array(bufferLength);
} audioElement.play();
draw();
}); document.getElementById('pauseButton').addEventListener('click', function() {
audioElement.pause();
cancelAnimationFrame(animationId);
});

当用户点击"播放"按钮时,创建一个新的AudioContext对象用于处理音频,创建一个AnalyserNode对象用于分析音频频谱。然后创建一个audio元素并将其设置为要播放的音频文件。将audio元素连接到AnalyserNode,将AnalyserNode连接到AudioContext的目标(通常是扬声器)。设置频率分析器的参数,包括FFT大小。

当用户点击"播放"按钮时,音频开始播放,并且在draw()函数中的requestAnimationFrame(draw)中调用的循环中,更新频谱数据并绘制频谱图。首先,使用analyser.getByteFrequencyData(dataArray)获取音频频谱数据。然后,通过遍历数据数组,计算每个频谱条的高度,并根据频谱条的位置在画布上绘制矩形。颜色根据频谱条的索引值计算,使得频谱图呈现彩虹色的效果。

当用户点击"暂停"按钮时,音频暂停播放,并调用cancelAnimationFrame(animationId)来停止绘制频谱图。

请确保将audioElement.src中的路径替换为你要播放的实际音频文件的路径。

当然修改draw函数可以得到其他的音频图,比如波形图

具体的draw代码如下

这个函数主要用于绘制音频的时域波形图。它也使用了requestAnimationFrame()方法来请求下一帧动画,并将自身作为回调函数。

在函数内部,analyser.getByteTimeDomainData(dataArray)用于获取当前的音频时域数据,将数据存储在dataArray数组中。

然后,画布被清空,并将背景颜色设置为lime。

接下来,设置线条的宽度和颜色。

然后,开始绘制路径。

通过计算每个数据片段的宽度,以及根据时域数据计算每个点的纵坐标,确定波形图的绘制参数。

然后,根据波形点的位置,使用moveTo()方法将绘制路径移动到第一个点的位置,并使用lineTo()方法连接到下一个点的位置。这样就形成了一条完整的波形路径。

在遍历完所有的数据点后,使用lineTo()方法将最后一个点连接到画布的右侧中点,以形成闭合路径。

最后,使用stroke()方法绘制路径。

通过不断调用requestAnimationFrame()方法并在每一帧更新波形图,可以实现连续的动画效果。

function draw() {
// 请求下一帧动画
animationId = requestAnimationFrame(draw);
// 获取音频时域数据
analyser.getByteTimeDomainData(dataArray);
// 清空画布并设置背景颜色为lime
ctx.fillStyle = 'lime';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 设置线条宽度和颜色
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
// 开始绘制路径
ctx.beginPath();
// 计算每个数据片段的宽度
var sliceWidth = canvas.width * 1.0 / bufferLength;
var x = 0;
// 遍历时域数据数组,绘制波形
for (var i = 0; i < bufferLength; i++) {
// 将数据归一化到范围[-1, 1]
var v = dataArray[i] / 128.0;
// 计算波形点的纵坐标
var y = v * canvas.height / 2;
if (i === 0) {
// 移动到第一个点的位置
ctx.moveTo(x, y);
} else {
// 连接到下一个点的位置
ctx.lineTo(x, y);
}
// 更新下一个点的横坐标
x += sliceWidth;
}
// 连接最后一个点到画布右侧中点,形成闭合路径
ctx.lineTo(canvas.width, canvas.height / 2);
    // 绘制路径
   ctx.stroke();
}

使用js写一个音乐音谱图的更多相关文章

  1. 原生js写一个无缝轮播图插件(支持vue)

    轮播图插件(Broadcast.js) 前言:写这个插件的原因 前段时间准备用vue加上网易云的nodejs接口,模拟网易云音乐移动端.因为想自己写一遍所有的代码以及加固自己的flex布局,所以没有使 ...

  2. 分享:计算机图形学期末作业!!利用WebGL的第三方库three.js写一个简单的网页版“我的世界小游戏”

    这几天一直在忙着期末考试,所以一直没有更新我的博客,今天刚把我的期末作业完成了,心情澎湃,所以晚上不管怎么样,我也要写一篇博客纪念一下我上课都没有听,还是通过强大的度娘完成了我的作业的经历.(当然作业 ...

  3. JS写一个简单日历

    JS写一个日历,配合jQuery操作DOM <!DOCTYPE html> <html> <head> <meta charset="UTF-8&q ...

  4. Vue折腾记 - (3)写一个不大靠谱的typeahead组件

    Vue折腾记 - (3)写一个不大靠谱的typeahead组件 2017年07月20日 15:17:05 阅读数:691 前言 typeahead在网站中的应用很多..今天跟着我来写一个不大靠谱的ty ...

  5. 前端与编译原理——用JS写一个JS解释器

    说起编译原理,印象往往只停留在本科时那些枯燥的课程和晦涩的概念.作为前端开发者,编译原理似乎离我们很远,对它的理解很可能仅仅局限于"抽象语法树(AST)".但这仅仅是个开头而已.编 ...

  6. 如何使用 js 写一个正常人看不懂的无聊代码

    如何使用 js 写一个正常人看不懂的无聊代码 代码质量, 代码可读性, 代码可维护性, clean code WAT js WTF https://www.destroyallsoftware.com ...

  7. 用原生js写一个"多动症"的简历

    用原生js写一个"多动症"的简历 预览地址源码地址 最近在知乎上看到@方应杭用vue写了一个会动的简历,觉得挺好玩的,研究一下其实现思路,决定试试用原生js来实现. 会动的简历实现 ...

  8. 【Part1】用JS写一个Blog(node + vue + mongoDB)

    学习JS也有一段时间了,准备试着写一个博客项目,前后端分离开发,后端用node只提供数据接口,前端用vue-cli脚手架搭建,路由也由前端控制,数据异步交互用vue的一个插件vue-resourse来 ...

  9. [NodeJS]使用Node.js写一个简单的在线聊天室

    声明:教程来自<Node即学即用>.源代码案例均出自此书.博文仅为个人学习笔记. 第一步:创建一个聊天server. 首先,我们先来写一个Server: var net = require ...

  10. 使用 Node.js 写一个代码生成器

    背景 第一次接触代码生成器用的是动软代码生成器,数据库设计好之后,一键生成后端 curd代码.之后也用过 CodeSmith , T4.目前市面上也有很多优秀的代码生成器,而且大部分都提供可视化界面操 ...

随机推荐

  1. linux 问题: ssh登录报错,ssh_exchange_identification,多次几次可以登录

    分析 怀疑是句柄数不够,和ssh的最大登录限制 确认 2.1 确认句柄数 过程: ~# systemctl status sshd | grep -i pid Main PID: 3767395 (s ...

  2. 【NestJS系列】连接数据库及优雅地处理响应

    前言 Node作为一门后端语言,当然也可以连接数据库,为前端提供CURD接口 我们以mysql为例,自行安装mysql TypeORM TypeORM 是一个ORM框架,它可以运行在 NodeJS.B ...

  3. 如何通过API接口获取淘宝的店铺所有商品详情

    在电子商务领域中,淘宝是亚洲最大的在线交易平台之一,拥有海量的商品资源和消费者.如果你是一名开发者,想要在自己的网站或者APP中嵌入淘宝商品资源,那么你就需要通过淘宝开放平台提供的API接口来获取这些 ...

  4. QA|linux指令awk '{print $(NF-1)}'为啥用单引号而不是双引号?|linux

    linux指令awk '{print $(NF-1)}'为啥用单引号而不是双引号? 我的理解: 因为单引号不对会内容进行转义,而双引号会,举个栗子 1 a=1 2 echo "$a" ...

  5. iOS越狱后必装软件

    iOS越狱后就跟ubuntu没两样了,很多ubuntu下常用的软件都要装一下 openssh 这个软件可以让我们能够登录iphone Apt-get 用这个软件可以安装很多软件,主要是一些工具调试类软 ...

  6. RK3568开发笔记(十):开发板buildroot固件移植开发的应用Demo,启动全屏显示

    前言   上一篇,移植应用前的通讯接口工作和全屏工作都已经完成了.本篇移植开发的商业应用.   交叉编译好应用   (略),参照<RK3568开发笔记(八):开发板烧写buildroot固件(支 ...

  7. python入门基础(14)--类的属性、成员方法、静态方法以及继承、重载

    上一篇提到过类的属性,但没有详细介绍,本篇详细介绍一下类的属性 一 .类的属性 方法是用来操作数据的,而属性则是建模必不的内容,而且操作的数据,大多数是属性,比如游戏中的某个boss类,它的生命值就是 ...

  8. 国庆微信头像DIY:轻松打造个性化头像

    前言 国庆节马上要到了,今天就教你如何从0到1使用canvas生成国庆风微信头像. 本文包含以下内容: vue3项目搭建,需求分析 canvas合成图片原理 github自动化部署 开发过程遇到的问题 ...

  9. SpringBoot WebSocket STOMP

    SpringBoot WebSocket STOMP 关键词:Springboot, WebSocket, STOMP, broadcast, sendToUser, MessageMapping, ...

  10. Springboot实现注解判断权限

    Springboot实现注解判断权限 今天记录一下使用springboot的注解来给方法加权限 避免了每个方法都需要大量的权限判断 超级好用√ @ 目录 Springboot实现注解判断权限 1.创建 ...