前言
自從上次在趣講CDN一文中講了一個"傳東奶"的故事之後,就再也沒有發過部落格。或許有些朋友還以為我們被抓了呢,哈哈哈~
很久以前,趙忠祥老師就告訴我們,雨季,是個好時節。雨季來了,春暖花開,萬物復甦,又到了大草原上程式猿們XX的季節。好吧,扯遠了。說到底,就是團隊中的小哥哥小姐姐都忙著談戀愛,都沒時間寫部落格了。
獲取音訊的時長
有這樣的一個需求,上傳一個音訊檔案,同時獲取其大小及時長。
常規方法
這很簡單,使用記憶中的那些方法,寫出下面的程式碼:
function getAudioDuration(url) {
const audio = document.createElement('audio');
audio.src = url;
audio.addEventListener("canplay", function () {
console.log(audio.duration);
});
}
const file = document.getElementById('file');
file.addEventListener('change', (e) => {
const file = e.target.files[0];
console.log(file.size);
getAudioDuration(URL.createObjectURL(file));
})
複製程式碼
當我擼完上面這段程式碼的時候,回想起總工的批判:這方案太簡單了。菊花一緊,嚇得我趕緊找找其他的方案。
ArrayBuffer
在電腦中,當我們選中一個MP3檔案的時候,通常可以看到一些元資訊,比如播放時長、取樣速率等。既然如此,我們是否可以通過讀取二進位制資料來獲取對應的資訊呢?
在查詢相關資料之後,發現了decodeAudioData這個API可以滿足我們的需求,於是有了下面的方案。
function getAudioDurationByAudioApi(file) {
const fileReader = new FileReader();
const audioContext = new AudioContext();
fileReader.readAsArrayBuffer(file);
fileReader.onload = () => {
audioContext.decodeAudioData(fileReader.result, (result) => {
console.log(result);
});
}
}
const file = document.getElementById('file');
file.addEventListener('change', (e) => {
const file = e.target.files[0];
console.log(file.size);
getAudioDurationByAudioApi(file);
})
複製程式碼
被忽略的Web Audio API
通過以上的探索,發現了一直被我忽略的Web Audio API。以往在處理音訊相關的需求,大多是通過audio標籤,播放一段音訊,很簡單。所以也就沒有關注到早已存在的Audio API。
舉個例子
實際應用一下,舉個簡單的播放音訊栗子:
function playAudio(file) {
const fileReader = new FileReader();
const audioContext = new AudioContext();
fileReader.readAsArrayBuffer(file);
fileReader.onload = () => {
audioContext.decodeAudioData(fileReader.result, (result) => {
//建立播放源
const source = audioContext.createBufferSource();
source.buffer = result;
//連線輸出終端
source.connect(audioContext.destination);
//開始播放
source.start();
});
}
};
const file = document.getElementById('file');
file.addEventListener('change', (e) => {
playAudio(e.target.files[0]);
});
複製程式碼
以上例子簡單使用相關的API進行了音訊的播放,分析一下關鍵的程式碼。
AudioContext
直接翻譯,就是"音訊上下文"。類似於canvas中的context。其中包含了一系列用來操作音訊的API。
上面的程式碼中,通過const audioContext = new AudioContext();建立了一個AudioContext物件,於是我們就可以進行各種各樣的操作。
建立播放源
上面的例子中,我們通過AudioContext.createBufferSource()建立了播放源。除此之外,我們還可以使用其他的資料作為播放源:
- AudioContext.createOscillator()
- AudioContext.createBuffer()
- AudioContext.createMediaElementSource()
- AudioContext.createMediaStreamSource()
具體介紹可點選連結檢視。
連線輸入輸出
我們可以看到,在設定好播放源之後,進行了一個connect操作。這個操作就是將播放源連結到播放終端。
AudioContext的destination屬性返回一個AudioDestinationNode表示context中所有音訊(節點)的最終目標節點,一般是音訊渲染裝置,比如揚聲器。
有趣的玩法
在學習AudioContext相關API的過程中,發現了createAnalyser這個方法。
createAnalyser方法能建立一個AnalyserNode
,可以用來獲取音訊時間和頻率資料,以及實現資料視覺化。
要看看效果吧,demo
以前,需要標識一個音訊正在播放,我們經常會放一個跳動的gif。比如:
是的,這一點都不酷。不禁又回想起總工的那句話:這方案太簡單了。
以後,我們再做這樣的需求的時候,就可以做成跟隨音樂頻率跳動的動畫效果了。
總結
魯迅先生說:"從來如此,便對嗎?"
是啊,我們應該對現有方案多點思考。
以上所述,僅僅只是Web Audio API的冰山一角,還有更多高階的玩法,有興趣的可以檢視相關的文件。
相關文章
@Author:TDGarden