我们经常看到在听乐音的时候,会有音谱图随着音乐的节奏不断变化给人视觉上的享受,那么我们通过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. KVM 动态调整 qcow2 硬盘

    动态扩容 参考:https://cloud-atlas.readthedocs.io/zh_CN/latest/kvm/kvm_vdisk_live.html 未关闭虚拟机,直接在宿主机器上qemu- ...

  2. 20.1K Star!Notion的开源替代方案:AFFiNE

    Notion这款笔记软件相信很多开发者都比较熟悉了,很多读者,包括我自己都用它来记录和管理自己的笔记.今天给大家推荐一个最近比较火的开源替代方案:AFFiNE.目前该开源项目已经斩获20.1K Sta ...

  3. Go函数可以返回多个值

    1 package main 2 3 import "fmt" 4 5 func swap(x, y string) (string, string){ 6 return y,x ...

  4. 基于Aidlux平台的人脸关键点检测以及换脸算法

    第一步:安装APP 手机应用市场下载AidLux 手机和电脑连接同一个Wifi 第二步:配置APP 赋予AidLux各种系统权限,包括:媒体和文件.相机.麦克风.后台弹窗 手机-设置-关于手机-点击操 ...

  5. 如何将训练好的Python模型给JavaScript使用?

    前言 从前面的Tensorflow环境搭建到目标检测模型迁移学习,已经完成了一个简答的扑克牌检测器,不管是从图片还是视频都能从画面中识别出有扑克的目标,并标识出扑克点数.但是,我想在想让他放在浏览器上 ...

  6. 关于3D-AIGC的调研与探讨

    0.前言 本文是自己最近在项目上的需要做的一些调研和自己的一些看法,以分享为主. 2D AIGC(文生文.文生图.图生图)在今天大放异彩,产生了许多惊艳的效果,如ChatGPT系列.Imagen.DA ...

  7. uniapp APP微信登录、支付、分享以及支付宝支付 实战踩坑记录

    1.微信支付和支付宝支付   先上代码.封装好了的组件    html部分      <template> <view class="rows"> < ...

  8. 3.你所不知道的go语言控制语句——Leetcode习题69

    目录 本篇前瞻 Leetcode习题9 题目描述 代码编写 控制结构 顺序结构(Sequence) 声明和赋值 多返回值赋值 运算符 算术运算符 位运算符 逻辑运算 分支结构 if 语句 switch ...

  9. Unity UGUI的ScrollRect(滚动视图)组件的介绍及使用

    Unity UGUI的ScrollRect(滚动视图)组件的介绍及使用 1. 什么是ScrollRect组件? ScrollRect(滚动视图)是Unity UGUI中的一个常用组件,用于在UI界面中 ...

  10. MySQL篇:第一章_软件安装和基本操作

    本篇安装软件Navicate Premium 16破解版和phpstudy_pro phpstudy_pro安装教程 phpstudy官网:https://www.xp.cn/download.htm ...