網頁取樣機的使用者編完卡帶之後,需要一個能帶走、能上傳、能放進剪輯軟體的 MP3。這份檔案由編曲引擎在瀏覽器內直接算出,不經過伺服器混音,也不錄製即時播放的聲音。本文依序說明算繪、後處理、編碼、兩種輸出與取樣檔的時間軸。即時播放用的排程與時鐘另見 取樣機的拍點時鐘設計,這裡只談輸出。
輸出改用離線算繪,不錄製即時播放
錄製即時播放的聲音,輸出要等整首播完,所需時間等於作品長度;手機切換應用程式時,音訊也可能暫停。
離線算繪不必等待播放,也不依賴播放當下的裝置狀態。W3C 的 Web Audio API 規格中,OfflineAudioContext 的時間軸不與即時播放時鐘綁定,結果寫進一個 AudioBuffer;MDN 的說明說明這個介面不輸出到裝置硬體,而是盡可能快地產生結果,寫進 AudioBuffer。每個音符的位置由排程時間決定,與播放當下的瀏覽器狀態無關。
- 卡帶資料4 個序列、12 個音色格
- 離線算繪重建音訊圖,依序列、音色格、步數排程
- 整包後處理Limiter 與整體降 3 dB
- 轉為單聲道取得 Float32 取樣點
- MP3 編碼192 kbps,每次 1152 個取樣點
流程依輸出整包完整音檔的路徑繪製。
用同一份卡帶資料重建音訊圖
編曲資料是 4 個序列,每個序列有 12 個音色格,每格 32 個步;一步是一個 8 分音符,一小節 8 步,所以 32 步等於 4 小節。每個序列各自設定 1 到 4 小節的 loop 長度。即時播放與離線算繪讀的是同一份序列、音色格與步資料。
輸出時呼叫 Tone.js 的 Tone.Offline,傳入一個回呼函式與總長度(秒)。回呼在獨立的離線環境裡執行,音訊圖要在裡面重建:每個有資料的音色格建立一個 player,接上 PitchShift 與 Filter,再接到全域處理的輸入或主通道。
排程只用一次 transport.scheduleOnce,時間點是 0:0:0。回呼裡用序列、音色格、步數三層迴圈,對每個啟用的步直接呼叫 player.start,並在同一時間點設定音量。第 N 個序列的起點,是前面 N-1 個序列的長度總和,四個序列因此依序排成一條連續的時間軸。
總長度由四個序列的 loop 長度與 BPM 算出:每個序列的秒數是 loop 小節數 × 8 × (60 ÷ BPM ÷ 2)。BPM 預設 120,此時一步 0.25 秒,一小節 2 秒;四個序列各設 2 小節,總長就是 16 秒。輸出長度只取決於 loop 長度與 BPM,與放了幾個音無關。

整包輸出前的處理與單聲道
整包輸出時,全域處理鏈的輸出會先經過 Limiter,門檻 -1 dB,整體再降 3 dB,為多個音色同時發聲時的疊加留出餘量。處理完成後,取得的 AudioBuffer 轉成單聲道,交給編碼器。
MP3 編碼:lamejs、192 kbps 與 1152 個取樣點
編碼用 lamejs,這是能在瀏覽器內執行的 MP3 編碼器,建立方式是 Mp3Encoder(聲道數, 取樣率, kbps)。聲道數與取樣率直接取自算繪出來的 buffer,位元率設為 192 kbps。
編碼分區塊進行。MIT Media Lab 的 MPEG Audio FAQ說明 Layer III 把聲音切成 1152 個取樣點的區塊,這是二手整理,不是 ISO 原文。lamejs 的 README 範例同樣取 1152,註解說明區塊大小可以任意,取 576 的倍數對編碼器較省力。這套編曲引擎每次餵給編碼器 1152 個取樣點。
Web Audio 的取樣點是 -1 到 1 之間的浮點數,編碼器吃的是 16 位元整數。轉換時先把每個值夾在 -1 到 1 之間,負值乘 32768,正值乘 32767,剛好對應 int16 的範圍 -32768 到 32767,不會溢位。
| 項目 | 設定 |
|---|---|
| 算繪 | Tone.Offline,總長由 loop 長度與 BPM 算出 |
| 聲道 | 單聲道 |
| 編碼器 | lamejs 的 Mp3Encoder |
| 位元率 | 192 kbps |
| 每次編碼 | 1152 個取樣點 |
| 浮點轉整數 | 夾在 -1 到 1,負值乘 32768、正值乘 32767 |
| 輸出型別 | Blob,audio/mp3 |
兩種輸出:完整音檔與各音色 ZIP
輸出視窗提供兩種結果。完整音檔是整首卡帶混成的單一 MP3;各音色 ZIP 則把每個音色各自算繪,再打包成壓縮檔,每個音色可以單獨取用。
- 卡帶完成編排尚未編排時先顯示提示
- 要一份完整的成品單一 MP3整包算繪,下載到使用者的裝置
- 要在剪輯軟體裡逐音色調整各音色 ZIP每個音色各算繪一次,打包成 download.zip
- 公開卡帶上傳完整音檔上限 20 MB,只收 MP3
各音色 ZIP 的做法如下。
- 12 個音色格逐一檢查,有取樣、且四個序列中至少有一步落在 loop 範圍內的格子才輸出。
- 每個音色格各跑一次 Tone.Offline,同樣取單聲道、同樣以 lamejs 編碼。
- 檔名依格子編號為 sample-0.mp3 到 sample-11.mp3,用 JSZip 打包成 download.zip 下載。
公開卡帶前,系統會要求先輸出一份完整音檔並上傳。檔案以表單送到後端,後端只收 MP3,大小上限 20 MB,成功後回傳檔案網址;前端把網址與輸出時間記進卡帶資料。

取樣檔的時間軸
MP3 以固定長度的 frame 編碼,多數編碼器會在檔案開頭加入一段延遲,不同軟體輸出的延遲長度也不相同。播放端若沒有補償,檔案開頭就多出一小段靜音。單次播放聽不出差異,但取樣在序列中循環時,每一圈都從頭開始,起點與拍點之間的偏移固定存在,多個音色同時發聲時,拍點就對不齊。
取樣機的做法是在上傳時處理。使用者上傳的 MP3 與 WAV,後端先轉成未壓縮的 AIFF,再用同一條流程轉成 MP3。所有取樣都由同一個編碼流程輸出,開頭的延遲不再隨來源軟體改變。前端不必逐檔偵測開頭的靜音長度,也不必替各軟體的差異各寫一套補償。
輸出前的提示
公開卡帶前必須先輸出完整音檔。卡帶尚未編排任何步時,輸出視窗會顯示「尚無打擊音樂,無法輸出音檔」,並提供「如何打擊」的入口,引導使用者先完成編排。
不適合離線算繪的情境
OfflineAudioContext 建立時就要指定長度,整段結果存放在記憶體裡。需要即時錄下麥克風或外接樂器的輸入,或是輸出長度事先未知的場景,改用錄製路線較合適。長度由 loop 與 BPM 決定的卡帶輸出,則符合離線算繪的前提。
延伸閱讀與官方教學影片
取樣機的整體做法與使用情境,見 北流雲取樣機案例;即時播放的拍點排程見 網頁步進編曲的時鐘設計。
輸出與取樣的操作示範,可看官方教學影片:3-2 卡帶編輯與輸出、2-1 錄製音色取樣。
網頁上需要音訊算繪、匯出或取樣功能,可從 網頁互動功能開發 了解範圍,並透過 說明網頁音訊功能的需求 與開發團隊聯繫。




