转 1

WAVE 文件格式分析

WAVE 文件作为多媒体中使用的声音波形文件格式之一,它是以RIFF(Resource Interchange File Format)格式为标准的。每个WAVE文件的头四个字节便是“RIFF”。WAVE 文件由文件头和数据体两大部分组成。其中文件头又分为 RIFF/WAV 文件标识段和声音数据格式说明段两部分。WAVE文件各部分内容及格式见后文。

常见的声音文件主要有两种,分别对应于单声道(11.025KHz 采样率、8Bit 的采样值)和双声道(44.1KHz 采样率、16Bit 的采样值)。采样率是指:声音信号在“模→数”转换过程中单位时间内采样的次数。采样值是指每一次采样周期 
内声音模拟信号的积分值。

对于单声道声音文件,采样数据为八位的短整数(short int 00H-FFH);而对于双声道立体声声音文件,每次采样数据为一个16位的整数(int),高八位和低八位分别代表左右两个声道。

WAVE 文件数据块包含以脉冲编码调制(PCM)格式表示的样本。WAVE 文件是由样本组织而成的。在单声道 WAVE 文件中,声道0代表左声道,声道1代表右声道。在多声道WAVE文件中,样本是交替出现的。

WAVE 文件除了前面一小段文件头对数据组织进行说明之外,Data 块就是声音的原始采样数据,WAVE 文件虽然可以压缩,但一般都使用不压缩的格式。44.1KHz 采样率、16Bit的分辨率、双声道,所以WAVE可以保存音质要求非常高的声音文件,CD 采用的也是这种格式,声音方面的专家或是音乐发烧友们应该非常熟悉。但这种文件的体积也非常大,以 44.1KHz 16bit 双声道的数据为例,一分钟的声音数据量为:4100*2byte*2channel*60s/1024/1024=10.09M 。所以不合适在网上传送。


下面我们具体地分析 WAVE 文件的格式

endian

field name

Size

 
big ChunkID 4 文件头标识,一般就是" RIFF" 四个字母
little ChunkSize 4 整个数据文件的大小,不包括上面ID和Size本身
big Format 4 一般就是" WAVE" 四个字母
big SubChunk1ID 4 格式说明块,本字段一般就是"fmt "
little SubChunk1Size 4 本数据块的大小,不包括ID和Size字段本身
little AudioFormat 2 音频的格式说明
little NumChannels 2 声道数
little SampleRate 4 采样率
little ByteRate 4 比特率,每秒所需要的字节数
little BlockAlign 2 数据块对齐单元
little BitsPerSample 2 采样时模数转换的分辨率
big SubChunk2ID 4 真正的声音数据块,本字段一般是"data"
little SubChunk2Size 4 本数据块的大小,不包括ID和Size字段本身
little Data N 音频的采样数据

以下是对各个字段的详细解说:

ChunkID 4bytes ASCII 码表示的“RIFF”。(0x52494646)
ChunkSize 4bytes 36+SubChunk2Size,或是 
4 + ( 8 + SubChunk1Size ) + ( 8 + SubChunk2Size ), 
这是整个数据块的大小(不包括ChunkID和ChunkSize的大小)
Format 4bytes ASCII 码表示的“WAVE”。(0x57415645)
     
SubChunk1ID   新的数据块(格式信息说明块) 
ASCII 码表示的“fmt ”——最后是一个空格。(0x666d7420)
SubChunk1Size 4bytes 本块数据的大小(对于PCM,值为16)。
AudioFormat 2bytes PCM = 1 (比如,线性采样),如果是其它值的话,则可能是一些压缩形式
NumChannels 2bytes 1 => 单声道  |  2 => 双声道
SampleRate 4bytes 采样率,如 8000,44100 等值
ByteRate 4bytes 等于: SampleRate * numChannels * BitsPerSample / 8
BlockAlign 2bytes 等于:NumChannels * BitsPerSample / 8
BitsPerSample 2bytes 采样分辨率,也就是每个样本用几位来表示,一般是 8bits 或是 16bits
     
SubChunk2ID 4bytes 新数据块,真正的声音数据 
ASCII 码表示的“data ”——最后是一个空格。(0x64617461)
SubChunk2Size 4bytes 数据大小,即,其后跟着的采样数据的大小。
Data N bytes 真正的声音数据

对于Data块,根据声道数和采样率的不同情况,布局如下(每列代表8bits):

