我们经常看到在听乐音的时候,会有音谱图随着音乐的节奏不断变化给人视觉上的享受,那么我们通过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. Selenium+2Captcha 自动化+验证码识别实战

    本文深入探讨了使用Selenium库进行网页自动化操作,并结合2Captcha服务实现ReCAPTCHA验证码的破解.内容涵盖Selenium的基础知识.验证码的分类.2Captcha服务的使用,以及 ...

  2. quarkus依赖注入之六:发布和消费事件

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本文是<quarkus依赖注入> ...

  3. 带你走进数仓大集群内幕丨详解关于作业hang及残留问题定位

    本文分享自华为云社区<[带你走进DWS大集群内幕]大集群通信:作业hang.残留问题定位>,作者: 雨落天穹丶. 前言: 测试过程中,我们会遇到这样一种情况,我的作业都执行很久了,为啥还不 ...

  4. vite 找不到依赖模块:[plugin:vite:dep-pre-bundle]

    问题描述: 运行项目时,出现[plugin:vite:dep-pre-bundle] 错误.这种问题一般为依赖的包未正常配置相关字段,导致vite无法找到包的入口. 遇到这种模块内.找不到引用模块的, ...

  5. 质效提升 | QA不做业务需求测试,你怎么看?

    ​因为有的小伙伴看到公司的QA不测试业务需求,只搞流程.卡点.规范.技术创新.QA平台,行业洞察,让研发自测.研发担责上线bug和风险,所以问我,你怎么看QA不做业务需求测试这件事.其实我怎么看不重要 ...

  6. 准备HarmonyOS开发环境

    引言 在开始 HarmonyOS 开发之前,需要准备好开发环境.本章将详细指导你如何安装 HarmonyOS SDK.配置开发环境.创建 HarmonyOS 项目. 目录 安装 HarmonyOS S ...

  7. API技术的使用场景

    ​ 互联网的发展和普及,API技术也变得越来越重要.API是应用程序接口,它是一种连接不同应用程序或系统之间数据交换和通信的方式.API技术不仅提高了不同应用程序之间的互操作性,还加速了应用程序的开发 ...

  8. 深入探讨API调用性能优化与错误处理

    ​ 随着互联网技术的不断发展,API(应用程序接口)已经成为软件系统中重要的组成部分.而优化API调用的性能以及处理错误和异常情况则是保障系统稳定性和可靠性的关键.本文将从以下几个方面来探讨如何进行性 ...

  9. selenium-wire兼容selenium和requests

    背景 在工作中UI自动化中可能会需要用到API来做一些数据准备或清理的事情,那UI操作是略低效的,但API操作相对高效. 而实战课就有这样一个案例,不过那个案例是UI操作和API分开的. 极少会遇到这 ...

  10. Journey -「CQOI 2021」

    Day -1 Thu. & Fri. 恰逢学校运动会,于是向班主任申请了不去,然后就在机房坐着.不美好的事情可能就是文化课老师还留了这两天的作业,不过-> 一旦放弃了作业,什么都好说了呢 ...