03 November 2013

最近读书读得有点上头,好久没有更新博客。今天发一篇博客,总结总结最近学习的关于WAV文件格式的内容,希望对大家有用。

似乎听音乐的同学都或多或少听过wav文件,其实其全称是WAVE,由微软开发的一种音频文件格式,文件的扩展名为“WAV”(有没有感觉有点像JPEG和jpg),数据本身的格式为PCM或压缩型,属于无损音乐格式的一种。

要说WAVE文件的格式,网上一搜一大堆,其实可以分为两大部分:头部分和数据部分。大概就是播放器先分析头部分,确定是wav文件后播放数据部分。头部分又可以分为3部分:RIFF WAVE Chunk,Format Chunk,Fact Chunk(可选)。这篇文章讲的很好,推荐大家看一看。

字节数        内容
  4       RIFF WAVE Chunk标志,为RIFF
  4       RIFF WAVE Chunk大小,为(总大小-4)字节
  4       WAV文件标志,为WAVE

  4       Format Chunk标志,为fmt
  4       过滤字节,一般为00000010H
  2       格式种类,线性PCM编码为1
  2       通道数,1为单声道,2为双声道
  4       采样频率
  4       波形传输速率
  2       数据调整数
  2       样本数据位数

  4       Fact Chunk标志,为fact
  。。。

  4       Data Chunk标志,为data
  4       采样数据大小,为总大小减掉头部分大小
  音频数据。。。

一个一个来说,首先RIFF那个标志就不说了,必须是那四个字母,而且是大写。大小那项也不必说,总字节-4就是了。下一个WAV标志也必须是“WAVE”。Format Chunk标志要着重说,这里是四个字节,但是仅有三个字母,但是最后一位必须是空格。如果是分隔符还是什么别的,这部分便识别不了,也就是说,两个相同的WAV文件,把这个空格改成分隔符,则这个音频文件无法识别。如果无法确定自己是否是填进的空格,用16进制的编辑器查看一下这个wav文件,第16个字节应该是20(空格的ASCII码)才对。过滤字节也要着重说一下,由于写入WAV文件实际是小端法,比如你写入123456,实际上查看文件是563412,等等,那个H是指16进制哈。也就是说,写入00000010,实际上看到的是10000000。这个倒是好办,赋值时直接赋一个0x10即可,但是要注意有时候别人给你的是563412,但是那是他在文件中直接读到的,实际上式0x123456。格式种类啊、通道数啊,还有采样频率,都是定好的,根据需要修改。波形传输速率为:每秒字节=采样频率每个样本字节数,这个每个样本的字节数即下面第二项样本数据位数除以8可得。数据调整数为 channles bit_samp / 8,也是可以计算出来的。

Fact Chunk部分是可选部分,根据网上所说,“一般当wav文件由某些软件转化而成”,我观察过一些wav文件,都没有这部分,也就是说除非情况特殊,则不用考虑。

数据部分先识别标志“data”,大小则是:总大小-头部大小,实际上就是纯音频数据的大小(字节)。

刚才推荐的那个网页其实已经给出了一个读取WAV文件格式的基本方法,但是有人会说怎么自己运行后会出错。其实问题很有可能出在位宽上,比如文中给出的uint32这个类型,他使用的其实是long型,long型在如今的计算机或者编译器上很可能不是32位而是64位,改成int型试试,说不定就通过了。也可以验证自己的系统和编译器给出的long和int的位宽是多少,最好char,short都试试。方法很简单:

printf("char: %d, short: %d, int: %d, long: %d\n",
		sizeof(char), sizeof(short), sizeof(int), sizeof(long));

如果想给一段纯音频文件添加WAVE头,或提取的音频部分经过处理再添加WAVE头,则注意我上面说的部分基本就够了,本人亲测可以。如果还是无法出正确结果,建议拿原始文件,以16进制形式来查看,一点点对照(实际上也就44个字节要对照),相信很快你就会找到问题的所在。

祝幸运!



blog comments powered by Disqus