1. 8 Bit 单声道:

采样1 采样2
数据1 数据2

2. 8 Bit 双声道

采样1   采样2  
声道1数据1 声道2数据1 声道1数据2 声道2数据2

1. 16 Bit 单声道:

采样1   采样2  
数据1低字节 数据1高字节 数据1低字节 数据1高字节

2. 16 Bit 双声道

采样1      
声道1数据1低字节 声道1数据1高字节 声道2数据1低字节 声道2数据1高字节
采样2      
声道1数据2低字节 声道1数据2高字节 声道2数据2低字节 声道2数据2高字节

下面我们看一个具体的例子,声音文件如下:

52 49 46 46 24 08 00 00 57 41 56 45
66 6d 74 20 10 00 00 00 01 00 02 00
22 56 00 00 88 58 01 00 04 00 10 00
64 61 74 61 00 08 00 00 00 00 00 00
24 17 1e f3 3c 13 3c 14 16 f9 18 f9
34 e7 23 a6 3c f2 24 f2 11 ce 1a 0d

对应的分析如下图所示:

本文参考了:

转2

1.PCM Wave格式详解

WAVE文件格式是微软RIFF(Resource Interchange File Format,资源交换文件标准)的一种,是针对于多媒体文件存储的一种文件格式和标准。 一般而言,RIFF文件由文件头和数据两部分组成,一个WAVE文件由一个“WAVE”数据块组成,这个“WAVE”块又由一个”fmt”子数据块和一个“data”子 数据块组成,也称这种格式为“Canonical form”(权威/牧师格式),如下图所示:

每个字段的涵义如下: ChunkID: 占4个字节,内容为“RIFF”的ASCII码(0x52494646),以大端(big endian)存储。
ChunkSize: 4字节,存储整个文件的字节数(不包含ChunkID和ChunkSize这8个字节),以小端(little endian)方式存储。
Format: 4字节,内容为“WAVE”的ASCII码(0x57415645),以大端存储。

其中bigendian 主要有一个特征,在内存中对操作数的存储方式和从高字节到低字节。例如:0x1234,这样一个数,存储为:
0x4000: 0x12
0x4001: 0x34
而小尾端littleendian是:
0x4000: 0x34
0x4001: 0x12
用程序在区别的话,可以考虑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
union w
{
short int a;
char b;
}c;
c.a=1;
if( c.b==1 ) printf("little endian\n");
else printf("big endian\n");
system("PAUSE");
return 0;
}

“WAVE”格式由两个子数据块构成:“fmt”块和“data”块,其中“fmt”块的详细解释如下: Subchunk1ID: 占4个字节,内容为“fmt ”的ASCII码(0x666d7420),以大端存储。
Subchunk1Size: 占4个字节,存储该子块的字节数(不含前面的Subchunk1ID和Subchunk1Size这8个字节),以小端方式存储。
AudioFormat:占2个字节,以小端方式存储,存储音频文件的编码格式,例如若为PCM则其存储值为1,若为其他非PCM格式的则有一定的压缩。
NumChannels: 占2个字节,以小端方式存储,通道数,单通道(Mono)值为1,双通道(Stereo)值为2,等等。
SampleRate: 占4个字节,以小端方式存储,采样率,如8k,44.1k等。
ByteRate: 占4个字节,以小端方式存储,每秒存储的bit数,其值=SampleRate * NumChannels * BitsPerSample/8
BlockAlign: 占2个字节,以小端方式存储,块对齐大小,其值=NumChannels * BitsPerSample/8
BitsPerSample: 占2个字节,以小端方式存储,每个采样点的bit数,一般为8,16,32等。
接下来是两个可选的扩展参数:
ExtraParamSize: 占2个字节,表示扩展段的大小。
ExtraParams: 扩展段其他自定义的一些参数的具体内容,大小由前一个字段给定。

其中,对于每个采样点的bit数,不同的bit数读取数据的方式不同:

1
2
3
4
5
6
7
8
9
10
// data 为读取到的采样点的值,speech为原始数据流,
//对应于下面的"WAVE"格式文件的第二个子数据块“data”块的“Data”部分。
for(i=0;i<NumSample;i++){
if(BitsPerSample==8)
data[i] = (int)*((char*)speech+i);
else if(BitsPerSample==16)
data[i] = (int)*((short*)speech+i);
else if(BitsPerSample==32)
data[i] = (int)*((int*)speech+i);
}

