您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關基于Web Audio API實現音頻可視化效果的方法,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
網頁音頻接口最有趣的特性之一它就是可以獲取頻率、波形和其它來自聲源的數據,這些數據可以被用作音頻可視化。這篇文章將解釋如何做到可視化,并提供了一些基礎使用案例。
基本概念節
要從你的音頻源獲取數據,你需要一個 AnalyserNode
節點,它可以用 AudioContext.createAnalyser()
方法創建,比如:
var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); var analyser = audioCtx.createAnalyser();
然后把這個節點(node)
連接到你的聲源:
source = audioCtx.createMediaStreamSource(stream); source.connect(analyser); analyser.connect(distortion);
// etc.
注意: 分析器節點(Analyser Node)
不一定輸出到另一個節點,不輸出時也可以正常使用。但前提是它必須與一個聲源相連(直接或者通過其他節點間接相連都可以)。
分析器節點(Analyser Node)
將在一個特定的頻率域里使用快速傅立葉變換(Fast Fourier Transform (FFT) )
來捕獲音頻數據,這取決于你給 AnalyserNode.fftSize
屬性賦的值(如果沒有賦值,默認值為2048)。
注意: 你也可以為FFT數據縮放范圍指定一個最小值和最大值,使用AnalyserNode.minDecibels 和AnalyserNode.maxDecibels
進行設置,要獲得不同數據的平均常量,使用 AnalyserNode.smoothingTimeConstant
。閱讀這些頁面以獲得更多如何使用它們的信息。
要捕獲數據,你需要使用 AnalyserNode.getFloatFrequencyData()
或 AnalyserNode.getByteFrequencyData()
方法來獲取頻率數據,用 AnalyserNode.getByteTimeDomainData() 或 AnalyserNode.getFloatTimeDomainData()
來獲取波形數據。
這些方法把數據復制進了一個特定的數組當中,所以你在調用它們之前要先創建一個新數組。第一個方法會產生一個32位浮點數組,第二個和第三個方法會產生8位無符號整型數組,因此一個標準的JavaScript數組就不能使用 —— 你需要用一個 Float32Array 或者 Uint8Array 數組,具體需要哪個視情況而定。
那么讓我們來看看例子,比如我們正在處理一個2048尺寸的FFT。我們返回 AnalyserNode.frequencyBinCount 值
,它是FFT的一半,然后調用Uint8Array()
,把frequencyBinCount
作為它的長度參數 —— 這代表我們將對這個尺寸的FFT收集多少數據點。
analyser.fftSize = 2048; var bufferLength = analyser.frequencyBinCount; var dataArray = new Uint8Array(bufferLength);
要正確檢索數據并把它復制到我們的數組里,就要調用我們想要的數據收集方法,把數組作為參數傳遞給它,例如:
analyser.getByteTimeDomainData(dataArray);
現在我們就獲取了那時的音頻數據,并存到了我們的數組里,而且可以把它做成我們喜歡的可視化效果了,比如把它畫在一個HTML5 <canvas>
畫布上。
創建一個頻率條形圖節
另一種小巧的可視化方法是創建頻率條形圖,
現在讓我們來看看它是如何實現的。
首先,我們設置好解析器和空數組,之后用 clearRect()
清空畫布。與之前的唯一區別是我們這次大大減小了FFT
的大小,這樣做的原因是為了使得每個頻率條足夠寬,讓它們看著像“條”而不是“細桿”。
analyser.fftSize = 256; var bufferLength = analyser.frequencyBinCount; console.log(bufferLength); var dataArray = new Uint8Array(bufferLength); canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);
接下來我們寫好 draw() 函數,再一次用 requestAnimationFrame()
設置一個循環,這樣顯示的數據就可以保持刷新,并且每一幀都清空一次畫布。
function draw() { drawVisual = requestAnimationFrame(draw); analyser.getByteFrequencyData(dataArray); canvasCtx.fillStyle = 'rgb(0, 0, 0)'; canvasCtx.fillRect(0, 0, WIDTH, HEIGHT); }
現在我們來設置一個 barWidth 變量,它等于每一個條形的寬度。理論上用花布寬度除以條的個數就可以得到它,但是在這里我們還要乘以2.5。這是因為有很多返回的頻率區域中是沒有聲音的,我們每天聽到的大多數聲音也只是在一個很小的頻率區域當中。在條形圖中我們肯定不想看到大片的空白條,所以我們就把一些能正常顯示的條形拉寬來填充這些空白區域。
我們還要設置一個條高度變量 barHeight
,還有一個 x 變量來記錄當前條形的位置。
var barWidth = (WIDTH / bufferLength) * 2.5; var barHeight; var x = 0;
像之前一樣,我們進入循環來遍歷 dataArray 數組中的數據。在每一次循環過程中,我們讓條形的高度 barHeight
等于數組的數值,之后根據高度設置條形的填充色(條形越高,填充色越亮),然后在橫坐標 x 處按照設置的寬度和高度的一半把條形畫出來(我們最后決定只畫高度的一半因為這樣條形看起來更美觀)。
需要多加解釋的一點是每個條形豎直方向的位置,我們在 HEIGHT-barHeight/2
的位置畫每一條,這是因為我想讓每個條形從底部向上伸出,而不是從頂部向下(如果我們把豎直位置設置為0它就會這樣畫)。所以,我們把豎直位置設置為畫布高度減去條形高度的一半,這樣每個條形就會從中間向下畫,直到畫布最底部。
for(var i = 0; i < bufferLength; i++) { barHeight = dataArray[i]/2; canvasCtx.fillStyle = 'rgb(' + (barHeight+100) + ',50,50)'; canvasCtx.fillRect(x,HEIGHT-barHeight/2,barWidth,barHeight); x += barWidth + 1; } };
和剛才一樣,我們在最后調用 draw()
函數來開啟整個可視化過程。
draw();
這些代碼會帶來下面的效果:
源碼:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"/> <title>可視化音樂播放器</title> </head> <body> <input type="file" name="" value="" id="musicFile"> <p id="tip"></p> <canvas id="casvased" width="500" height="500"></canvas> </body> <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script> <script type="text/javascript"> //隨機變顏色 function randomRgbColor() { //隨機生成RGB顏色 var r = Math.floor(Math.random() * 256); //隨機生成256以內r值 var g = Math.floor(Math.random() * 256); //隨機生成256以內g值 var b = Math.floor(Math.random() * 256); //隨機生成256以內b值 return `rgb(${r},${g},${b})`; //返回rgb(r,g,b)格式顏色 } //隨機數 0-255 function sum (m,n){ var num = Math.floor(Math.random()*(m - n) + n); } console.log(sum(0,100)); console.log(sum(100,255)); //展示音頻可視化 var canvas = document.getElementById("casvased"); var canvasCtx = canvas.getContext("2d"); //首先實例化AudioContext對象 很遺憾瀏覽器不兼容,只能用兼容性寫法;audioContext用于音頻處理的接口,并且工作原理是將AudioContext創建出來的各種節點(AudioNode)相互連接,音頻數據流經這些節點并作出相應處理。 //總結就一句話 AudioContext 是音頻對象,就像 new Date()是一個時間對象一樣 var AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext; if (!AudioContext) { alert("您的瀏覽器不支持audio API,請更換瀏覽器(chrome、firefox)再嘗試,另外本人強烈建議使用谷歌瀏覽器!") } var audioContext = new AudioContext();//實例化 // 總結一下接下來的步驟 // 1 先獲取音頻文件(目前只支持單個上傳) // 2 讀取音頻文件,讀取后,獲得二進制類型的音頻文件 // 3 對讀取后的二進制文件進行解碼 $('#musicFile').change(function(){ if (this.files.length == 0) return; var file = $('#musicFile')[0].files[0];//通過input上傳的音頻文件 var fileReader = new FileReader();//使用FileReader異步讀取文件 fileReader.readAsArrayBuffer(file);//開始讀取音頻文件 fileReader.onload = function(e) {//讀取文件完成的回調 //e.target.result 即為讀取的音頻文件(此文件為二進制文件) //下面開始解碼操作 解碼需要一定時間,這個時間應該讓用戶感知到 var count = 0; $('#tip').text('開始解碼') var timer = setInterval(function(){ count++; $('#tip').text('解碼中,已用時'+count+'秒') },1000) //開始解碼,解碼成功后執行回調函數 audioContext.decodeAudioData(e.target.result, function(buffer) { clearInterval(timer) $('#tip').text('解碼成功,用時共計:'+count+'秒') // 創建AudioBufferSourceNode 用于播放解碼出來的buffer的節點 var audioBufferSourceNode = audioContext.createBufferSource(); // 創建AnalyserNode 用于分析音頻頻譜的節點 var analyser = audioContext.createAnalyser(); //fftSize (Fast Fourier Transform) 是快速傅里葉變換,一般情況下是固定值2048。具體作用是什么我也不太清除,但是經過研究,這個值可以決定音頻頻譜的密集程度。值大了,頻譜就松散,值小就密集。 analyser.fftSize = 256; // 連接節點,audioContext.destination是音頻要最終輸出的目標, // 我們可以把它理解為聲卡。所以所有節點中的最后一個節點應該再 // 連接到audioContext.destination才能聽到聲音。 audioBufferSourceNode.connect(analyser); analyser.connect(audioContext.destination); console.log(audioContext.destination) // 播放音頻 audioBufferSourceNode.buffer = buffer; //回調函數傳入的參數 audioBufferSourceNode.start(); //部分瀏覽器是noteOn()函數,用法相同 //可視化 創建數據 // var dataArray = new Uint8Array(analyser.fftSize); // analyser.getByteFrequencyData(dataArray)//將數據放入數組,用來進行頻譜的可視化繪制 // console.log(analyser.getByteFrequencyData) var bufferLength = analyser.frequencyBinCount; console.log(bufferLength); var dataArray = new Uint8Array(bufferLength); console.log(dataArray) canvasCtx.clearRect(0, 0, 500, 500); function draw() { drawVisual = requestAnimationFrame(draw); analyser.getByteFrequencyData(dataArray); canvasCtx.fillStyle = 'rgb(0, 0, 0)'; //canvasCtx.fillStyle = ; canvasCtx.fillRect(0, 0, 500, 500); var barWidth = (500 / bufferLength) * 2.5; var barHeight; var x = 0; for(var i = 0; i < bufferLength; i++) { barHeight = dataArray[i]; //隨機數0-255 Math.floor(Math.random()*255) // 隨機數 10*Math.random() canvasCtx.fillStyle = 'rgb(' + (barHeight+100) + ','+Math.floor(Math.random()*(20- 120) + 120)+','+Math.floor(Math.random()*(10 - 50) + 50)+')'; canvasCtx.fillRect(x,500-barHeight/2,barWidth,barHeight/2); x += barWidth + 1; } }; draw(); }); } }) </script> </html>
關于基于Web Audio API實現音頻可視化效果的方法就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。