基于Visual C++6.0的声音文件操作.docx_第1页
基于Visual C++6.0的声音文件操作.docx_第2页
基于Visual C++6.0的声音文件操作.docx_第3页
基于Visual C++6.0的声音文件操作.docx_第4页
基于Visual C++6.0的声音文件操作.docx_第5页
免费预览已结束,剩余10页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

基于visual c+6.0的声音文件操作-一、前言当前visual c+相关的编程资料中,无论是大部头的参考书,还是一些计算机杂志,对声音文件的处理都是泛泛的涉及一下,许多编程爱好者都感到对该部分的内容了解不是很透彻,本文希望能够给刚刚涉及到声音处理领域的朋友们起到一个引路的作用,帮助他们尽快进入声音处理的更深奥空间。当前计算机系统处理声音文件有两种办法:一是使用现成的软件,如微软的录音机、soundforge、cooledit等软件可以实现对声音信号进行录音、编辑、播放的处理,但它们的功能是有限的,为了更灵活,更大限度地处理声音数据,就不得不使用另外一种方法,既利用微软提供的多媒体服务,在windows环境下自己编写程序来进行声音处理来实现一些特定的功能。下面就开始介绍声音文件的格式和在windows环境下使用visual c+开发工具进行声音文件编程处理的方法,本文所有的程序代码都在windows2000、visual c+6.0环境下编译通过,运行正常。二、riff文件结构和wave文件格式windows支持两种riff(resource interchange file format,资源交互文件格式)格式的音频文件:midi的rmid文件和波形音频文件格式wave文件,其中在计算机领域最常用的数字化声音文件格式是后者,它是微软专门为windows系统定义的波形文件格式(waveform audio),由于其扩展名为*.wav,因而该类文件也被称为wave文件。为了突出重点,有的放矢,本文涉及到的声音文件所指的就是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 格式/列表类型数据图二、riff/list块结构 wave文件是非常简单的一种riff文件,它的格式类型为wave。riff块包含两个子块,这两个子块的id分别是fmt和data,其中fmt子块由结构pcmwaveformat所组成,其子块的大小就是sizeofof(pcmwaveformat),数据组成就是pcmwaveformat结构中的数据。wave文件的结构如下图三所示:标志符(riff)数据大小格式类型(wave)fmtsizeof(pcmwaveformat)pcmwaveformatdata声音数据大小声音数据图三、wave文件结构图 pcmwaveformat结构定义如下: typedef structwaveformat wf;/波形格式;word wbitspersample;/wave文件的采样大小;pcmwaveformat;waveformat结构定义如下:typedef structword wformatag;/编码格式,包括wave_format_pcm,waveformat_adpcm等word nchannls;/声道数,单声道为1,双声道为2;dword nsamplespersec;/采样频率;dword navgbytespersec;/每秒的数据量;word nblockalign;/块对齐;waveformat;data子块包含wave文件的数字化波形声音数据,其存放格式依赖于fmt子块中wformattag成员指定的格式种类,在多声道wave文件中,样本是交替出现的。如16bit的单声道wave文件和双声道wave文件的数据采样格式分别如图四所示:16位单声道: 16位单声道:采样一采样二 低字节高字节低字节高字节 16位双声道:采样一 左声道右声道低字节高字节低字节高字节 图四、wave文件数据采样格式三、声音文件的声音数据的读取操作操作声音文件,也就是将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 style4;/定义一个四字节的数据,用来存放文件的类型;mmioseek(file1,8,seek_set);/定位到wave文件的类型位置mmioread(file1,style,4);if(style0!=w|style1!=a|style2!=v|style3!=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 charsize;/根据数据的大小申请缓冲区;mmioseek(file1,28+sizeof(pcmwaveformat),seek_set);/对文件重新定位;mmioread(file1,(char*)pdata,size);/读取声音数据;mmioclose(file1, mmio_fhopen);/关闭wave文件;return pdata; 四、使用mci方法操作声音文件wave声音文件一个最基本的操作就是将文件中的声音数据播放出来,用windows提供的api函数bool sndplaysound(lpcstr lpszsound, uint fusound)可以实现小型wav文件的播放,其中参数lpszsound 为所要播放的声音文件,fusound为播放声音文件时所用的标志位。例如实现sound.wav 文件的异步播放,只要调用函数sndplaysound(c:windowssound.wav,snd_async)就可以了,由此可以看到sndplaysound函数使用是很简单的。但是当wave文件大于100k时,这时候系统无法将声音数据一次性的读入内存,sndplaysound函数就不能进行播放了。为了解决这个问题,你的一个选择就是用mci方法来操作声音文件了。在使用mci方法之前,首先需要在你开发的项目设置project-setting-link-object/library modules中加入winmm.lib。并在头文件中包括mmsystem.h头文件。microsoft api提供了mci(the media control interface)的方法mcisendcommand()和mcisendstring()来完成wave文件的播放,这里仅介绍mcisendcommand()函数的使用。原型:dword mcisendcommand(uint wdeviceid,uint wmessage,dword dwparam1,dword dwparam2);参数:wdeviceid:接受消息的设备id;message:mci命令消息;wparam1:命令的标志位;wparam2:所使用参数块的指针返值:调用成功,返回零;否则,返回双字中的低字存放有错误信息。在使用mci播放声音文件时,首先要打开音频设备,为此要定义mci_open_parms变量 openparms,并设置该结构的相应分量:openparms.lpstrdevicetype = (lpcstr) mci_devtype_waveform_audio;/wave类型openparms.lpstrelementname = (lpcstr) filename;/打开的声音文件名;openparms.wdeviceid = 0;/打开的音频设备的idmcisendcommand (null, mci_open,mci_wait | mci_open_type | mci_open_type_id | mci_open_element, (dword)(lpvoid) &openparms)函数调用发送mci_open命令后,返回的参数 openparms中成员变量的wdeviceid指明打开了哪个设备。需要关闭音频设备时只要调用mcisendcommand (m_wdeviceid, mci_close, null, null)就可以了。 播放wave文件时,需要定义mci_play_parms变量playparms,对该变量进行如下设置:playparms.dwfrom = 0,这是为了指定从什么地方(时间)播放wave文件,设置好以后,调用函数mcisendcommand (m_wdeviceid, mci_play,mci_from, (dword)(lpvoid)&playparms);就实现了wave声音文件的播放。另外,调用mcisendcommand (m_wdeviceid, mci_pause, 0,(dword)(lpvoid)&playparms)实现了暂停功能。调用mcisendcommand (m_wdeviceid, mci_stop, null, null)实现停止功能等,可以看出,这些不同的功能实现都是依靠参数message取不同的值来实现的。 不同的message和dwparam1、dwparam2的组合还可以实现文件的 跳跃功能。如下面的代码实现了跳转到wave文件末端的操作:mcisendcommand (m_wdeviceid, mci_seek, mci_seek_to_end, null)。下面的代码实现了wave声音文件的播放:void ctest1view:onmciplaywave() / todo: add your command handler code heremci_open_parms mciopenparms;mci_play_parms playparms;mciopenparms.dwcallback=0;mciopenparms.lpstrelementname=d:chimes.wav;mciopenparms.wdeviceid=0;mciopenparms.lpstrdevicetype=waveaudio;mciopenparms.lpstralias= ;playparms.dwcallback=0;playparms.dwto=0;playparms.dwfrom=0;mcisendcommand(null,mci_open,mci_open_type|mci_open_element,(dword)(lpvoid)&mciopenparms);/打开音频设备;mcisendcommand(mciopenparms.wdeviceid,mci_play,mci_wait,(dword)(lpvoid)&playparms);/播放wave声音文件;mcisendcommand(mciopenparms.wdeviceid,mci_close,null,null);/关闭音频设备; 五、directsound操作wave文件的方法mci虽然调用简单,功能强大,可以满足声音文件处理的基本需要,但是mci也有它的缺点,那就是它一次只能播放一个wave文件,有时在实际应用中,为了实现混音效果,需要同时播放两个或两个以上的wave文件时,就需要使用微软directx技术中的directsound了,该技术直接操作底层声卡设备,可以实现八个以上wav文件的同时播放。实现directsound需要以下几个步骤:1.创建及初始化directsound;2.设定应用程序的声音设备优先级别方式,一般为dsscl_normal;2. 将wav文件读入内存,找到格式块、数据块位置及数据长度;3.创建声音缓冲区;4.载入声音数据;5.播放及停止:下面的函数利用directsound技术实现了一个wave声音文件的播放(注意项目设置中要包含dsound.lib、dxguid.lib的内容),代码和注释如下:void cplaysoundview:onplaysound() / todo: add your command handler code herelpvoid lpptr1;/指针1;lpvoid lpptr2;/指针2;hresult hresult;dword dwlen1,dwlen2;lpvoid m_pmemory;/内存指针;lpwaveformatex m_pformat;/lpwaveformatex变量;lpvoid m_pdata;/指向语音数据块的指针;dword m_dwsize;/wave文件中语音数据块的长度;cfile file;/cfile对象;dword dwsize;/存放wav文件长度;/打开sound.wav文件;if (!file.open (d:/sound.wav, cfile:moderead |cfile:sharedenynone)return ;dwsize = file.seek (0, cfile:end);/获取wave文件长度;file.seek (0, cfile:begin);/定位到打开的wave文件头;/为m_pmemory分配内存,类型为lpvoid,用来存放wave文件中的数据;m_pmemory = globalalloc (gmem_fixed, dwsize);if (file.readhuge (m_pmemory, dwsize) != dwsize)/读取文件中的数据;file.close ();return ;file.close ();lpdword pdw,pdwend;dword dwriff,dwtype, dwlength;if (m_pformat) /格式块指针m_pformat = null;if (m_pdata) /数据块指针,类型:lpbytem_pdata = null;if (m_dwsize) /数据长度,类型:dwordm_dwsize = 0;pdw = (dword *) m_pmemory;dwriff = *pdw+;dwlength = *pdw+;dwtype = *pdw+;if (dwriff != mmiofourcc (r, i, f, f)return ;/判断文件头是否为riff字符;if (dwtype != mmiofourcc (w, a, v, e)return ;/判断文件格式是否为wave;/寻找格式块,数据块位置及数据长度pdwend = (dword *)(byte *) m_pmemory+dwlength -4);bool m_bend=false;while (pdw pdwend)&(!m_bend)/pdw文件没有指到文件末尾并且没有获取到声音数据时继续;dwtype = *pdw+;dwlength = *pdw+;switch (dwtype)case mmiofourcc(f, m, t, ):/如果为fmt标志;if (!m_pformat)/获取lpwaveformatex结构数据;if (dwlength setcooperativelevel(this-getsafehwnd(), dsscl_normal);/设置声音设备优先级别为normal;/创建声音数据缓冲;lpdirectsoundbuffer m_pdsoundbuffer;if (m_lpdirectsound-createsoundbuffer (&bufferdesc, &m_pdsoundbuffer, 0) = ds_ok)/载

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论