HTML5 canvas绘制音频,音乐可视化

效果

效果示例

技术
  • nodeJs + express + http + fs 实现环境搭建,读取歌曲并生成列表
  • ajax 获取音频
  • AudioContext API 解析音频
  • canvas 绘制图形图像
  • requestAnimationFrame 调起动画
重点

canvas绘制、AudioContext API 应用
代码在 ‘public/javascripts/index.js’ 中
本博文重点讲解实现过程中使用的 AudioContext 相关的 API
如果对 web audio API 很有兴趣,请参见 web audio API

AudioContext

音频处理的环境和上下文,可以控制它所包含的节点的创建,以及音频处理、音频解码操作,读取播放状态等。
做任何音频相关的事情之前都要先创建 AudioContext 对象,因为一切都发生在这个环境之中。

那么如何创建 AudioContext 这个环境呢?

const AC = new(window.AudioContext || window.webkitAudioContext)();

这个环境下包含许多非常重要的方法和属性,挑几个说说:

AudioBufferSourceNode:代表一个音频源,可以挂载一段写在内存中的音频数据,没有输入,有一个输出方法,可以利用 start 方法来调用,利用 stop 方法来关闭

const AudioBufferSourceNode = AC.createBufferSource(); //这里创建了个音频源
AudioBufferSourceNode.start([when [, offset [, duration]]); //安排声音在指定时间播放。没有指定时间,则声音立即开始播放。
AudioBufferSourceNode.buffer = buffer; //挂载一段内存中的音频片段,
AudioBufferSourceNode.stop([when]); //停止播放
AudioBufferSourceNode.onended = ()=>{} //当前音频播放完毕后的回调函数

这里需要注意一个事情:
AudioBufferSourceNode 只能被播放一次
GainNode :代表一个音量控制器,通过它可以控制输出音频的音量大小,一般取值0-1

const GainNode = AC.createGain()
GainNode.gain.value = 0.6

AnalyserNode :代表一个音频分析器,赋予了节点可以提供实时频率及时间域分析的信息

const AnalyserNode = AC.createAnalyser();
AnalyserNode.fftSize = number * 2 // FFT是离散傅里叶变换的快速算法,用于将一个信号变换到频域,
									//得到的值是32-2048之间的2的整数次倍,默认是2048。
console.log(AnalyserNode.frequencyBinCount) // number,通常代表要用于可视化的数据值的数量,值为 analyserNode.fftSize/2

AudioDestinationNode:表示音频的最终输出地址 - 通常为扬声器

const AudioDestinationNode = AC.destination

currentTime:当前音频环境播放时长

AC.currentTime

(关于 currentTime 我的理解和翻译过来的 API 解读文档有所不同),下图是翻译来的意思:
在这里插入图片描述
这张图是英文原文
在这里插入图片描述
英文的意思大概是用来调节音频播放、可视化时间戳等(scheduling audio playback, visualizing timelines),
所以我的理解是当前环境的播放时长,事实上在案例中我也实际使用了这个值,在音频开始播放前, AC.currentTime 始终为 0,并且音频环境被 suspend() 掉的时候,currentTime的值也不再变化,即被暂停掉了

decodeAudioData:这是一个方法,通常用于异步解码音频文件,被解码的文件是通过使用 responseType 为 arraybuffer 类型的 ajax 获取的,该方法只能作用于完整的音频文件

xhr.responseType = "arraybuffer"; //返回一段二进制数据
xhr.onload = function() { //类似onreadystatechange
    AC.decodeAudioData(this.response,(buffer)=>{
    	console.log(buffer) //解码后得到的文件,可以挂在到 AudioBufferSourceNode.buffer 上
    	console.log(buffer.duration) // 音频时间长度
	},(err) => {
        console.log(`errMessage:${err}`);
    });
}

resume:重新启动一个已被暂停的音频环境

AC.resume()

suspend:暂停音频内容的进度.暂时停止音频硬件访问和减少在过程中的CPU/电池使用.

AC.suspend()

这里还少了一个重要步骤,即将音频和音量控制器,音频分析器,播放器相互关联,这样他们才能够正常使用

AudioBufferSourceNode.connect(AnalyserNode );
AnalyserNode .connect(GainNode);
GainNode.connect(AudioDestinationNode ); 
梳理一下音乐播放的实现流程
  1. node 使用 fs 模块读取所有的歌曲并生成列表渲染到前端页面
  2. 当点击播放的时候,我们先查找本地缓存中是否有当前歌曲,有的话,我们创建一个音频环境进行播放,没有的话,我们则通过 ajax 获取到音频数据,然后通过 AC.decodeAudioData 解析成 buffer 存到缓存中,然后创建音频环境进行播放
  3. 在每次播放不同的歌曲之前,先调用 AC.suspend 停止当前播放的音乐,这样保证同一时间只有一首歌处于播放状态
  4. 如果是点击暂停/播放按钮,那么我们单纯的通过 resume/suspend 来控制当前音频的播放与暂停
  5. 播放的时长是通过 AC.currentTime 拿到的,总时长是 buffer.duration, 进度条是二者的比值
  6. 音量的控制通过 gainNode.gain.value 来控制
  7. 本地文件播放则是通过 fileReader.readAsArrayBuffer 将文件读取,然后依然通过 AC.decodeAudioData 解码来进行播放
canvas图形绘制

首先我们得到 AnalyserNode.frequencyBinCount,即可视化数据值,然后将其存为 Uint8Array 数组类型,

let arr = new Uint8Array(AnalyserNode.frequencyBinCount);

之后通过 getByteFrequencyData 方法将当前频率数据复制到传递给它的 uint8array 中,

AnalyserNode.getByteFrequencyData(arr);

得到的值大概是这样
在这里插入图片描述
这就是我们可视化音频需要的数据了,他是随着音频播放而不断变化的值,初始全部为 0 ,然后遍历这个数组,拿到数组中每一项的值,就是一组音谱条应该绘制的高度,看图就明白了
在这里插入图片描述
每一组音谱条其实就是一条有宽度的,带有渐变背景色的线,线的高度就是 arr[i], 这条线被平均分成了 n 个小方格,每个小方格的高度为 4,彼此间隔为 0.5,然后我们不断计算更新小方块和小红块的位置,通过 requestAnimationFrame 重新渲染就可以了。

最后附上代码地址,欢迎 star 和 issue。

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的使用 JavaScript 可视化音乐的案例: ```html <!DOCTYPE html> <html> <head> <title>音乐可视化</title> <style> canvas { background-color: #000; } </style> </head> <body> <audio id="audio" controls> <source src="music.mp3" type="audio/mpeg"> </audio> <canvas id="canvas"></canvas> <script> // 获取 canvas 元素 var canvas = document.getElementById("canvas"); // 设置 canvas 的宽和高 canvas.width = window.innerWidth; canvas.height = window.innerHeight; // 获取 canvas 的上下文 var ctx = canvas.getContext("2d"); // 获取音频元素 var audio = document.getElementById("audio"); // 创建音频上下文 var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); // 创建音频源节点 var source = audioCtx.createMediaElementSource(audio); // 创建分析器节点 var analyser = audioCtx.createAnalyser(); // 连接节点 source.connect(analyser); analyser.connect(audioCtx.destination); // 设置分析器的参数 analyser.fftSize = 2048; var bufferLength = analyser.frequencyBinCount; var dataArray = new Uint8Array(bufferLength); // 绘制可视化效果 function draw() { // 清空画布 ctx.clearRect(0, 0, canvas.width, canvas.height); // 获取音频数据 analyser.getByteFrequencyData(dataArray); // 设置绘制样式 ctx.fillStyle = "#fff"; ctx.lineWidth = 2; ctx.strokeStyle = "#fff"; ctx.beginPath(); var sliceWidth = canvas.width * 1.0 / bufferLength; var x = 0; for (var i = 0; i < bufferLength; i++) { 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(); requestAnimationFrame(draw); } // 开始绘制 draw(); </script> </body> </html> ``` 以上代码实现了一个简单的音乐可视化效果。用户可以在页面上播放音乐,并且通过 canvas 元素将音频数据可视化为波形图。在代码中,使用了 Web Audio API 中的 AnalyserNode 节点来获取音频数据,并且使用 canvas 绘制波形图。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值