wav数据格式详解
简述
WAV 文件是在 PC 机平台上很常见的、最经典的多媒体音频文件, 是 WaveForm 的简写,也称为波形文件,可直接存储声音波形,还原的波形曲线十分逼真。
WAV 的特点如下:真实记录自然声波形,基本无数据压缩,数据量大。
文件结构
WAV 文件遵循 RIFF 规则,其内容以区块(chunk)为最小单位进行存储。WAV文件一般由3个区块组成:RIFF chunk、Format chunk 和 Data chunk。
CHUNK
每个 CHUNK 的格式都是:
| 名称 | 字节数 | 说明 |
|---|---|---|
| ID | 4 | 标识 |
| Size | 4 | 该块的数据长度 |
| Data | Size | 该块的数据 |
以下是存在的 CHUNK 类型:
| 数据块符号 | 数据块名称 | 可选否 |
|---|---|---|
RIFF chunk |
文件头数据块 | 否 |
Format chunk |
格式数据块 | 否 |
Data chunk |
波形数据块 | 否 |
Fact chunk |
是 | |
Cue points chunk |
是 | |
Playlist chunk |
是 | |
Associated data list chunk |
是 |
RIFF chunk
| 名称 | 字节数 | 端序 | 内容 |
|---|---|---|---|
| ID | 4 | 大端 | RIFF (0x52494646) |
| Size | 4 | 小端 | fileSize - 8 (文件大小 - 8) |
| Type | 4 | 大端 | WAVE (0x57415645) |
当 Type 是 WAVE
时,表示后面需要两个子块:Format chunk 和
Data chunk。
Format chunk
| 名称 | 字节数 | 端序 | 内容 |
|---|---|---|---|
| ID | 4 | 大端 | fmt (0x666D7420) |
| Size | 4 | 小端 | 16 |
| AudioFormat | 2 | 小端 | 音频格式 |
| NumChannels | 2 | 小端 | 声道数 (1 or 2) |
| SampleRate | 4 | 小端 | 采样率 |
| ByteRate | 4 | 小端 | 每秒数据字节数 |
| BlockAlign | 2 | 小端 | 数据块对齐 |
| BitsPerSample | 2 | 小端 | 采样位数 (8, 16 or 32) |
需要注意的是,ByteRate 和 BlockAlign 是可以计算出来的,如果不满足公式可能导致读取文件错误:
ByteRate = SampleRate * NumChannels * BitsPerSample / 8
BlockAlign = NumChannels * BitsPerSample / 8
BitsPerSample 代表的是采样位数,即接下来的 Data chunk 中的每个波形数据有几个字节。
Data chunk
| 名称 | 字节数 | 端序 | 内容 |
|---|---|---|---|
| ID | 4 | 大端 | data (0x64617461) |
| Size | 4 | 小端 | N |
| Data | Size | 小端 | 波形数据 |
需要注意的是,Size = ByteRate * seconds
如果声道数为 2,即多声道音频,在 Data 中每次采样依次排列,即例如 8bit 双声道的数据存放为:
| 采样1 | 采样2 | ||
|---|---|---|---|
| 声道1数据 (1 byte) | 声道2数据 (1 byte) | 声道1数据 (1 byte) | 声道2数据 (1 byte) |
音频处理
python3&wave
这里使用 Python3 对 wav 文件进行处理。
在 Python3 中自带一个 wave 模块支持对 wav
格式的音频数据进行处理,结合 numpy 可以自由操作所有 wav
的波形数据。
常用的操作有:
| 函数 | 作用 |
|---|---|
wave.open(filename, "r") |
打开一个音频文件,返回 Wave_read 对象 |
Wave_read.close() |
关闭一个 Wave_read 对象 |
Wave_read.getnchannels() |
返回声道数量,1为单声道,2为立体声 |
Wave_read.getsampwidth() |
返回采样位数 |
Wave_read.getframerate() |
返回采样频率 |
Wave_read.getnframes() |
返回音频总帧数 |
Wave_read.readframes(n) |
读取 n 帧波形数据,如果参数为 -1 则读取所有 |
将波形数据转化为成 ndarray 的示例代码:
1 | import wave |
python3&soundfile
但这里更推荐使用第三方库
soundfile,可以更轻松的将音频数据读取并转换为
ndarray,示例代码如下:
1 | data, samplerate = sf.read("attachment.wav") |
其中,samplerate 是音频的采样率。
但默认读取类型是 float,如果觉得不好看,可以通过
dtype 参数控制输出的 numpy 数组的
dtype。
1 | data, samplerate = sf.read("attachment.wav", dtype = np.int16) |
同时如果是多声道的音频文件,它将转换出多个 ndarray
数组来保存不同声道的数据。