原创 STM32开发板上音频播放程序的设计之一

2010-4-9 12:26 6329 11 11 分类: MCU/ 嵌入式

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

 


一、WAV文件格式分析


1、开发板上的资源


在开发板的GPIO管脚中,PB0外接了一个扬声器。通过一个三极管8050 驱动扬声器。我以前试过将该脚复用为TIM_CH3,采用PWM输出,频率不同时,可以听到高低不同的声音,但不知道播放音乐的效果怎么样。


我记得网上有网友说用智林开发板实现了音乐播放,我也来试一试。


这里主要是采用WAV格式的声音文件,它里面数据的存放是按照采样率、声音的大小采样来实现的。也就是说,只要按它的采用率从文件中取出声音数据,然后让扬声器输出一个与声音数据大小成正比的声音,就可以将声音还原播放出来。


 


2WAV格式分析


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


 


2WAV格式实践


我在网上下了一个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文件大小减去IDSize所占用的字节数,即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 0022050=22.05kHZ这个是对应的。


每秒字节数AB 2B 00 00,共11179个字节,这个数据好像不对


每次采样字节数00 02512字节,不可能吧。


采样位数,04 00四位,应该最少8位啊。


这是附加的字节:20 00,什么意思?


 


然后紧跟着是一个Fact ChunkFact 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 Chunk12个字节,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 Chunk16个字节,而且没有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.=..€€€


SIZE10 00 00 00,表示16字节


编码方式为01 00,应该就是指PCM编码


声道数目为01 00,一个声道


采样频率为40 1F 00 008000HZ这个是对应的采样频率。


每秒字节数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编码格式就行了。有兴趣的可以看这篇文章。我是从这里得到以上信息的。


Microsoft ADPCM 编码解码算


 


 


 

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
11
关闭 站长推荐上一条 /3 下一条