分享

【音频】Wav和Pcm格式文件详解

 zhouADNjj 2014-03-04

一,Windows支持两种RIFF(Resource Interchange File Format,“资源交互文件格式”)格式的音频文件

        MIDI的RMID文件和波形音频文件格式WAVE文件

        在计算机领域最常用的数字化声音文件格式是后者,它是微软专门为Windows系统定义的波形文件格式(Waveform Audio),由于其扩展名为"*.wav",因而该类文件也被称为WAVE文件

        常见的WAVE语音文件主要有两种,分别对应于单声道(11.025KHz采样率、8Bit的采样值)和双声道(44.1KHz采样率、16Bit的采样值)

        这里的采样率是指声音信号在进行"模→数"转换过程中单位时间内采样的次数采样值是指每一次采样周期内声音模拟信号的积分值。

             对于单声道声音文件,采样数据为八位的短整数(short int 00H-FFH);

            对于双声道立体声声音文件,每次采样数据为一个16位的整数(int),高八位和低八位分别代表左右两个声道。

        WAVE文件数据块包含以脉冲编码调制(PCM)格式表示的样本。

二,RIFF文件和WAVE文件格式。

    RIFF文件结构可以看作是树状结构,其基本构成是称为"块"(Chunk)的单元,每个块有"标志符"、"数据大小"及"数据"所组成,块的结构如图1所示:

块的标志符(4BYTES)
数据大小 (4BYTES)
数据

  "标志符"为4个字符所组成的代码,如"RIFF","LIST"等,指定块的标志ID;

   “数据大小”用来指定块的数据域大小,它的尺寸也为4个字符;

   “数据”用来描述具体的声音信号,它可以由若干个子块构成,一般情况下块与块是平行的,不能相互嵌套,但是有两种类型的块可以嵌套子块,他们是"RIFF"或"LIST"标志的块,其中RIFF块的级别最高,它可以包括LIST块。另外,RIFF块和LIST块与其他块不同,RIFF块的数据总是以一个指定文件中数据存储格式的四个字符码(称为格式类型)开始,如WAVE文件有一个"WAVE"的格式类型。LIST块的数据总是以一个指定列表内容的4个字符码(称为列表类型)开始,例如扩展名为".AVI"的视频文件就有一个"strl"的列表类型。

    RIFF和LIST的块结构如下:


RIFF/LIST标志符
数据1大小
数据1 格式/列表类型
数据


WAVE文件是非常简单的一种RIFF文件,它的格式类型为"WAVE"。RIFF块包含两个子块,这两个子块的ID分别是"fmt"和"data",其中"fmt"子块由结构PCMWAVEFORMAT所组成,其子块的大小就是sizeofof(PCMWAVEFORMAT),数据组成就是PCMWAVEFORMAT结构中的数据。

    WAVE文件的结构如下图三所示:

标志符(RIFF)
数据大小
格式类型("WAVE")
"fmt"
Sizeof(PCMWAVEFORMAT)
PCMWAVEFORMAT
"data"
声音数据大小
声音数据

  PCMWAVEFORMAT结构定义如下:

Typedef struct
{
    WAVEFORMAT wf;       //波形格式;
    WORD wBitsPerSample; //WAVE文件的采样大小;
}PCMWAVEFORMAT;

    WAVEFORMAT结构定义如下:
typedef struct
{
    WORD wFormatag;//编码格式,包括WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM等
    WORD nChannls;//声道数,单声道为1,双声道为2;
    DWORD nSamplesPerSec;//采样频率;
    DWORD nAvgBytesperSec;//每秒的数据量;
    WORD nBlockAlign;//块对齐;
}WAVEFORMAT;

三、声音文件的声音数据的读取操作

  操作声音文件,也就是将WAVE文件打开,获取其中的声音数据,根据所需要的声音数据处理算法,进行相应的数学运算,然后将结果重新存储与WAVE格式的文件中去。可以使用CFILE类来实现读取操作,也可以使用另外一种方法,拿就是使用Windows提供的多媒体处理函数(这些函数都以mmino打头)。这里就介绍如何使用这些相关的函数来获取声音文件的数据,至于如何进行处理,那要根据你的目的来选择不同的算法了。WAVE文件的操作流程如下:


  1.调用mminoOpen函数来打开WAVE文件,获取HMMIO类型的文件句柄;

  2.根据WAVE文件的结构,调用mmioRead、mmioWrite和mmioSeek函数实现文件的读、写和定位操作;

  3.调用mmioClose函数来关闭WAVE文件。

  下面的函数代码就是根据WAVE文件的格式,实现了读取双声道立体声数据,但是在使用下面的代码过程中,注意需要在程序中链接Winmm.lib库,并且包含头文件"Mmsystem.h"。

BYTE * GetData(Cstring *pString) //获取声音文件数据的函数,pString参数指向要打开的声音文件;
{
	if (pString==NULL)
		return NULL;
	HMMIO file1;//定义HMMIO文件句柄;
	file1=mmioOpen((LPSTR)pString,NULL,MMIO_READWRITE);//以读写模式打开所给的WAVE文件;
	if(file1==NULL)
	{
		MessageBox("WAVE文件打开失败!");
		Return NULL;
	}
	char style[4];//定义一个四字节的数据,用来存放文件的类型;
	mmioSeek(file1,8,SEEK_SET);//定位到WAVE文件的类型位置
	mmioRead(file1,style,4);
	if(style[0]!='W'||style[1]!='A'||style[2]!='V'||style[3]!='E')//判断该文件是否为"WAVE"文件格式
	{
		MessageBox("该文件不是WAVE格式的文件!");
		Return NULL;
	}
	PCMWAVEFORMAT format; //定义PCMWAVEFORMAT结构对象,用来判断WAVE文件格式;
	mmioSeek(file1,20,SEEK_SET);//对打开的文件进行定位,此时指向WAVE文件的PCMWAVEFORMAT结构的数据;
	mmioRead(file1,(char*)&format,sizeof(PCMWAVEFORMAT));//获取该结构的数据;
	if(format.wf.nChannels!=2)//判断是否是立体声声音;
	{
		MessageBox("该声音文件不是双通道立体声文件");
		return NULL;
	}
	mmioSeek(file1,24+sizeof(PCMWAVEFORMAT),SEEK_SET);//获取WAVE文件的声音数据的大小;
	long size;
	mmioRead(file1,(char*)&size,4);
	BYTE *pData;
	pData=(BYTE*)new char[size];//根据数据的大小申请缓冲区;
	mmioSeek(file1,28+sizeof(PCMWAVEFORMAT),SEEK_SET);//对文件重新定位;
	mmioRead(file1,(char*)pData,size);//读取声音数据;
	mmioClose(file1, MMIO_FHOPEN);//关闭WAVE文件;
	return pData;
}


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多