“WAVE”格式文件的第二个子数据块是“data”,其个字段的详细解释如下:
Subchunk2ID: 占4个字节,内容为“data”的ASCII码(0x64617461),以大端存储。
Subchunk2Size: 占4个字节,内容为接下来的正式的数据部分的字节数,其值=NumSamples * NumChannels * BitsPerSample/8
Data: 真正的语音数据部分。

一个Wave文件头的实例

设一个wave文件的前72个字节的十六进制内容如下(可以使用Ultra Edit等工具查看wave文件头):

1
2
3
52 49 46 46 24 08 00 00 57 41 56 45 66 6d 74 20 10 00 00 00 01 00 02 00
22 56 00 00 88 58 01 00 04 00 10 00 64 61 74 61 00 08 00 00 00 00 00 00
24 17 1e f3 3c 13 3c 14 16 f9 18 f9 34 e7 23 a6 3c f2 24 f2 11 ce 1a 0d

则其个字段的解析如下图:

C语言实现wave文件的读取

这里给出一个用基本的C语言文件操作库函数实现的Wave文件读取的实例代码,可以跨Windows和Linux平台。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // define Wave format structure
typedef struct tWAVEFORMATEX
{
short wFormatTag; /* format type */
short nChannels; /* number of channels (i.e. mono, stereo...) */
unsigned int nSamplesPerSec; /* sample rate */
unsigned int nAvgBytesPerSec; /* for buffer estimation */
short nBlockAlign; /* block size of data */
short wBitsPerSample; /* number of bits per sample of mono data */
short cbSize; /* the count in bytes of the size of */
/* extra information (after cbSize) */
} WAVEFORMATEX, *PWAVEFORMATEX; char* wavread(char *fname, WAVEFORMATEX *wf); int main(){
char fname[] = "test.wav";
char *speech;
WAVEFORMATEX wf; speech = wavread(fname, &wf);
// afterward processing... return 0;
} // read wave file
char* wavread(char *fname, WAVEFORMATEX *wf){
FILE* fp;
char str[32];
char *speech;
unsigned int subchunk1size; // head size
unsigned int subchunk2size; // speech data size // check format type
fp = fopen(fname,"r");
if(!fp){
fprintf(stderr,"Can not open the wave file: %s.\n",fname);
return NULL;
}
fseek(fp, 8, SEEK_SET);
fread(str, sizeof(char), 7, fp);
str[7] = '\0';
if(strcmp(str,"WAVEfmt")){
fprintf(stderr,"The file is not in WAVE format!\n");
return NULL;
} // read format header
fseek(fp, 16, SEEK_SET);
fread((unsigned int*)(&subchunk1size),4,1,fp);
fseek(fp, 20, SEEK_SET);
fread(wf, subchunk1size, 1, fp); // read wave data
fseek(fp, 20+subchunk1size, SEEK_SET);
fread(str, 1, 4, fp);
str[4] = '\0';
if(strcmp(str,"data")){
fprintf(stderr,"Locating data start point failed!\n");
return NULL;
}
fseek(fp, 20+subchunk1size+4, SEEK_SET);
fread((unsigned int*)(&subchunk2size), 4, 1, fp);
speech = (char*)malloc(sizeof(char)*subchunk2size);
if(!speech){
fprintf(stderr, "Memory alloc failed!\n");
return NULL;
}
fseek(fp, 20+subchunk1size+8, SEEK_SET);
fread(speech, 1, subchunk2size, fp); fclose(fp);
return speech;
}

参考

[1]WAVE PCM soundfile format: https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ 
[2]Resource Interchange File Format: http://en.wikipedia.org/wiki/Resource_Interchange_File_Format 
[3]基于Visual C++6.0的声音文件操作: http://www.yesky.com/20030414/1663116_1.shtml

Original Link: http://ibillxia.github.io/blog/2013/07/20/details-of-wave-format-and-reading-wave-files-in-C-language/
Attribution - NON-Commercial - ShareAlike - Copyright © Bill Xia

