WAV格式文件分析

14 篇文章 0 订阅

文章目录

WAV格式文件分析

WAV格式简介

WAV是最常见的声音文件格式之一,是微软公司专门为Windows开发的一种标准数字音频文件,该文件能记录各种单声道或立体声的声音信息,并能保证声音不失真。它符合资源互换文件格式(RIFF)规范,用于保存Windows平台的音频信息资源,被Windows平台及其应用程序所广泛支持。Wave格式支持MSADPCM、CCITT A律、CCITT μ律和其他压缩算法,支持多种音频位数、采样频率和声道,是PC机上最为流行的声音文件格式;但其文件尺寸较大,多用于存储简短的声音片段。

来源:百度百科

WAV格式组成

WAV文件遵循RIFF规则,其内容以chunk为最小单位进行存储。WAV文件一般由三个区块组成:RIFF chunkFormat chunkData chunk。同时,文件中也可能存在一些可选的区块,比如:Fact chunkPlayList chunk等。在分析的过程中,我们重点分析前三种区块:RIFF chunkFormat chunkData chunk

下面详细给出各区块的组成结构:

RIFF Chunk

名称

偏移地址

字节数

端序

内容

ID

0x00

4

大端

RIFF (0x52494646)

Size

0x04

4

小端

fileSize - 8

Type

0x08

4

大端

WAVE(0x57415645)

  • RIFF为标识
  • Size是指的整个文件的大小减去IDSize的长度。故是 f i l e s i z e 8 filesize - 8 filesize8
  • TypeWave表示后面需要有两个子块:FormatData

Format Chunk

名称

偏移地址

字节数

端序

内容

ID

0x00

4

大端

fmt (0x666D7420)

Size

0x04

4

小端

16/18

AudioFormat

0x08

2

小端

音频格式

NumChannels

0x0A

2

小端

声道数

SampleRate

0x0C

4

小端

采样率

ByteRate

0x10

4

小端

每秒数据字节数

BlockAlign

0x14

2

小端

数据块对齐

BitsPerSample

0x16

2

小端

采样位数

  • fmt为标识
  • Size表示该区块数据的长度(不包含ID和Size的长度)为16时WAV头部不包含附加信息
  • AudioFormat表示Data区块存储的音频数据的格式,PCM音频数据的值为1
  • NumChannels表示音频数据的声道数,1:单声道,2:双声道
  • SampleRate表示音频数据的采样率
  • ByteRate每秒数据字节数 S a m p l e R a t e N u m C h a n n e l s B i t s P e r S a m p l e / 8 SampleRate * NumChannels * BitsPerSample / 8 SampleRateNumChannelsBitsPerSample/8
  • BlockAlign每个采样所需的字节数 N u m C h a n n e l s B i t s P e r S a m p l e / 8 NumChannels * BitsPerSample / 8 NumChannelsBitsPerSample/8
  • BitsPerSample每个采样存储的bit数,取值有8,16,32

Data Chunk

名称

偏移地址

字节数

端序

内容

ID

0x00

4

大端

data(0x64617461)

Size

0x04

4

小端

视实际情况而定

Data

0x08

视文件大小而定

小端

音频数据

  • Data为标识
  • Size表示音频的长度 B y t e R a t e S e c o n d s ByteRate * Seconds ByteRateSeconds
  • Data表示数据

对于Data Chunk,声道数和采样率不同,造成不同的数据布局:(每列1Byte大小)

8 bit 单声道

采样1

采样2

数据1

数据2

8 bit 双声道

采样1

采样2

声道1 数据1

声道2 数据1

声道1 数据2

声道2 数据2

16 bit 单声道

采样1

采样2

数据1 低字节

数据1 高字节

数据2 低字节

数据2 高字节

16 bit 双声道

采样1

声道1 数据1 低字节

声道1 数据1 高字节

声道2 数据1 低字节

声道2 数据1 高字节

采样2

声道1 数据2 低字节

声道1 数据2 高字节

声道2 数据2 低字节

声道2 数据2 高字节

下面解释一下在上述内容中经常出现的大小端序问题

大小端端序

Wave文件以小端端序来存储数据

  • 大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中,如PNG文件格式;
  • 小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。

下面我们分析一个具体的.wav文件:

实际文件分析

RIFF Chunk

名称

实际数据

说明

ID

在这里插入图片描述

和上述内容一致

Size

在这里插入图片描述

整个文件大小为45340字节

Type

在这里插入图片描述

文件类型为WAVE

Format Chunk

名称

实际数据

说明

ID

在这里插入图片描述

和上文描述一致

Size

在这里插入图片描述

大小为16,头部不含附加信息

AudioFormat

在这里插入图片描述

为PCM音频数据

NumChannels

在这里插入图片描述

单声道音频

SampleRate

在这里插入图片描述

采样率为22050

ByteRate

