基于VisualC++6.0的声音文件操作

上传人:B**** 文档编号:51481569 上传时间:2022-01-26 格式:DOCX 页数:15 大小:121.67KB
收藏 版权申诉 举报 下载
基于VisualC++6.0的声音文件操作_第1页
第1页 / 共15页
基于VisualC++6.0的声音文件操作_第2页
第2页 / 共15页
基于VisualC++6.0的声音文件操作_第3页
第3页 / 共15页
资源描述:

《基于VisualC++6.0的声音文件操作》由会员分享,可在线阅读,更多相关《基于VisualC++6.0的声音文件操作(15页珍藏版)》请在装配图网上搜索。

1、基于 Visual C+6.0的声音文件操作一、前言当前 Visual C+ 相关的编程资料中,无论是大部头的参考书,还是一些计算机杂志,对声音文件的处理都是泛泛的涉及一下, 许多编程爱好者都感到对该部分的内容了解不是很透彻, 本文希望能够给刚刚涉及到声音处理领域的朋友们起到一个引路的作用,帮助他们尽快进入声音处理的更深奥空间。当前计算机系统处理声音文件有两种办法: 一是使用现成的软件, 如微软的录音机、 SoundForge 、CoolEdit 等软件可以实现对声音信号进行录音、编辑、播放的处理,但它们的功能是有限的,为了更灵活,更大限度地处理声音数据,就不得不使用另外一种方法,既利用微软提

2、供的多媒体服务,在 Windows 环境下自己编写程序来进行声音处理来实现一些特定的功能。 下面就开始介绍声音文件的格式和在 Windows 环境下使用 Visual C+ 开发工具进行声音文件编程处理的方法,本文所有的程序代码都在 Windows2000 、Visual C+6.0 环境下编译通过,运行正常。二、 RIFF 文件结构和 WAVE 文件格式Windows 支持两种 RIFF(Resource Interchange File Format, 资源交互文件格式 )格式的音频文件: MIDI 的 RMID 文件和波形音频文件格式 WAVE 文件,其中在计算机领域最常用的数字化声音文

3、件格式是后者,它是微软专门为Windows 系统定义的波形文件格式 (Waveform Audio ),由于其扩展名为 *.wav ,因而该类文件也被称为WAVE 文件。为了突出重点,有的放矢,本文涉及到的声音文件所指的就是 WAVE 文件。常见的 WAVE 语音文件主要有两种, 分别对应于单声道(11.025KHz 采样率、 8Bit 的采样值)和双声道(44.1KHz 采样率、 16Bit 的采样值)。这里的采样率是指声音信号在进行 模数 转换过程中单位时间内采样的次数。 采样值是指每一次采样周期内声音模拟信号的积分值。对于单声道声音文件,采样数据为八位的短整数(short int 00H

4、-FFH );而对于双声道立体声声音文件,每次采样数据为一个16 位的整数( int),高八位和低八位分别代表左右两个声道。WAVE 文件数据块包含以脉冲编码调制(PCM )格式表示的样本。在进行声音编程处理以前,首先让我们来了解一下RIFF 文件和WAVE 文件格式。RIFF 文件结构可以看作是树状结构, 其基本构成是称为 块 (Chunk )的单元,每个块有 标志符 、数据大小 及 数据 所组成,块的结构如图 1 所示:块的标志符( 4BYTES )数据大小(4BYTES )数据图一、块的结构示意图从上图可以看出,其中 标志符 为 4 个字符所组成的代码, 如RIFF ,LIST等,指定块

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

6、 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(PCM

7、WAVEFORMAT)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;/采样

8、频率;DWORD nAvgBytesperSec; /每秒的数据量;WORD nBlockAlign;/ 块对齐;WAVEFORMAT ;data 子块包含 WAVE 文件的数字化波形声音数据,其存放格式依赖于fmt 子块中 wFormatTag 成员指定的格式种类,在多声道 WAVE 文件中,样本是交替出现的。如 16bit 的单声道 WAVE 文件和双声道 WAVE 文件的数据采样格式分别如图四所示:16 位单声道:16 位单声道:采样一采样二低字节高字节低字节高字节16 位双声道:左声道低字节高字节采样一右声道低字节高字节图四、 WAVE 文件数据采样格式三、声音文件的声音数据的读取操作

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

10、 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

11、)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 格式的文件! );Ret

