一文詳解Web Audi 繪制音頻圖譜
背景
前端處理音頻,目前一些開源的插件和js庫已經(jīng)提供了非常好的支持。其中小編了解的比較多的是sound.js和wavasuffer.js這倆個庫。其中sound.js是一個大而全的音頻處理庫,功能豐富,兼容性也處理的很好。wavesuffer則偏重于音頻波形圖繪制處理,相對比較輕量。小編此篇不在于比較二者的差異,而是和大家一起學習下如何自己實現(xiàn)一個簡易的音頻圖譜繪制。
實現(xiàn)思路
先介紹下小編的整體思路吧。所謂的音頻圖譜,其實只是將聲音的響度具象化為一個波形圖,響度高對應的波形高,響度低波形也就低。所以第一步,我們可以通過xhr拿到一個音頻文件的數(shù)據(jù)。那么,第二步便是如何處理這組數(shù)據(jù),讓數(shù)據(jù)能夠比較真實的反應音頻的響度。這時候就需要前端的Web Audio Api來發(fā)揮作用了,具體如何處理,我們后面詳細說明。完成數(shù)據(jù)處理之后,最后一步就是需要根據(jù)數(shù)據(jù)繪制出波形圖,這里我們使用canvas來做波形圖的繪制。
獲取音頻文件
首先,我們利用fetch,來獲取一個線上音頻。這里,我們借用一下wavesuffer官網(wǎng)demo中用的線上音頻來做示范。
// 音頻url let audioUrl = 'https://wavesurfer-js.org/example/media/demo.wav'; // 創(chuàng)建音頻上下文 let audioCtx = new (window.AudioContext || window.webkitAudioContext)(); // 創(chuàng)建音頻源 let source = audioCtx.createBufferSource(); /* * 通過fetch下載音頻,responseType設置為'arrayBuffer',我們以arrayBuffer格式接收返回的數(shù)據(jù) */ fetch(audioUrl, { method: 'GET', responseType: 'arraybuffer', }).then(res => { return res.arrayBuffer(); }).then(data => { // 處理音頻數(shù)據(jù) initAudio(data); });
利用Web Audio Api 處理音頻數(shù)據(jù)
拿到音頻數(shù)據(jù)之后,我們需要利用Web Audio Api,來處理音頻數(shù)據(jù),實現(xiàn)音頻的播放,暫停等操作以及我們后續(xù)的波形圖繪制。這里簡單介紹下,Web Audio Api是一組非常強大的Api,它提供了在Web中控制音頻、處理音頻的一整套有效通用的系統(tǒng)。它能夠允許開發(fā)著,控制音頻,自選音頻源、對音頻添加特效,使音頻可視化,添加空間效果,添加混響等等。而我們今天要實現(xiàn)的功能,僅僅只用到了其中幾個Api,整體流程如下:
// audio 初始化 function initAudio (data) { // 音頻數(shù)據(jù)解碼 // decodeAudioData方法接收一個arrayBuffer數(shù)據(jù)作為參數(shù),這也是為什么前面fetch音頻時設置以arrayBuffer格式接收數(shù)據(jù) audioCtx.decodeAudioData(data).then(buffer => { // decodeAudioData解碼完成后,返回一個AudioBuffer對象 // 繪制音頻波形圖 drawWave(buffer); // 連接音頻源 source.buffer = buffer; source.connect(audioCtx.destination); // 音頻數(shù)據(jù)處理完畢 alert('音頻數(shù)據(jù)處理完畢!'); }); } // web audio 規(guī)范不允許音頻自動播放,需要用戶觸發(fā)頁面事件來觸發(fā)播放,這里我們增加一個播放按鈕,數(shù)據(jù)處理完畢后點擊播放 document.querySelector('#btn').onclick = () => { // 播放音頻 source.start(0); }
通過解碼后的音頻數(shù)據(jù),繪制波形圖
音頻數(shù)據(jù)通過AudioContext解碼后,返回一個AudioBuffer對象,這個對象,保存有音頻的采樣率、聲道、pcm數(shù)據(jù)等信息。通過getChannelData方法可以獲取到音頻某個聲道的pcm數(shù)據(jù)。返回的是一個Float32Array對象,數(shù)值范圍在-1到1之間。音頻數(shù)據(jù)比較龐大,每一秒鐘可能包含成千上萬的數(shù)據(jù),因此我們在做圖形繪制時,需要對數(shù)據(jù)進一步采樣。比如,這里我們采用每1000條數(shù)據(jù)中,取一個最大值(正數(shù))一個最小值(負數(shù))來繪制圖形;
// 繪制波形圖 function drawWave (buffer) { // buffer.numberOfChannels返回音頻的通道數(shù)量,1即為單聲道,2代表雙聲道。這里我們只取一條通道的數(shù)據(jù) let data = []; let originData = buffer.getChannelData(0); // 存儲所有的正數(shù)據(jù) let positives = []; // 存儲所有的負數(shù)據(jù) let negatives = []; // 先每隔100條數(shù)據(jù)取1條 for (let i = 0; i < originData.length; i += 100) { data.push(originData[i]); } // 再從data中每10條取一個最大值一個最小值 for (let j = 0, len = parseInt(data.length / 10); j < len; j++) { let temp = data.slice(j * 10, (j + 1) * 10); positives.push(Math.max.apply(null, temp)); negatives.push(Math.min.apply(null, temp)); } // 創(chuàng)建canvas上下文 let canvas = document.querySelector('#canvas'); if (canvas.getContext) { let ctx = canvas.getContext('2d'); canvas.width = positives.length; let x = 0; let y = 100; let offset = 0; ctx.fillStyle = '#fa541c'; ctx.beginPath(); ctx.moveTo(x, y); // canvas高度200,橫坐標在canvas中點100px的位置,橫坐標上方繪制正數(shù)據(jù),下方繪制負數(shù)據(jù) // 先從左往右繪制正數(shù)據(jù) // x + 0.5是為了解決canvas 1像素線條模糊的問題 for (let k = 0; k < positives.length; k++) { ctx.lineTo(x + k + 0.5, y - (100 * positives[k])); } // 再從右往左繪制負數(shù)據(jù) for (let l = negatives.length - 1; l >= 0; l--) { ctx.lineTo(x + l + 0.5, y + (100 * Math.abs(negatives[l]))); } // 填充圖形 ctx.fill(); } };
這樣,簡單的音頻波形圖繪制就完成了。小編這里僅做拋磚引玉,簡單介紹下Web Audio的一個應用場景。更多更復雜的應用,大家可以深入了解學習Web Audio相關api。最后,貼一下效果圖:
以上就是一文詳解Web Audi 繪制音頻圖譜的詳細內(nèi)容,更多關于Web Audio繪制音頻圖譜的資料請關注腳本之家其它相關文章!
相關文章
基于JS實現(xiàn)導航條之調(diào)用網(wǎng)頁助手小精靈的方法
在網(wǎng)站中加入網(wǎng)頁助手小精靈,當用戶訪問網(wǎng)站時,向用戶問好,或是傳遞一些網(wǎng)站的重要信息,給用戶帶來極好的體驗感,那么基于js代碼是如何調(diào)用網(wǎng)頁助手小精靈的呢?下面跟著腳本之家小編一起學習吧2016-06-06使用?Angular?服務器端渲染?Transfer?State?Service
這篇文章主要介紹了使用?Angular?服務器端渲染?Transfer?State?Service,假設我們使用?Angular?Universal?開發(fā)一個服務器端渲染的?Angular?應用,這個應用會消費一個第三方的?Restful?API2022-06-06javascript設計模式之Adapter模式【適配器模式】實現(xiàn)方法示例
這篇文章主要介紹了javascript設計模式之Adapter模式,結(jié)合實例形式分析了JS適配器模式的原理與具體實現(xiàn)方法,具有一定參考借鑒價值,需要的朋友可以參考下2017-01-01