在这里插入图片描述

每秒数据字节数为44100

BlockAlign

在这里插入图片描述

每个采样所需字节数为2

BitsPerSample

在这里插入图片描述

每个采样存储16bit

Data Chunk

名称

实际数据

说明

ID

在这里插入图片描述

和上文描述一致

Size

在这里插入图片描述

数据长度为45304字节

Data

好多不放了就…

实际存储的数据

是否存在其他可选区块?

为了验证该文件是否存在可选区块,加入了以下代码:

#include <iostream>
#include <fstream>
#include <cstdio>
#include <vector>
#include <map>
#include <set>
#define uchar unsigned char

using namespace std;

const string path = "test.wav";
vector<string> ans;

struct RiffHeader
{
    string id = "";
    string type = "";
    unsigned int length = 0;
    uchar len[4];
    uchar Type[4];
    void GetHead(ifstream & in) {
        uchar* buffer = new uchar[4];
        in.read((char *)buffer, 4);
        for (int i = 0;i < 4;i ++) id += (int)buffer[i];
        in.read((char *)len, 4);
        length = (len[1] + (len[0] << 8)) + ((len[3] + (len[2] << 8)) << 8);
        in.read((char *)Type, 4);
        for (auto i : Type) type += (int)i;
        return ; 
    }
};

struct FormatHeader
{
    string id = "";
    uchar data[20];
    void GetHead(ifstream & in) {
        uchar* buffer = new uchar[4];
        in.read((char*)buffer, 4);
        for (int i = 0;i < 4;i ++) id += (int)buffer[i];
        in.read((char*)data, 20);
        return ;
    }
};

struct DataHeader
{
    string id = "";
    uchar* data;
    unsigned int length = 0;
    void GetHead(ifstream & in) {
        uchar* buffer = new uchar[4];
        in.read((char*)buffer, 4);
        for (int i = 0;i < 4;i ++) id += (int)buffer[i];
        uchar* len = new uchar[4];
        in.read((char*)len, 4);
        length = (len[1] + (len[0] << 8)) + ((len[3] + (len[2] << 8)) << 8);
        data = new uchar[length];
        in.read((char *)data, length);
        return ;
    }
};

int main()
{
    ifstream in(path, ios :: binary);
    RiffHeader riff;
    FormatHeader format;
    riff.GetHead(in);
    ans.push_back(riff.id);
    format.GetHead(in);
    ans.push_back(format.id);
    while (!in.eof()) {
        DataHeader data;
        data.GetHead(in);
        ans.push_back(data.id);
    }
    cout << "All chunks : " << endl;
    for (auto i : ans) cout << "Chunk id : " << i << endl;
    return 0;
}

得到结果:

All chunks : 
Chunk id : RIFF
Chunk id : fmt 
Chunk id : data

本文件中无可选数据块。

参考文献

WAV文件格式详解
WAVE文件格式分析

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
wav文件是一种常见的音频文件格式,它是由Microsoft和IBM共同定义的。下面是对wav文件格式的详解: 1. 文件头(Header):wav文件的前44个字节是文件头,包含了文件的基本信息。文件头的结构如下: - ChunkID(4字节):文件标识,通常为"RIFF"。 - ChunkSize(4字节):文件大小,即整个文件的大小减去8个字节(ChunkID和ChunkSize本身的大小)。 - Format(4字节):文件格式,通常为"WAVE"。 - Subchunk1ID(4字节):子块标识,通常为"fmt "。 - Subchunk1Size(4字节):子块大小,即除去Subchunk1ID和Subchunk1Size本身的大小。 - AudioFormat(2字节):音频格式,常见值为1表示PCM(脉冲编码调制)。 - NumChannels(2字节):声道数,常见值为1表示单声道,2表示立体声。 - SampleRate(4字节):采样率,即每秒采样的样本数。 - ByteRate(4字节):数据传输速率,即每秒传输的字节数。 - BlockAlign(2字节):数据块对齐,即每个采样的字节数。 - BitsPerSample(2字节):样本位数,即每个采样的位数。 2. 数据块(Data Chunk):文件头之后的部分是音频数据块,包含了实际的音频采样数据。数据块的结构如下: - Subchunk2ID(4字节):子块标识,通常为"data"。 - Subchunk2Size(4字节):子块大小,即音频数据的大小。 - Data(变长):音频数据,以二进制形式存储。 在wav文件中,音频数据以采样点的形式存储,每个采样点的值表示音频信号在该时间点上的幅度。采样点的位数(BitsPerSample)决定了每个采样点的精度,位数越高,精度越高,音频质量也越好。 总结起来,wav文件格式通过文件头和数据块来存储音频数据,其中文件头包含了文件的基本信息,数据块存储了实际的音频采样数据。通过解析文件头和读取数据块中的采样数据,可以对wav文件进行分析和处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值