使用canvas繪圖音樂頻譜示例及技術(shù)分析
正文
看到跳動的音符你難道不想知道它是如何實現(xiàn)的么?開擼!
問:實現(xiàn)這個有什么用呢?
答:裝杯用!??其實這個操作能實現(xiàn)音頻效果器。就是主播開麥后大媽聲音變成少女,男人聲音可以變女聲!??因為音頻分析器可以拿到音頻的頻譜,既可以改變音調(diào)啊音色啊什么的就可以實現(xiàn)音頻效果器!??
不想看我啰嗦的直接看最后,有整體html+js代碼,粘貼到你的html頁面內(nèi),換以下音頻資源鏈接就能看到效果了!
效果圖

技術(shù)分析
音頻加載
在html內(nèi)增加audio標簽。將音樂加載進來。給audio標簽增加controls屬性用來控制音樂播放。如下:
<html> <body> <audio src="/source/YOU.m4a" controls></audio> </body> </html>
頻譜獲取
要獲取音頻的頻譜需要使用javascript的AudioContext對象。
var audio = document.querySelector("audio");
let dataArray = new Uint8Array(512);
let analyser = null
audio.onplay = function() {
let audctx = new AudioContext() // 創(chuàng)建音頻上下文
let source = audctx.createMediaElementSource(audio) // 創(chuàng)建音頻源
analyser = audctx.createAnalyser() // 創(chuàng)建音頻分析器
analyser.fftSize = 512 // 設置分析器大小, 必須為2^n次方
// 創(chuàng)建一個數(shù)組,用于存放分析器節(jié)點數(shù)據(jù)
// analyser.frequencyBinCount可以拿到傅里葉變換的值,因為傅里葉變換是對稱的因此只要一半即可(傅里葉變換請自行搜索)
dataArray = new Uint8Array(analyser.frequencyBinCount)
source.connect(analyser) // 音頻源連接到音頻分析器
analyser.connect(audctx.destination) // 音頻分析器連接到音頻輸出
}至此我們已經(jīng)獲取到了音頻的頻譜數(shù)據(jù)。
頻譜可視化
對于高效繪制需要用到畫布,既canvas標簽,在body內(nèi)增加canvas標簽,并起id為cvs。
<body>
<canvas id="cvs"></canvas>
<audio src="/source/YOU.m4a" controls></audio>
</body>var cvs = document.getElementById("cvs");
var ctx = cvs.getContext("2d");
function initCanvas() {
// 設置canvas寬度為瀏覽器可視區(qū)域
cvs.width = window.innerWidth * devicePixelRatio;
// 設置canvas高度為瀏覽器可視區(qū)域的一半
cvs.height = window.innerHeight / 2 * devicePixelRatio;
}
// 窗口變化時候重新設置canvas寬高
window.onresize = function() {
initCanvas();
}
// 定義draw方法用于繪制頻譜
function draw() {
// 使用瀏覽器自帶幀動畫函數(shù)實現(xiàn)每一幀都繪制。
requestAnimationFrame(draw);
// 清空畫布
ctx.clearRect(0, 0, cvs.width, cvs.height);
const len = dataArray.length / 1.2; // 截取頻譜繪制長度
const barWidth = cvs.width / len; // 每一根柱子的寬度
ctx.fillStyle = '#c875fc'; // 給柱子填充顏色
// 遍歷每一根柱子,設置其位置以及邊框。
for (let i = 0; i < len; i++) {
const data = dataArray[i]
const barHeight = data / 255 * cvs.height
const x = i * barWidth
const y = cvs.height - barHeight
drawBorder(x,y,barWidth, barHeight)
ctx.fillStyle = '#8ca86d'
ctx.fillRect(x, y, barWidth, barHeight)
}
}至此基本完成了繪制方面的任務
全部合并后就是以下代碼,將以下代碼在你本機創(chuàng)建一個html復制進去就可以看到效果(注意把音頻資源換成自己的):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>聲音波浪</title>
</head>
<style>
#cvs {
border: 1px solid #000;
}
audio {
display: block;
}
</style>
<body>
<canvas id="cvs"></canvas>
<audio src="/source/YOU.m4a" controls></audio>
</body>
<script>
var cvs = document.getElementById("cvs");
var ctx = cvs.getContext("2d");
var audio = document.querySelector("audio");
let isInitAudio = false;
let analyser = null
let dataArray = new Uint8Array(512);
/* 初始化canvas */
function initCanvas() {
cvs.width = window.innerWidth * devicePixelRatio;
cvs.height = window.innerHeight / 2 * devicePixelRatio;
}
window.onresize = function() {
initCanvas();
}
/* 初始化音頻 */
function initAudio() {
audio.onplay = function() {
let audctx = new AudioContext() // 創(chuàng)建音頻上下文
let source = audctx.createMediaElementSource(audio) // 創(chuàng)建音頻源
analyser = audctx.createAnalyser() // 創(chuàng)建音頻分析器
analyser.fftSize = 512 // 設置分析器大小, 必須為2^n次方
// 創(chuàng)建一個數(shù)組,用于存放分析器節(jié)點數(shù)據(jù)
// analyser.frequencyBinCount可以拿到傅里葉變換的值,因為傅里葉變換是對稱的因此只要一半即可
dataArray = new Uint8Array(analyser.frequencyBinCount)
draw()
source.connect(analyser) // 音頻源連接到音頻分析器
analyser.connect(audctx.destination) // 音頻分析器連接到音頻輸出
let bufferLength = analyser.frequencyBinCount
}
}
function draw() {
requestAnimationFrame(draw);
// 清空畫布
ctx.clearRect(0, 0, cvs.width, cvs.height);
analyser.getByteFrequencyData(dataArray)
const len = dataArray.length / 1.2
const barWidth = cvs.width / len
ctx.fillStyle = '#c875fc'
for (let i = 0; i < len; i++) {
const data = dataArray[i]
const barHeight = data / 255 * cvs.height
const x = i * barWidth
const y = cvs.height - barHeight
drawBorder(x,y,barWidth, barHeight)
ctx.fillStyle = '#8ca86d'
ctx.fillRect(x, y, barWidth, barHeight)
}
}
function drawBorder(xPos, yPos, width, height, thickness = 1) {
ctx.fillStyle='#000';
ctx.fillRect(xPos - (thickness), yPos - (thickness), width + (thickness * 2), height + (thickness * 2));
}
function initAll() {
initCanvas();
initAudio()
}
initAll()
</script>
</html>以上就是使用canvas實現(xiàn)音樂頻譜示例及技術(shù)分析的詳細內(nèi)容,更多關于canvas音樂頻譜的資料請關注腳本之家其它相關文章!
相關文章
JS網(wǎng)頁播放聲音實現(xiàn)代碼兼容各種瀏覽器
JS網(wǎng)頁播放聲音有多種方法可以實現(xiàn),不過兼容各種瀏覽器的就沒有幾個了,不過本文的這個示例或許對大家有所幫助2013-09-09
支付寶小程序自定義彈窗dialog插件的實現(xiàn)代碼
支付寶小程序官方提供的alert提示框、dialog對話框、model彈窗功能比較有限,有些都不能隨意自定義修改的。這篇文章主要介紹了支付寶小程序自定義彈窗dialog插件的實現(xiàn)代碼,需要的朋友可以參考下2018-11-11
js數(shù)組循環(huán)遍歷數(shù)組內(nèi)所有元素的方法
在js中數(shù)組遍歷最簡單的辦法就是使用for然后再利用arr.length長度作為for最大限度值即可解決了,下面我們來看看一些有用的實例2014-01-01
???????Rxjs?map,?mergeMap?和?switchMap?的區(qū)別與聯(lián)系
這篇文章主要介紹了???????Rxjs?map,mergeMap和switchMap的區(qū)別與聯(lián)系,map、mergeMap和switchMap是RxJS中的三個主要運算符,在SAP?Spartacus開發(fā)中有著廣泛的使用場景2022-07-07

