WAV 檔案格式
Waveform Audio,一種未壓縮(通常是 PCM)的 RIFF 音訊容器。
- MIME 類型
- audio/wav
- 副檔名
- .wav
- 分類
- 音訊
Magic number(檔案簽章)
| 0x00000000 | 52494646 | RIFF | RIFF container |
| 0x00000008 | 57415645 | WAVE | 'WAVE' form type |
關於 WAV 格式
WAV 把音訊以原始 PCM 取樣存在 RIFF 容器裡,代價是檔案很大,換來的是無損音質與容易編輯 — 這正是錄音與後製的標準格式。標頭是 'RIFF'、長度,接著格式類型 'WAVE'。前四個位元組之後的所有東西都是小端序,而檔案本身是一份扁平的 chunk 清單:四個位元組的 chunk id、四個位元組的大小,然後是那麼多位元組的酬載,並補齊到偶數長度。這種排版就是為什麼 WAV 寫起來輕而易舉、也輕而易舉地錯得很細微:檔案裡沒有任何東西會去對照另一個東西,所以一個跟現實不符的大小欄位,仍然是一個格式完全正確、卻沒有兩個播放器處理方式一致的 WAV。
檔頭結構,一個位元組一個位元組看
| 位移 | 長度 | 欄位 | 意義 |
|---|---|---|---|
| 0 | 4 | RIFF chunk id | ASCII 的 RIFF 四個字母,52 49 46 46。RIFF 是 Microsoft 和 IBM 的通用 Resource Interchange File Format,所以這根本不是 WAV 的標記 — AVI 和 WebP 開頭就是一模一樣的四個位元組。 |
| 4 | 4 | RIFF chunk size | 後面所有東西的位元組數,小端序 32 位元無號整數,也就是檔案長度減八。一段 176478 位元組的錄音這裡會是 56 B1 02 00,也就是 176470。沒有任何東西會強制它正確,而值寫錯是手工寫出來的 WAV 最常見的單一缺陷。 |
| 8 | 4 | WAVE form type | 57 41 56 45。這才是真正說出「這是音訊」的欄位:AVI 這裡是 'AVI ',WebP 是 'WEBP'。一個檢查完位移 0 的 RIFF 就收手的偵測器,分不出這三者。 |
| 12 | 4 | 'fmt ' chunk id | 66 6D 74 20 — 注意尾隨的空格,因為每個 RIFF chunk id 都剛好四個位元組,而 'fmt' 只有三個。這個格式 chunk 是必要的,慣例上排在最前面。 |
| 16 | 4 | fmt chunk size | 純 PCM 是 16,附加了兩位元組的延伸大小時是 18,WAVE_FORMAT_EXTENSIBLE 則是 40。只要不是 16,後面每個 chunk 都會被往後推,這就是為什麼位移 36 不是一個可靠的地標。 |
| 20 | 2 | Audio format code | 1 是未壓縮的 PCM,3 是 32 位元 IEEE 浮點,6 是 A-law,7 是 mu-law,而 FE FF(65534)是 WAVE_FORMAT_EXTENSIBLE — 那種情況下真正的編碼是由格式延伸區裡的一個 GUID 指名的。 |
| 22 | 2 | Channel count | 1 是單聲道、2 是立體聲,更多就是環繞配置。用延伸格式時會有一個聲道遮罩說明每條聲道屬於哪一顆喇叭;純 PCM 的 WAV 什麼都不說,所以聲道順序只是慣例。 |
| 24 | 4 | Sample rate | 每秒的取樣框數,小端序。44100 是 44 AC 00 00,48000 是 80 BB 00 00。這是播放器決定播放速度時唯一會看的欄位。 |
| 28 | 4 | Byte rate | 取樣率乘聲道數乘每取樣位元數再除以八 — 44.1 kHz 立體聲 16 位元就是 176400。它完全可以由周圍那三個欄位推導出來,所以拿來檢查可疑的標頭是免費的一致性檢查。 |
| 32 | 2 | Block align | 每個取樣框的位元組數:聲道數乘每取樣位元數除以八,所以 16 位元立體聲是 4。seek 的算術會用到它,所以值寫錯的話,每一次 seek 都會變成一陣雜訊。 |
| 34 | 2 | Bits per sample | 8、16、24 或 32。8 位元 PCM 是無號的,比它寬的全部是有號的二補數,而這個不連續性專門絆倒從零寫轉檔器的人。 |
| 36 | 4 | Next chunk id | 只有在最精簡的情況下,這裡才是 'data' chunk。編碼器很常先放一個 'LIST' INFO 區塊或一個 'fact' chunk — 某個常見編碼器寫出來的檔案這裡是 4C 49 53 54 — 所以剖析器必須把 chunk 清單走一遍,不能假設位移。 |
| variable | 4 | 'data' chunk size | 緊接在 64 61 74 61 這個 chunk id 之後的四個位元組,給出後面有幾個位元組的取樣資料。因為它是無號 32 位元,這就是 WAV 那個四 GB 硬上限的來源。 |
怎麼跟長得像的格式分開
| 容易搞混的 | 怎麼分 |
|---|---|
| AVI | 前八個位元組完全相同:兩者都是 RIFF 容器,位移 4 都是小端序長度。位移 8 的格式類型決定一切 — 音訊是 57 41 56 45,影片是 41 56 49 20('AVI ' 尾隨一個空格)。天真的「開頭是 RIFF」檢查會把影片檔案報成音訊,踩的就是這個坑。 |
| WebP | RIFF 家族的第三個成員,位移 8 是 57 45 42 50。所以三種毫無關係的媒體類型共用同樣的前八個位元組,只差一個四位元組的字 — 這也是為什麼任何誠實的 RIFF 偵測器都讀十二個位元組而不是四個。 |
| RF64 / BW64 | 超過四 GB 的錄音沒辦法用 32 位元欄位表達自己的長度,所以廣播用的變體把位移 0 的 id 換成 52 46 36 34('RF64')或 42 57 36 34('BW64'),把位移 4 的大小設成 FF FF FF FF,再加一個裝著真正 64 位元大小的 'ds64' chunk。檔案其餘部分就是一般的 WAVE — 這就是為什麼有些播放器打得開它們,有些卻只看到一個壞掉的標頭。 |
| FLAC | 兩者都是無損的,大家也一天到晚拿來比較,但位元組上毫無歧義:原生 FLAC 開頭是 66 4C 61 43('fLaC'),後面接一個 34 位元組的 STREAMINFO 區塊。一個被改名成 .wav 的 FLAC 檔案哪裡都打不開,因為沒有 WAV 讀取端會去掃描格式類型。 |
| MP3 | MP3 根本沒有容器。它的開頭不是一個 'ID3' 標籤,就是直接一個音框同步 — 十一個位元全設,也就是 FF 後面接一個高三位元皆為 1 的位元組。它跟 RIFF 沒有半點相似,而一個開頭是 FF FB 的 .wav,就是一個標錯名字的 MP3。 |
常見的壞法
- 錄音程式當掉或被強制關閉。音訊資料已經在磁碟上了,但那兩個大小欄位 — 位移 4 的 RIFF 大小和 data chunk 的大小 — 還停在錄音開始時寫下的值,常常是零或一個預先配置的長度。於是播放器提早停住,或是越過取樣值一路讀進後面的東西。修法是算術題:用真正的檔案長度把兩個欄位重算一次,檔案就播得好好的。
- 四 GB 上限。兩個大小欄位都是無號 32 位元,所以一段長的多軌或戶外錄音會悄悄繞回去,標頭描述的檔案遠小於磁碟上的那個。RF64、BW64 和 Sony 的 Wave64 存在的唯一目的就是逃出這個限制,而它們沒有一個是單純的 WAV。
- 位元深度跟取樣值對不上。位移 34 說 16,取樣值卻是用 24 位元寫的,於是每一個取樣框的邊界都是錯的,檔案會以大致正確的長度播出一片有節奏的靜電雜訊。標頭本身是合法的;它只是在描述另一批位元組,不是實際存在的那批。
- 少了 chunk 補齊位元組。RIFF 要求奇數長度的 chunk 後面要跟一個補齊位元組,而那個位元組不算進 chunk 大小裡。寫入端忘了它,後面每個 chunk 的位移就都少一,於是讀取端落在 chunk 中間,報出像 'ata' 加一個 NUL 這種亂七八糟的 chunk id。
- 前面被塞了位元組。一頁 HTML 錯誤訊息、一個多出來的 UTF-8 BOM,或是被存在音訊前面的郵件標頭,都會把 RIFF 擠離位移 0。每個取樣值都活著;把 52 49 46 46 之前的東西全部刪掉,檔案就一模一樣地回來了。
這個格式現在還在用嗎
WAV 到現在還是音訊後製的工作格式,而且這件事大概不會改變:它無損、每套 DAW 和每個作業系統都讀得懂,而且排版簡單到從零寫一個出來只要一頁程式碼。它不適合當散佈格式 — 一小時的 CD 品質立體聲大約 600 MB,所以任何要離開錄音室的東西都會先編成 AAC、Opus 或 MP3,而無損散佈這一塊已經被 FLAC 接手,因為它用大約一半的空間裝同樣的取樣值,還附一套像樣的中介資料模型。WAV 同時也還是系統短音效、取樣音色庫、語音語料庫,以及任何微控制器或遊戲引擎必須在沒有解碼器的情況下播出來的東西的預設,因為原始 PCM 根本不吃 CPU。它真正的兩個限制是四 GB 上限,以及沒有標準的中介資料方案 — 而這兩點正是廣播領域改用 RF64 和 BWF 的原因。
在這個站上打開 WAV 檔
這些全部在你的瀏覽器裡跑,檔案不會離開你的電腦。
相關格式
容易和 WAV 搞混的格式,可以比對它們的開頭位元組。