转wave 文件解析的更多相关文章

  1. Alsa 读取wave文件,并播放wave 文件

    对于一个wave文件,如果需要播放,涉及到几个方面 1.对于wave文件的解析 2.通过解析wave文件,将得到的参数(主要是sampfrequency, bitsperSample,channel) ...

  2. 音频文件解析(一):WAV格式文件头部解析

    WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范,用于保存Windows平台的音频信息资源. 文 ...

  3. (转)AVI文件格式解析+AVI文件解析工具

    AVI文件解析工具下载地址:http://download.csdn.net/detail/zjq634359531/7556659 AVI(Audio Video Interleaved的缩写)是一 ...

  4. 【转】Python处理wave文件

    #本文PDF版下载 Python解析Wav文件并绘制波形的方法 #本文代码下载 Wav波形绘图代码 #本文实例音频文件night.wav下载 音频文件下载 (石进-夜的钢琴曲) 前言 在现在繁忙的生活 ...

  5. WAVE文件格式解析

    WAVE 文件作为Windows多媒体中使用的声音波形文件格式之一,它是以RIFF(Resource Interchange File Format)格式为标准的.这里不针对RIFF文件格式做介绍,不 ...

  6. 基于Linux ALSA音频驱动的wav文件解析及播放程序 2012

    本设计思路:先打开一个普通wav音频文件,从定义的文件头前面的44个字节中,取出文件头的定义消息,置于一个文件头的结构体中.然后打开alsa音频驱动,从文件头结构体取出采样精度,声道数,采样频率三个重 ...

  7. 转载:AAC文件解析及解码

    转自:http://blog.csdn.net/wlsfling/article/details/5876016 http://www.cnblogs.com/gaozehua/archive/201 ...

  8. CocosStudio文件解析工具CsdAnalysis

    起因 因为工作需要,所以需要使用CocosStudio来制作界面动画什么的.做完了发现需要找里边对象的时候会有很长一串代码,感觉不是很爽.之前写OC代码的时候可以吧程序中的对象指针跟编辑器中的对象相对 ...

  9. 通过正则表达式实现简单xml文件解析

    这是我通过正则表达式实现的xml文件解析工具,有些XHTML文件中包含特殊符号,暂时还无法正常使用. 设计思路:常见的xml文件都是单根树结构,工具的目的是通过递归的方式将整个文档树装载进一个Node ...

随机推荐

  1. QANet

    Reading Comprehension(RC) 阅读理解对于机器来说, 是一项非常艰巨的任务.google提出QANet, 目前(2018 0505)一直是SQuAD的No. 1. 今天简单地与大 ...

  2. quartz的job怎么获取Spring上下文

    第一步.在org.springframework.scheduling.quartz.SchedulerFactoryBean对象中注入applicationContextSchedulerConte ...

  3. Vue(九) 自定义指令

    前面介绍了许多 Vue 内置的指令,比如 v-if.v-show等,这些丰富的指令能满足我们绝大部分的业务需求,不过在需要一些特殊功能时,我们仍然希望对 DOM 进行底层的操作,这时就要用到自定义指令 ...

  4. sql 中取整,四舍五入取整,向下取整,向上取整。

    SELECT round(52.45, 0) AS round4, round(52.54, 0) AS round5, round(52.45, 1) AS round41, round(52.54 ...

  5. Visual Basic 2017 操作Excel和word【1】持续更新……

    我坚持在VB的路上走到黑…………  清单1.1  从应用程序对象导航到Excel中的工作表  Dim myWorkbooks As Excel.Workbooks = app.Workbooks ) ...

  6. Centos7修改分区空间

    一:缩小/home空间 1.1:备份/home内容 cp -r /home/* /homebak 1.2:删除挂载/home umount /home 1.3:删除/home所在lv lvremove ...

  7. 容器的注入和container设计的思想——Injection Container 理解

    为什么会出现容器的注入? 容器:顾名思义,装东西的器物. 至于spring中bean,aop,ioc等一些都只是实现的方式:具体容器哪些值得我们借鉴,我个人觉得是封装的思想.将你一个独立的系统功能放到 ...

  8. IntelliJ IDEA使用教程(很全)

    IntelliJ IDEA使用教程(很全) 这个编辑器我就不再多做介绍了.直接开始新建maven hello world 的Java web项目啦 你电脑上得有jdk1.7,或者1.8,然后就是mav ...

  9. js使页面重定向

    location.assign("http://www.baidu.com"); window.location="http://www.baidu.com"; ...

  10. UILabel Text显示不同的颜色

    UILabel的text实现不同的颜色. NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithStr ...