前陣子在兩廳院駐館的呈現中,我們嘗試使用網頁讀入環境的聲音,做為控制、觸發作品走向的條件。今天就來分享從網頁使用 Javascript 讀取麥克風聲音的簡單概念吧!
網頁難道一直在收音嗎?
回想一下,當你打開新下載的 APP ,有時會跳出「是否同意使用相簿」、「是否同意使用行事曆」或「是否同意使用麥克風」等各種詢問視窗。對網頁而言亦是如此:故事的起頭得從要求權限開始。
首先使用 WebRTC(Web Real-Time Communication)中的 API getUserMedia()
要求使用用戶裝置的音訊。在用戶點選同意後,API 會回傳一筆麥克風的資料(stream)。
const handleMic = (stream) => {
// handle stream here
}
navigator.mediaDevices.getUserMedia({audio: true}).then(handleMic);
得到麥克風的資料以後,再使用 Web Audio API 來處理資料。
在網頁蓋一個聲音工廠
Web Audio API 是一套幫助開發者在網頁上操作與處理音訊的程式介面。要使用 Web Audio API,必須先創建一個 AudioContext。AudioContext 就像一座聲音工廠,這座工廠中有多個單位或設備協力產出目標產品(聲音或相關資料)。
// global variable
let AudioContext = window.AudioContext||window.webkitAudioContext;
let context = new AudioContext();
創立了聲音工廠(AudioContext)後,可以選擇適合的單位或設備,並因應需求設計操作與執行的步驟。在 Web Audio API 裡,每個單位及設備被稱作一個 AudioNode。由於今天的目的是讀取麥克風資料,我們使用 createMediaStreamSource()
和 createAnalyser()
得到兩個需要的工廠單位(AudioContext): MediaStreamAudioSourceNode 和 AnalyserNode。
// in Handle Mic function
microphone = context.createMediaStreamSource(stream);
analyser = context.createAnalyser();
其中,MediaStreamAudioSourceNode 是個音訊來源。在聲音工廠中,它負責接收工廠外部的物料,再將物料(音訊)傳遞給後續處理的單位。而 AnalyserNode 主責分析,它不改造與加工音訊,但能分析音訊、提供相關數據。
創造出工廠單位後,接著使用 connect()
函式建立溝通管道——讓接收物料的窗口把音訊傳遞給分析單位。
microphone.connect(analyser);
做到這裡,聲音工廠的大致架構就完成了!目前有了一個小工廠,單位部門、工作流程都設計妥當。除了還不會發生任何事。
所以我說那個數據呢?
最後階段是跟分析單位(AnalyserNode)要資料。AnalyserNode 可以提供即時的時域(time-domain)和頻域(frequency-domain)數據。
在得到數據以前,我們需要先給定 AnalyserNode 的 fftSize。由於 fftSize 牽涉到域轉頻域的數學運算,這裡不多做解釋。只要先記得 fftSize 需要設定成 2 的倍數,數字越大,代表頻域的數據被切分得越細。選定 fftSize 後,創造一個長度為 frequencyBinCount (frequencyBinCount 是 fftSize 數量的一半)、空的 Uint8 陣列,作為未來讀取數據的容器。
接著,如果需要時域數據,可以使用:
analyser.getByteTimeDomainData(dataArray);
得到 dataArray 陣列中存著各個 frame 的音訊數值。
或在需要頻域時使用:
analyser.getByteFrequencyData(dataArray);
將各頻率區間的數值大小存入 dataArray 陣列。
如此一來,音訊數據到手,除了可以應用在視覺化上,也可以從陣列中提取其他資訊(音量、頻率⋯⋯)啦!更多 AnalyserNode 介紹可以參考:WebAudioApi Analysis and Visualization
還找不到稱呼自己的方式,暫時歸類為文字工作者——多數時候只寫給機器看。
在〈【創意科技】使用網頁來讀取手機的麥克風聲音〉中有 1 則留言
太酷了,老師好,我是去年在清大修你的msp程式設計的理鈞,剛好最近在爬文怎麼用網頁做音訊方面的處理,找到這裡發現居然在讀老師的文(?教學風格真的太友善了好好懂~~謝謝老師