我们经常看到在听乐音的时候,会有音谱图随着音乐的节奏不断变化给人视觉上的享受,那么我们通过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()
方法并在每一帧更新波形图,可以实现连续的动画效果。
// 获取音频时域数据 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(); } 标签:频谱,canvas,音谱,音乐,ctx,js,var,绘制,音频 From: https://www.cnblogs.com/ximenchuifa/p/17836340.html