12、urn NULL;PCMWAVEFORMAT format; /定义 PCMWAVEFORMAT结构对象,用来判断 WAVE 文件格式;mmioSeek(file1,20,SEEK_SET);/对打开的文件进行定位,此时指向WAVE 文件的 PCMWAVEFORMAT结构的数据;mmioRead(file1,(char*)&format,sizeof(PCMWAVEFORMAT);/获取该结构的数据;判断是否是立体声声音;MessageBox( 该声音文件不是双通道立体声文件);return NULL;mmioSeek(file1,24+sizeof(PCMWAVEFORMAT),SEEK_S

13、ET);/获取 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 声音文件一

14、个最基本的操作就是将文件中的声音数据播放出来,用Windows 提供的 API 函数 BOOL sndPlaySound(LPCSTR lpszSound, UINTfuSound)可以实现小型WAV文件的播放,其中参数lpszSound为所要播放的声音文件,fuSound为播放声音文件时所用的标志位。例如实现Sound.wav文件的异步播放,只要调用函数sndPlaySound(c:windowsSound.wav,SND_ASYNC)就可以了,由此可以看到 sndPlaySound 函数使用是很简单的。但是当 WAVE 文件大于 100K 时,这时候系统无法将声音数据一次性的读入内存, s

15、ndPlaySound 函数就不能进行播放了。为了解决这个问题,你的一个选择就是用 MCI 方法来操作声音文件了。在使用 MCI 方法之前,首先需要在你开发的项目设置Project-Setting-Link-Object/library modules中加入 winmm.lib 。并在头文件中包括 mmsystem.h 头文件。MicroSoft API 提供了 MCI(The Media Control Interface)的方法mciSendCommand ()和 mciSendString ()来完成 WAVE 文件的播放,这里仅介绍 mciSendCommand ()函数的使用。原型:

16、DWORD mciSendCommand (UINT wDeviceID ,UINT wMessage ,DWORD dwParam1 ,DWORD dwParam2 );参数: wDeviceID :接受消息的设备ID;Message : MCI 命令消息;wParam1 :命令的标志位;wParam2 :所使用参数块的指针返值:调用成功,返回零;否则,返回双字中的低字存放有错误信息。在使用 MCI 播放声音文件时,首先要打开音频设备,为此要定义MCI_OPEN_PARMS变量 OpenParms ,并设置该结构的相应分量:OpenParms.lpstrDeviceType = (LPCST

17、R)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 指明打

18、开了哪个设备。需要关闭音频设备时只要调用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声音文件的播放。另外,调用 mciSendComm

19、and (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

20、)。下面的代码实现了WAVE 声音文件的播放:void CTest1View:OnMciPlayWave()/ TODO: Add your command handler code here MCI_OPEN_PARMS mciOpenParms; MCI_PLAY_PARMS PlayParms; mciOpenParms.dwCallback=0; mciOpenParms.lpstrElementName=d:chimes.wav; mciOpenParms.wDeviceID=0; mciOpenParms.lpstrDeviceType=waveaudio; mciOpenParm

21、s.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.wD

22、eviceID,MCI_CLOSE,NULL,NULL);/关闭音频设备;五、 DirectSound操作 WAVE 文件的方法MCI 虽然调用简单,功能强大,可以满足声音文件处理的基本需要,但是MCI 也有它的缺点,那就是它一次只能播放一个WAVE 文件,有时在实际应用中,为了实现混音效果,需要同时播放两个或两个以上的 WAVE 文件时,就需要使用微软 DirectX 技术中的 DirectSound 了,该技术直接操作底层声卡设备,可以实现八个以上 WAV 文件的同时播放。实现 DirectSound 需要以下几个步骤 :1.创建及初始化 DirectSound ;2.设定应用程序的声音设

23、备优先级别方式 ,一般为 DSSCL_NORMAL ;2. 将 WAV 文件读入内存 ,找到格式块、数据块位置及数据长度; 3.创建声音缓冲区; 4.载入声音数据; 5.播放及停止 :下面的函数利用 DirectSound 技术实现了一个 WAVE 声音文件的播放(注意项目设置中要包含 dsound.lib 、dxguid.lib 的内容),代码和注释如下:void CPlaysoundView:OnPlaySound()/ TODO: Add your command handler code here LPVOID lpPtr1;/ 指针 1;LPVOID lpPtr2;/ 指针 2;HR

24、ESULT 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 ;dw

25、Size = 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;D

26、WORD 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 (

27、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_p

28、Format)/ 获取 LPWAVEFORMATEX 结构数据; if (dwLength SetCooperativeLevel(this-GetSafeHwnd(),DSSCL_NORMAL);/设置声音设备优先级别为NORMAL ;/创建声音数据缓冲;LPDIRECTSOUNDBUFFER m_pDSoundBuffer;if (m_lpDirectSound-CreateSoundBuffer (&BufferDesc, &m_pDSoundBuffer, 0) = DS_OK)/载入声音数据,这里使用两个指针 lpPtr1,lpPtr2 来指向 DirectSoundBuffer 缓

29、冲区的数据,这是为了处理大型 WAVE 文件而设计的。 dwLen1,dwLen2 分别对应这两个指针所指向的缓冲区的长度。hResult=m_pDSoundBuffer-Lock(0,m_dwSize,&lpPtr1,&dwLen1,&lpPtr2,& dwLen2,0);if (hResult = DS_OK)memcpy (lpPtr1, m_pData, dwLen1);if(dwLen20)BYTE *m_pData1=(BYTE*)m_pData+dwLen1;m_pData=(void *)m_pData1;memcpy(lpPtr2,m_pData, dwLen2);m_pDS

30、oundBuffer-Unlock (lpPtr1, dwLen1, lpPtr2, dwLen2);DWORD dwFlags = 0;m_pDSoundBuffer-Play (0, 0, dwFlags); /播放 WAVE 声音数据;为了更好的说明 DiretSound 编程的实现,笔者使用了一个函数来实现所有的操作,当然读者可以将上面的内容包装到一个类中,从而更好的实现程序的封装性,至于如何实现就不需要笔者多说了,真不明白的话, 找本 C+ 的书看看。如果定义了类,那么就可以一次声明多个对象来实现多个WAVE 声音文件的混合播放。也许细心的读者会发现,在介绍WAVE 文件格式的时候我们介绍了PCMWAVEFORMAT结构,但是在代码的实现读取WAVE 文件数据部分, 我们使用的却是 LPWAVEFORMATEX结构,那末是不是我们有错误呢?其实没有错,对于 PCM 格式的 WAVE 文件来说,这两个结构是完全一样的,使用LPWAVEFORMATEX结构不过是为了方便设置DSBUFFERDESC对象罢了。操作 WAVE 声音文件的方法很多,灵活的运用它们可以灵活地操作WAVE文件,这些函数的详细用途读者可以参考MSDN 。本文只是对 WAVE 文件的操作作了一个肤浅的介绍,希望可以对读者起到抛砖引玉的作用。

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

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!