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

    xiaoxiao2024-10-21  72

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

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

    wav文件头

    偏移 地址

    字节数

    数据 类型

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

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

    26H4字符数据块标识data2aH4长整型数数据块长度数据块的长度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”作为测试,程序运行结果如下:

     

     

     

    最新回复(0)