音频文件(.wav)解析读取

wav是一种无损的音频文件格式,所有的WAV都有一个文件头,包含了音频流的编码参数,即支持非压缩的PCM编码方式,也支持常见的压缩编码格式。

当WAV文件采用PCM编码方式时,PCM文件和WAV文件的区别只在于是否有文件头,下面介绍一下wav文件的文件头。

wav文件头

偏移
地址

字节数

数据
类型

字段名称 字段说明
00H 4 字符 文档标识 大写字符串"RIFF",标明该文件为有效的 RIFF 格式文档。
04H 4 长整型数 文件数据长度 从下一个字段首地址开始到文件末尾的总字节数。该字段的数值加 8 为当前文件的实际长度。
08H 4 字符 文件格式类型 所有 WAV 格式的文件此处为字符串"WAVE",标明该文件是 WAV 格式文件。
0CH 4 字符 格式块标识 小写字符串,"fmt "。
10H 4 长整型数 格式块长度。 其数值不确定,取决于编码格式。可以是 16、 18 、20、40 等。(PCM 编码为16)
14H 2 整型数 编码格式代码。 常见的 WAV 文件使用 PCM 脉冲编码调制格式,该数值通常为 1。
16H 2 整型数 声道个数 单声道为 1,立体声或双声道为 2
18H 4 长整型数 采样频率 每个声道单位时间采样次数。常用的采样频率有 11025, 22050 和 44100 kHz。
1CH 4 长整型数 数据传输速率, 该数值为:声道数×采样频率×每样本的数据位数/8。
20H 2 整型数 数据块对齐单位 采样帧大小。该数值为:声道数×位数/8。
22H 2 整型数 采样位数 存储每个采样值所用的二进制数位数。常见的位数有 4、8、12、16、24、32
24H 2 整型数 扩展区长度

22(根据格式块长度有关)

26H 4 字符 数据块标识 data
2aH 4 长整型数 数据块长度 数据块的长度
2eH        

当使用C程序读写wav格式数据时,先要把头文件的内容读取了,并判断文件的是否有损坏(可以通过文件长度判断)。

首先定义头文件的结构体:

typedef struct WAV_Format {

    char ChunkID[4];    /* "RIFF" */

    int ChunkSize;    /* 36 + Subchunk2Size */

    char Format[4];    /* "WAVE" */

 
    /* sub-chunk "fmt" */

    char Subchunk1ID[4];    /* "fmt " */

    int Subchunk1Size;    /* 16 for PCM */

    short AudioFormat;    /* PCM = 1*/

    short NumChannels;    /* Mono = 1, Stereo = 2, etc. */

    int SampleRate;    /* 8000, 44100, etc. */

    int ByteRate;    /* = SampleRate * NumChannels * BitsPerSample/8 */

    short BlockAlign;    /* = NumChannels * BitsPerSample/8 */    

    short BitsPerSample;    /* 8bits, 16bits, etc. */

    /* sub-chunk "data" */

    char Subchunk2ID[4];    /* "data" */

    int Subchunk2Size;    /* data size */

}WaveHead; 

编写函数读取.wav文件的文件头,并返回文件头长度,数据块的数据长度,指向数据块的指针。

/*****************************************************************************
*@fn    : read wave head and return wave head len

*@input : wh      ,WaveHead point 
        :filename , wave file path point 

*@output: fn      ,file point of data chunk 
        : flen    ,data len 

*@return: head_len,wave head len

*@author:  
*@data  : 
*******************************************************************************/
int WaveReadHead(WaveHead *wh, char *filename,FILE *fn, int *flen)
{

   FILE *fd = NULL;	
   
   if((fd = fopen(filename, "rb")) == NULL) 
   {
	printf("WaveReadHead(): cannot open file %s\n",filename);
   }  
   int head_len = 0;
   fseek(fd, 0L, SEEK_END);
   *flen = ftell(fd);
   fseek(fd,0L, SEEK_SET);
   
   if (1!= fread(wh->ChunkID,4,1,fd))  return -1;
   head_len += sizeof(int);
   if (1!= fread(&wh->ChunkSize,4,1,fd))  return -1;
   head_len += sizeof(int);
   if (1!= fread(wh->Format,4,1,fd))  return -1;
   head_len += 4*sizeof(char);
   if (1!= fread(wh->Subchunk1ID,4,1,fd))  return -1;
   head_len += sizeof(int);
   if (1!= fread(&wh->Subchunk1Size,4,1,fd))  return -1;
   head_len += sizeof(int);
   if (1!= fread(&wh->AudioFormat,2,1,fd))  return -1;
   head_len += sizeof(short);
   
   if (1!= fread(&wh->NumChannels,2,1,fd))  return -1;
   head_len += sizeof(short);
   if (1!= fread(&wh->SampleRate,4,1,fd))  return -1;
   head_len += sizeof(int);
   if (1!= fread(&wh->ByteRate,4,1,fd))  return -1;
   head_len += 4*sizeof(char);
   if (1!= fread(&wh->BlockAlign,2,1,fd))  return -1;
   head_len += sizeof(short);
   if (1!= fread(&wh->BitsPerSample,2,1,fd))  return -1;
   head_len += sizeof(short);
   int i = 0;
   char *str;
   while (i>(wh->Subchunk1Size - 16))
   {
	if(1 != fread(str,1,1,fd))  return -1;
   }
    
   head_len += (wh->Subchunk1Size - 16);
   
   if(1!= fread(wh->Subchunk2ID,4,1,fd)) return -1;
   head_len +=4;
   
   if(1!= fread(&wh->Subchunk2Size,4,1,fd)) return -1;
   head_len +=4;
   
   *flen -=head_len;

   if(strncmp(wh->ChunkID,"RIFF",4)!=0|| strncmp(wh->Subchunk1ID,"fmt",3)!=0||
      strncmp(wh->Format,"WAVE",4)!=0|| strncmp(wh->Subchunk2ID,"data",4)!=0||
      wh->ChunkSize- wh->Subchunk2Size != head_len-8)
   {
     printf("Wave head read err!\n");
     if (fd)  fclose(fd);
   }
   
  
   fn = fd;
   return(head_len);
}

编写一个测试函数。

int main()
{
  FILE *fp = NULL;
  WaveHead wh;
  int flen = 0;
  int head_len = 0;
  char *filename ="0_0_0_0_1_1_1_1.wav";
  if(0!=( head_len = WaveReadHead(&wh,filename,fp,&flen)));
 	 printf("head_len: %d",head_len);
}

使用kaldi yesno 文件“0_0_0_0_1_1_1_1.wav”作为测试,程序运行结果如下:

 

 

 

你可能感兴趣的:(音频信号处理)