多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內(nèi)最全I(xiàn)T社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > web前端 > htmlcss > 使用HTML5 API(AudioContext)實(shí)現(xiàn)可視化頻譜效果

使用HTML5 API(AudioContext)實(shí)現(xiàn)可視化頻譜效果

來源:程序員人生   發(fā)布時(shí)間:2015-05-12 09:41:33 閱讀次數(shù):12252次

HTML5 可視化頻譜效果


如今的HTML5技術(shù)正讓網(wǎng)頁變得愈來愈強(qiáng)大,通過其Canvas標(biāo)簽與AudioContext對象可以輕松實(shí)現(xiàn)之前在Flash或Native App中才能實(shí)現(xiàn)的頻譜唆使器的功能。

Demo: Cyandev Works - HTML5 Audio Visualizing

開始使用AudioContext

The AudioContext interface represents an audio-processing graph built from audio modules linked together, each represented by an AudioNode.

根據(jù)MDN的文檔,AudioContext是1個(gè)專門用于音頻處理的接口,并且工作原理是將AudioContext創(chuàng)建出來的各種節(jié)點(diǎn)(AudioNode)相互連接,音頻數(shù)據(jù)流經(jīng)這些節(jié)點(diǎn)并作出相應(yīng)處理。

創(chuàng)建AudioContext對象

由于閱讀器兼容性問題,我們需要為不同閱讀器配置AudioContext,在這里我們可以用下面這個(gè)表達(dá)式來統(tǒng)1對AudioContext的訪問。

var AudioContext = window.AudioContext || window.webkitAudioContext; var audioContext = new AudioContext(); //實(shí)例化AudioContext對象

附. 閱讀器兼容性

閱讀器 Chrome Firefox IE Opera Safari
支持版本 10.0 25.0 不支持 15.0 6.0

固然,如果閱讀器不支持的話,我們也沒有辦法,用IE的人們我想也不需要這些效果。但最好實(shí)踐是使用的時(shí)候判斷1下上面聲明的變量是不是為空,然后再做其他操作。

解碼音頻文件

讀取到的音頻文件是2進(jìn)制類型,我們需要讓AudioContext先對其解碼,然后再進(jìn)行后續(xù)操作。

audioContext.decodeAudioData(binary, function(buffer) { ... });

方法decodeAudioData被調(diào)用后,閱讀器將開始解碼音頻文件,這需要1定時(shí)間,我們應(yīng)當(dāng)讓用戶知道閱讀器正在解碼,解碼成功后會調(diào)用傳進(jìn)去的回調(diào)函數(shù),decodeAudioData還有第3個(gè)可選參數(shù)是在解碼失敗時(shí)調(diào)用的,我們這里就先不實(shí)現(xiàn)了。

創(chuàng)建音頻處理節(jié)點(diǎn)

這是最關(guān)鍵的1步,我們需要兩個(gè)音頻節(jié)點(diǎn):

  • AudioBufferSourceNode
  • AnalyserNode

前者是用于播放解碼出來的buffer的節(jié)點(diǎn),而后者是用于分析音頻頻譜的節(jié)點(diǎn),兩個(gè)節(jié)點(diǎn)順次連接就可以完成我們的工作。

創(chuàng)建AudioBufferSourceNode

var audioBufferSourceNode; audioBufferSourceNode = audioContext.createBufferSource();

創(chuàng)建AnalyserNode

var analyser; analyser = audioContext.createAnalyser(); analyser.fftSize = 256;

上面的fftSize是用于肯定FFT大小的屬性,那FFT是甚么高3的博主還不知道,其實(shí)也不需要知道,總之最后獲得到的數(shù)組長度應(yīng)當(dāng)是fftSize值的1半,還應(yīng)當(dāng)保證它是以2為底的冪。

連接節(jié)點(diǎn)

audioBufferSourceNode.connect(analyser); analyser.connect(audioContext.destination);

上面的audioContext.destination是音頻要終究輸出的目標(biāo),我們可以把它理解為聲卡。所以所有節(jié)點(diǎn)中的最后1個(gè)節(jié)點(diǎn)應(yīng)當(dāng)再連接到audioContext.destination才能聽到聲音。

播放音頻

所有工作就緒,在解碼終了時(shí)調(diào)用的回調(diào)函數(shù)中我們就能夠開始播放了。

audioBufferSourceNode.buffer = buffer; //回調(diào)函數(shù)傳入的參數(shù) audioBufferSourceNode.start(0); //部份閱讀器是noteOn()函數(shù),用法相同

參數(shù)代表播放出發(fā)點(diǎn),我們這里設(shè)置為0意味著從頭播放。

文件讀取

HTML5支持文件選擇、讀取的特性,我們利用這個(gè)特性可以實(shí)現(xiàn)不上傳,即播放的功能。


HTML標(biāo)簽

在你的頁面中找個(gè)位置插入:

<input id="fileChooser" type="file" />

Js邏輯

var file; var fileChooser = document.getElementById('fileChooser'); fileChooser.onchange = function() { if (fileChooser.files[0]) { file = fileChooser.files[0]; // Do something with 'file'... } }

使用FileReader異步讀取文件

var fileContent; var fileReader = new FileReader(); fileReader.onload = function(e) { fileContent = e.target.result; // Do something with 'fileContent'... } fileReader.readAsArrayBuffer(file);

其實(shí)這里的fileContent就是上面AudioContext要解碼的那個(gè)binary,至此兩部份的工作就能夠連起來了。

WARNING:

Chrome或Firefox閱讀器的跨域訪問限制會使FileReader在本地失效,Chrome用戶可在調(diào)試時(shí)添加命令行參數(shù):

chrome.exe --disable-web-security

Canvas繪制頻譜

這1部份我不打算詳細(xì)敘述,就提幾個(gè)重點(diǎn)。

AnalyserNode數(shù)據(jù)解析

在繪制之前通過下面的方法獲得到AnalyserNode分析的數(shù)據(jù):

var dataArray = new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(dataArray);

數(shù)組中每一個(gè)元素是從0到fftSize屬性值的數(shù)值,這樣我們通過1定比例就可以控制能量條的高度等狀態(tài)。

requestAnimationFrame的使用

要使動畫動起來,我們需要不斷重繪Canvas標(biāo)簽里的內(nèi)容,這就需要requestAnimationFrame這個(gè)函數(shù)了,它可以幫你以60fps的幀率繪制動畫。

使用方法:

var draw = function() { // ... window.requestAnimationFrame(draw); } window.requestAnimationFrame(draw);

這段代碼應(yīng)當(dāng)不難理解,就是1個(gè)類似遞歸的調(diào)用,但不是遞歸,有點(diǎn)像Android中的postInvalidate

實(shí)例代碼

貼上我寫的1段繪制代碼:

var render = function() { ctx = canvas.getContext("2d"); ctx.strokeStyle = "#00d0ff"; ctx.lineWidth = 2; ctx.clearRect(0, 0, canvas.width, canvas.height); //清算畫布 var dataArray = new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(dataArray); var step = Math.round(dataArray.length / 60); //采樣步長 for (var i = 0; i < 40; i++) { var energy = (dataArray[step * i] / 256.0) * 50; for (var j = 0; j < energy; j++) { ctx.beginPath(); ctx.moveTo(20 * i + 2, 200 + 4 * j); ctx.lineTo(20 * (i + 1) - 2, 200 + 4 * j); ctx.stroke(); ctx.beginPath(); ctx.moveTo(20 * i + 2, 200 - 4 * j); ctx.lineTo(20 * (i + 1) - 2, 200 - 4 * j); ctx.stroke(); } ctx.beginPath(); ctx.moveTo(20 * i + 2, 200); ctx.lineTo(20 * (i + 1) - 2, 200); ctx.stroke(); } window.requestAnimationFrame(render); }

OK,大致就是這樣,以后可以加1些css樣式,完善1下業(yè)務(wù)邏輯,這里就不再闡釋了。最后貼上整理好的全部代碼:

HTML 部份

<html> <head> <title>HTML5 Audio Visualizing</title> <style type="text/css"> body { background-color: #222222 } input { color: #ffffff } #wrapper { display: table; width: 100%; height: 100%; } #wrapper-inner { display: table-cell; vertical-align: middle; padding-left: 25%; padding-right: 25%; } #tip { color: #fff; opacity: 0; transition: opacity 1s; -moz-transition: opacity 1s; -webkit-transition: opacity 1s; -o-transition: opacity 1s; } #tip.show { opacity: 1 } </style> <script type="text/javascript" src="./index.js"></script> </head> <body> <div id="wrapper"> <div id="wrapper-inner"> <p id="tip">Decoding...</p> <input id="fileChooser" type="file" /> <br> <canvas id="visualizer" width="800" height="400">Your browser does not support Canvas tag.</canvas> </div> </div> </body> </html>

Js部份

var AudioContext = window.AudioContext || window.webkitAudioContext; //Cross browser variant. var canvas, ctx; var audioContext; var file; var fileContent; var audioBufferSourceNode; var analyser; var loadFile = function() { var fileReader = new FileReader(); fileReader.onload = function(e) { fileContent = e.target.result; decodecFile(); } fileReader.readAsArrayBuffer(file); } var decodecFile = function() { audioContext.decodeAudioData(fileContent, function(buffer) { start(buffer); }); } var start = function(buffer) { if(audioBufferSourceNode) { audioBufferSourceNode.stop(); } audioBufferSourceNode = audioContext.createBufferSource(); audioBufferSourceNode.connect(analyser); analyser.connect(audioContext.destination); audioBufferSourceNode.buffer = buffer; audioBufferSourceNode.start(0); showTip(false); window.requestAnimationFrame(render); //先判斷是不是已調(diào)用1次 } var showTip = function(show) { var tip = document.getElementById('tip'); if (show) { tip.className = "show"; } else { tip.className = ""; } } var render = function() { ctx = canvas.getContext("2d"); ctx.strokeStyle = "#00d0ff"; ctx.lineWidth = 2; ctx.clearRect(0, 0, canvas.width, canvas.height); var dataArray = new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(dataArray); var step = Math.round(dataArray.length / 60); for (var i = 0; i < 40; i++) { var energy = (dataArray[step * i] / 256.0) * 50; for (var j = 0; j < energy; j++) { ctx.beginPath(); ctx.moveTo(20 * i + 2, 200 + 4 * j); ctx.lineTo(20 * (i + 1) - 2, 200 + 4 * j); ctx.stroke(); ctx.beginPath(); ctx.moveTo(20 * i + 2, 200 - 4 * j); ctx.lineTo(20 * (i + 1) - 2, 200 - 4 * j); ctx.stroke(); } ctx.beginPath(); ctx.moveTo(20 * i + 2, 200); ctx.lineTo(20 * (i + 1) - 2, 200); ctx.stroke(); } window.requestAnimationFrame(render); } window.onload = function() { audioContext = new AudioContext(); analyser = audioContext.createAnalyser(); analyser.fftSize = 256; var fileChooser = document.getElementById('fileChooser'); fileChooser.onchange = function() { if (fileChooser.files[0]) { file = fileChooser.files[0]; showTip(true); loadFile(); } } canvas = document.getElementById('visualizer'); }

以上。

生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: tube日本xxxx69| 欧美精品在线免费 | 女啪啪www女高清 | 国产狂喷白浆在线观看视频 | 亚洲欧洲高清有无 | 日本理论在线观看被窝网 | 国产成人一区二区三区影院免费 | 亚洲自拍偷拍专区 | 欧美二区在线观看 | a天堂中文在线 | 国产性生交xxxxx免费 | 欧美操片 | 国产福利一区二区三区视频在线 | 日韩国产欧美成人一区二区影院 | 东京干手机福利视频 | 午夜影院啪啪 | 日韩国产欧美精品综合二区 | 97成人在线观看 | 一级毛片在线不卡直接观看 | 亚洲逼| 国产精品人成 | www视频在线观看com | 在线观看麻豆精品国产不卡 | 国产成人综合日韩精品无 | 国产成人精品日本亚洲直接 | 一级做a级爰片性色毛片视频 | 美女免费网站在线视频 | 波多野结衣视频免费 | 在线偷拍自拍 | 久久久久久一级毛片免费野外 | xx性欧美高清| 亚洲 欧美 小说 | 国产成人啪一区二区 | 精品无码中出一区二区 | 国产精品一区伦免视频播放 | 亚洲天堂中文字幕在线观看 | 日韩久久中文字幕 | h网站在线免费观看 | 在线看黄色网址 | 精品亚洲综合在线第一区 | 毛片一级在线 |