以前恰好看到Web Audio API方面的內容,所以用了相關api作了個音頻可視化的頁面。實現:javascript
Web Audio API中一個關鍵的對象就是音頻上下文(AudioContext),能夠類比canvas context,在AudioContext咱們進行相關的操做。音頻處理的一個典型流程爲:java
<audio>
(HTMLAudioElement), 音頻數據(Ajax 獲取的 AudioBufferSourceNode ), 流(MediaStreamAudioSourceNode)// 1. 建立上下文
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
// 2. 獲取音頻源(MediaElementAudioSourceNode)
// 這裏音頻源可使用 OscillatorNode 建立,也使用麥克風源等
var audioElement = document.querySelector('audio');
var track = audioContext.createMediaElementSource(audioElement);
// ...這裏咱們已經能夠將聲音鏈接到系統揚聲器
// track.connect(audioContext.destination);
// 3. 須要先啓動音頻環境,不然可能會提示須要手勢觸發的警告
// resume() 和 suspend() 返回的都是異步對象,最好使用then等待異步處理結束
if (audioContext.state === 'suspended') {
audioContext.resume();
}
// 4. 播放控制
audioElement.play();
audioElement.pause();
// 5. 聲音控制
const gainNode = audioContext.createGain();
track.connect(gainNode).connect(audioContext.destination);
// 6. 立體聲平移控制
const pannerOptions = { pan: 0 };
const panner = new StereoPannerNode(audioContext, pannerOptions);
// 官網使用構造器方法,可是在Edge中會提示錯誤,可使用如下的工廠方法代替
this.panner = this.audioContext.createStereoPanner();
this.panner.pan.value = 0.0;
// 7. 鏈接到系統揚聲器
track.connect(gainNode).connect(panner).connect(audioContext.destination)
複製代碼
// 1. 建立AnalyserNode對象
var analyser = audioContext.createAnalyser();
// 2. 獲取柱形圖須要的數量,初始化一個dataArray
var bufferLength = analyser.frequencyBinCount;
var dataArray = new Uint8Array(bufferLength);
// 3. 得到繪製輸出
var canvasCtx = canvasElement.getContext('2d');
// 4. 得到 canvas 相關參數
var WIDTH = canvasElement.width;
var HEIGHT = canvasElement.height;
// 5. 定義須要的條形數目,可本身定製
count = dataArray.length;
// 6. 繪製canvas
function draw () {
canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);
analyser.getByteFrequencyData(dataArray);
let value = 0,
step = Math.round(dataArray.length / count), // 得到繪製間隔
x = 0,
y = 0,
lineWidth = canvasCtx.lineWidth = WIDTH / count, // 描邊寬度
index = count;
canvasCtx.strokeStyle = "#fff"; // 描邊顏色
while (index) {
value = dataArray[index * step + step]; // 描邊高度相關
x = index * lineWidth;
y = HEIGHT - value * 1.5;
canvasCtx.beginPath(); // 開始繪製
canvasCtx.moveTo(x, HEIGHT); // 從座標軸x點開始繪製
canvasCtx.lineTo(x, y); // 到須要的高度結束
canvasCtx.stroke();
index -= 2; // 調整繪製間隔
}
requestAnimationFrame(() => draw());
};
複製代碼
function playHandler () {
if (playState === false) {
audioElement.play();
playState = true;
playButton.dataset.playing = 'true';
} else {
audioElement.pause();
playState = false;
playButton.dataset.playing = 'false';
}
}
複製代碼
若是多個音頻關聯到一個 GainNode 對象,切換前注意斷開鏈接 git
咱們經過 audioContext.createMediaElementSource(audioElement)
已經將上下文對象與一個 HTMLAudioElement
對象關聯,咱們後面進行操做能夠經過切換這個媒體對象的src實現(或者從新new一個AudioContext與新的媒體對象關聯,不推薦)github
// 假如咱們以前有這樣的鏈接
function setTrack () {
track.connect(gainNode)
.connect(panner)
.connect(analyser)
.connect(audioContext.destination);
}
// 那麼咱們進行音頻切換時要進行以下操做
function changeAudio (index) {
let idx = index || 0;
if (playList.length <= 0 || idx > playList.length) return;
playState = false;
track && track.disconnect();
gainNode && gainNode.disconnect();
panner && panner.disconnect();
analyser && analyser.disconnect();
audioElement.src = playList[idx].src;
audioElement.load();
_enableControls();
}
複製代碼
AudioContext.currentTime
以雙精度浮點型數字返回硬件調用的秒數 (readonly)AudioContext.state
返回AudioContext當前狀態 (readonly)AnalyserNode.frequencyBinCount
一個無符號長整形 (unsigned long) 的值, 值爲fftSize的一半。這一般等於將要用於可視化的數據值的數量。AudioContext.createMediaElementSource()
建立一個 MediaElementAudioSourceNode 接口來關聯 HTMLMediaElement . 這能夠用來播放和處理來自<video>
或<audio>
元素的音頻AudioContext.resume()
從新啓動一個已被暫停的音頻環境AudioContext.suspend()
暫停音頻內容的進度.暫時中止音頻硬件訪問和減小在過程當中的CPU/電池使用AudioContext.close()
關閉一個音頻環境, 釋聽任何正在使用系統資源的音頻AudioContext.decodeAudioData()
從ArrayBuffer對象中異步解碼音頻文件AudioContext.createGain()
建立一個GainNode,它能夠控制音頻的總音量AudioContext.createPanner()
建立一個PannerNode, 它爲音源建立一個3D音源環境AudioContext.createAnalyser()
建立一個AnalyserNode,它能夠用來顯示音頻時間和頻率的數據AudioContext.createStereoPanner()
建立一個使用立體聲的音頻源 StereoPannerNodeAudioContext.createAnalyser()
建立一個AnalyserNode,能夠用來獲取音頻時間和頻率數據,以及實現數據可視化。AnalyserNode.getByteFrequencyData()
將當前頻域數據拷貝進Uint8Array數組new AudioContext()
|
V
+----------+ +------------+
| running | -- suspend() -> | suspended |
| | <- resume() --- | |
+----------+ +------------+
| |
| close() | close()
+------------------------------+
|
V
+-----------+
| closed |
+-----------+
複製代碼
不兼容IE
項目預覽codepen
項目地址githubweb