基于JavaScript實現(xiàn)簡單的音樂音譜圖效果
我們經(jīng)常看到在聽樂音的時候,會有音譜圖隨著音樂的節(jié)奏不斷變化給人視覺上的享受,那么我們通過js來實現(xiàn)以下這個效果,下面是簡單的效果圖

首先我們需要有一個繪制音頻的函數(shù)
function draw() {
// 請求下一幀動畫
animationId = requestAnimationFrame(draw);
// 獲取音頻頻譜數(shù)據(jù)
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;
// 遍歷頻譜數(shù)據(jù)數(shù)組,繪制頻譜條
for (var i = 0; i < bufferLength; i++) {
// 計算頻譜條的高度
barHeight = dataArray[i] / 255 * canvas.height;
// 根據(jù)頻譜條的索引值計算顏色(彩虹色)
var hue = i / bufferLength * 360;
ctx.fillStyle = 'hsl(' + hue + ', 100%, 50%)';
// 繪制頻譜條矩形
ctx.fillRect(x, canvas.height - barHeight, barWidth, barHeight);
// 更新下一個頻譜條的起始位置
x += barWidth + 1;
}
}這個函數(shù)是用于繪制頻譜圖的核心部分。它使用requestAnimationFrame()方法來請求下一幀動畫,并將自身作為回調函數(shù)。這樣可以不斷更新頻譜圖。
在函數(shù)內(nèi)部,analyser.getByteFrequencyData(dataArray)用于獲取當前的音頻頻譜數(shù)據(jù),將數(shù)據(jù)存儲在dataArray數(shù)組中。
然后,畫布被清空,使用黑色填充整個畫布。
接下來,通過計算每個頻譜條的寬度,以及根據(jù)頻譜數(shù)據(jù)計算每個頻譜條的高度,來確定頻譜條的繪制參數(shù)。
然后,使用彩虹色調的漸變來設置頻譜條的顏色,顏色的HSL值根據(jù)頻譜條的索引值計算。
最后,在畫布上繪制每個頻譜條的矩形,每個矩形之間留有間距。
通過不斷調用requestAnimationFrame()方法并在每一幀更新頻譜圖,可以實現(xiàn)連續(xù)的動畫效果。
接下來我們需要分析一下音頻
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);
});當用戶點擊"播放"按鈕時,創(chuàng)建一個新的AudioContext對象用于處理音頻,創(chuàng)建一個AnalyserNode對象用于分析音頻頻譜。然后創(chuàng)建一個audio元素并將其設置為要播放的音頻文件。將audio元素連接到AnalyserNode,將AnalyserNode連接到AudioContext的目標(通常是揚聲器)。設置頻率分析器的參數(shù),包括FFT大小。
當用戶點擊"播放"按鈕時,音頻開始播放,并且在draw()函數(shù)中的requestAnimationFrame(draw)中調用的循環(huán)中,更新頻譜數(shù)據(jù)并繪制頻譜圖。首先,使用analyser.getByteFrequencyData(dataArray)獲取音頻頻譜數(shù)據(jù)。然后,通過遍歷數(shù)據(jù)數(shù)組,計算每個頻譜條的高度,并根據(jù)頻譜條的位置在畫布上繪制矩形。顏色根據(jù)頻譜條的索引值計算,使得頻譜圖呈現(xiàn)彩虹色的效果。
當用戶點擊"暫停"按鈕時,音頻暫停播放,并調用cancelAnimationFrame(animationId)來停止繪制頻譜圖。
請確保將audioElement.src中的路徑替換為你要播放的實際音頻文件的路徑。
當然修改draw函數(shù)可以得到其他的音頻圖,比如波形圖

具體的draw代碼如下
這個函數(shù)主要用于繪制音頻的時域波形圖。它也使用了requestAnimationFrame()方法來請求下一幀動畫,并將自身作為回調函數(shù)。
在函數(shù)內(nèi)部,analyser.getByteTimeDomainData(dataArray)用于獲取當前的音頻時域數(shù)據(jù),將數(shù)據(jù)存儲在dataArray數(shù)組中。
然后,畫布被清空,并將背景顏色設置為lime。
接下來,設置線條的寬度和顏色。
然后,開始繪制路徑。
通過計算每個數(shù)據(jù)片段的寬度,以及根據(jù)時域數(shù)據(jù)計算每個點的縱坐標,確定波形圖的繪制參數(shù)。
然后,根據(jù)波形點的位置,使用moveTo()方法將繪制路徑移動到第一個點的位置,并使用lineTo()方法連接到下一個點的位置。這樣就形成了一條完整的波形路徑。
在遍歷完所有的數(shù)據(jù)點后,使用lineTo()方法將最后一個點連接到畫布的右側中點,以形成閉合路徑。
最后,使用stroke()方法繪制路徑。
通過不斷調用requestAnimationFrame()方法并在每一幀更新波形圖,可以實現(xiàn)連續(xù)的動畫效果。
function draw() {
// 請求下一幀動畫
animationId = requestAnimationFrame(draw);
// 獲取音頻時域數(shù)據(jù)
analyser.getByteTimeDomainData(dataArray);
// 清空畫布并設置背景顏色為lime
ctx.fillStyle = 'lime';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 設置線條寬度和顏色
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
// 開始繪制路徑
ctx.beginPath();
// 計算每個數(shù)據(jù)片段的寬度
var sliceWidth = canvas.width * 1.0 / bufferLength;
var x = 0;
// 遍歷時域數(shù)據(jù)數(shù)組,繪制波形
for (var i = 0; i < bufferLength; i++) {
// 將數(shù)據(jù)歸一化到范圍[-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();
}到此這篇關于基于JavaScript實現(xiàn)簡單的音樂音譜圖效果的文章就介紹到這了,更多相關JavaScript音譜圖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
JavaScript 判斷數(shù)據(jù)類型的4種方法
這篇文章主要介紹了JavaScript 判斷數(shù)據(jù)類型的4種方法,幫助大家更好的理解和學習JavaScript,感興趣的朋友可以了解下2020-09-09
基于javascript實現(xiàn)彩票隨機數(shù)生成(簡單版)
這篇文章主要介紹了基于javascript實現(xiàn)彩票隨機數(shù)生成的相關資料,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-01-01
使用Javascript監(jiān)控前端相關數(shù)據(jù)的代碼
本篇文章詳細的介紹了使用Javascript監(jiān)控前端相關數(shù)據(jù),可以及時的監(jiān)控前端的錯誤,加載時間等,有需要的可以了解一下。2016-10-10
前端JavaScript中l(wèi)ocation.reload刷新頁面用法詳解
這篇文章主要介紹了前端JavaScript中l(wèi)ocation.reload刷新頁面用法的相關資料,location.reload()是JavaScript中用于重新加載當前頁面的方法,它可以接受一個布爾參數(shù),以決定是否忽略緩存,文中通過代碼介紹的非常詳細,需要的朋友可以參考下2025-02-02

