<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
一、WAV文件格式分析
1、开发板上的资源
在开发板的GPIO管脚中,PB0外接了一个扬声器。通过一个三极管8050 驱动扬声器。我以前试过将该脚复用为TIM_CH3,采用PWM输出,频率不同时,可以听到高低不同的声音,但不知道播放音乐的效果怎么样。
我记得网上有网友说用智林开发板实现了音乐播放,我也来试一试。
这里主要是采用WAV格式的声音文件,它里面数据的存放是按照采样率、声音的大小采样来实现的。也就是说,只要按它的采用率从文件中取出声音数据,然后让扬声器输出一个与声音数据大小成正比的声音,就可以将声音还原播放出来。
2、WAV格式分析
(1)格式的简单学习
WAV文件的扩展名为“WAV”,数据本身的格式为PCM或压缩型。它采用RIFF文件格式结构,使用三个参数来表示声音:采样位数、采样频率和声道数。
PCM是指脉冲编码调制,利用脉冲编码调制,波形可以按固定的周期频率取样,其频率通常是每秒几万次(比如44.1kHZ,就是每秒4.41万次)。对于每个样本都测量其波形的振幅。
Windows同时支持8位和16位的样本大小。储存8位的样本时,样本以无正负号字节处理,静音将储存为一个值为0x80的字符串。16位的样本以带正负号整数处理,这时静音将储存为一个值为0的字符串。
对于双声道立体声声音文件,每次采样数据为一个16位的整数(int)。我们在电脑上使用的好像都是采样率44.1KHZ,双声道的。
WAVE文件是由若干个Chunk组成的。按照在文件中的出现位置包括:RIFF WAVE Chunk, Format Chunk, Fact Chunk(可选), Data Chunk。
(2)WAV格式实践
我在网上下了一个WAV文件,利用Ultraedit以二进制的方式打开。结合百度上有关文章对WAV格式的描述,学习以下它的结构。
WAV文件头部首先是一个RIFF WAVE Chunk。它包括12个字节。
00000000h: 52 49 46 46 98 95 <?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />0A 00 57 41 56 45 ; RIFF槙..WAVE
以'RIFF'作为标示,占四个字节,然后紧跟着为size字段,该size是整个wav文件大小减去ID和Size所占用的字节数,即FileLen - 8 = Size。我打开的这个文件共693664个字节,而 000A9598 = 693 656。然后是Type字段,为'WAVE',表示是wav文件。
然后紧跟着是一个Format Chunk,这个部分包括了WAV文件的大部分格式信息。包括采样频率、位数、声道数,编码方式、每个采样所需字节数、每秒需要的字节数等等。
以'fmt '四个字节作为标示。后面一般情况下Size占用2个字节。其取值为16,此时最后附加信息没有;如果为18则最后多了2个字节的附加信息。主要由一些软件制成的wav格式中含有该2个字节的附加信息。
后面的属性用一个结构体表示,结构定义如下:
struct WAVE_FORMAT
{ WORD wFormatTag; //编码方式,2个字节
WORD wChannels; //声道数目,2个字节
DWORD dwSamplesPerSec; //采样频率,4给字节
DWORD dwAvgBytesPerSec; //每秒需用的字节数,4个字节
WORD wBlockAlign; //每次采样所需字节数,2个字节
WORD wBitsPerSample; //每次采样所用的位数,2个字节
//这里可能还要附加字节,看size的值。
};
0000000ch: 66 6D 74 20 32 00 00 00 02 00 01 00 22 56 00 00 ; fmt 2......."V..
0000001ch: AB 2B 00 00 00 02 04 00 20 00 F4 03 07 00 00 01 ; ?...... .?....
0000002ch: 00 00 00 02 00 FF 00 00 00 00 C0 00 40 00 F0 00 ; .....�....?@.?
0000003ch: 00 00 CC 01 30 FF 88 01 18 FF ; ..?0�?.�
我这个取出来的数据与网上说的有点不同啊,size字段表明格式字段后面跟着0x32个字节,也就是50个。前面16个表示属性:
编码方式为02 00,编码类型?
声道数目为01 00,一个声道
采样频率为22 56 00 00,22050=22.05kHZ。这个是对应的。
每秒字节数AB 2B 00 00,共11179个字节,这个数据好像不对。
每次采样字节数00 02,,512字节,不可能吧。
采样位数,04 00四位,应该最少8位啊。
这是附加的字节:20 00,什么意思?
然后紧跟着是一个Fact Chunk,Fact Chunk是可选字段,一般当wav文件由某些软件转化而成,则包含该Chunk。一般是12个字节。
其结构如下:
struct FACT_BLOCK
{ char szFactID[4]; // 'f','a','c','t'
DWORD dwFactSize; //后面数据的大小。
};
我的WAV文件是这样的:
00000046h: 66 61 63 74 04 00 00 00 08 EB 14 00 ; fact.....?.
然后紧跟着是Data Chunk,所有的声音数据都放在这里了。
我的WAV文件是这样的:
00000052h: 64 61 74 61 46 95 0A 00 01 10 00 00 00 00 ; dataF?.......
0x46 95 0A 00表明数据部分的大小,比文件长度小90个字节。因为RIFF WAVE Chunk占用12个字节,Format Chunk占用58个字节,Fact Chunk占12个字节,Data Chunk头部8个字节,所以后面全是声音采样的数据。
Data Chunk是真正保存wav数据的地方,以'data'作为该Chunk的标示。然后是数据的大小。紧接着就是wav数据。根据Format Chunk中的声道数以及采样bit数, wav数据的bit位置可以分成以下几种形式:
---------------------------------------------------------------------
| 单声道 | 取样1 | 取样2 | 取样3 | 取样4 |
| |--------------------------------------------------------
| 8bit量化 | 声道0 | 声道0 | 声道0 | 声道0 |
---------------------------------------------------------------------
| 双声道 | 取样1 | 取样2 | 取样3 | 取样4 |
| |-----------------------------------------------------------------------------
| 8bit量化 | 声道0(左) | 声道1(右) | 声道0(左) | 声道1(右) |
---------------------------------------------------------------------
| 单声道 | 取样1 | 取样2 | 取样3 | 取样4 |
| |-------------------------------------------------------------------
| 16bit量化 | 声道0 | 声道0 | 声道0 | 声道0 |
| | (低位) | (高位) | (低位) | (高位) |
---------------------------------------------------------------------
| 双声道 | 取样1 |取样2 | 取样3 | 取样4 |
| |---------------------------------------------------------------------------
| 16bit量化 | 声道0(左) | 声道0(左) | 声道1(右) | 声道1(右) |
| | (低位) | (高位) | (低位) | (高位) |
(3)再打开一个文件
在Format Chunk部分有点问题,所以再打开一个WAV文件看一下。
这次打开的跟网上描述的一样:Format Chunk共16个字节,而且没有Fact Chunk。后面马上就是Data Chunk。
0000h:52 49 46 46 44 3D 07 00 57 41 56 45 66 6D 74 20 ; RIFFD=..WAVEfmt
0010h:10 00 00 00 01 00 01 00 40 1F 00 00 40 1F 00 00 ; ........@...@...
0020h:01 00 08 00 64 61 74 61 1F 3D 07 00 80 7F 80 80 ; ....data.=..€€€
SIZE为10 00 00 00,表示16字节
编码方式为01 00,应该就是指PCM编码
声道数目为01 00,一个声道
采样频率为40 1F 00 00,8000HZ。这个是对应的采样频率。
每秒字节数40 1F 00 00,每秒共8000个字节,单声道8位采样。
每次采样字节数01 00,一个字节
采样位数08 00,每次采样为8位。
(4)再次搜索,看SIZE=50到底对应什么情况。
终于找到了:
其中wFormatTag标明了文件的类型,这样我们就可以判断后面的数据是以什么方式来存储和表示的了,比如,#define WAVE_FORMAT_PCM 0x0001 这样,WAVE_FORMAT_PCM表示的就是普通的原始wav文件格式。再比如,#define WAVE_FORMAT_ADPCM 0x0002 我们就可以知道,wFormatTag的值为WAVE_FORMAT_ADPCM就是以ADPCM压缩的格式了。
WAVEFORMATEX是所有的format所共有的一个头部,不同格式会在后面添加自己的相关的数据段,添加的段的字节数可以通过cbSize来得到。
cbSize用来描述不同的格式后面添加的多余的字节数。比如WAVE_FORMAT_ADPCM格式的format的这个值就是32,表明还有32个字节在后面。标准16个字节+附加的两个字节+后面的32个字节等于50字节。
至于详细的的ADPCM编码格式,我就不做分析了,因为我计划的声音播放只要实现简单的PCM编码格式就行了。有兴趣的可以看这篇文章。我是从这里得到以上信息的。
文章评论(0条评论)
登录后参与讨论