版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、基于Visual C+6.0工具下的声音文件操作声音是人类传递信息的重要途径,如果应用程序中包含声音信息,就可以大大增强它的亲合力;另外在科研开发过程中,声音信号的处理也是一个很重要的科学研究领域。Visual C+作为一个强大的开发工具,当然是声音处理的首选工具,但是在当前Visual C+相关的编程资料中,无论是大部头的参考书,还是一些计算机杂志,对声音文件的处理都是泛泛的涉及一下,许多编程爱好者都感到对该部分的内容了解不是很透彻,笔者结合自己的学习和开发过程中积累的一些经验,在本实例中来和广大编程爱好者们探讨一下声音文件的处理,当然本实例也不可能包括声音处理内容的方方面面,只是希望它能够
2、对刚刚涉及到声音处理领域的朋友们起到一个引路的作用,帮助他们尽快进入声音处理的更深奥空间。当前计算机系统处理声音文件有两种办法:一是使用现成的软件,如微软的录音机、SoundForge、CoolEdit等软件可以实现对声音信号进行录音、编辑、播放的处理,但它们的功能是有限的,为了更灵活,更大限度地处理声音数据,就不得不使用另外一种方法,既利用微软提供的多媒体服务,在Windows环境下自己编写程序来进行声音处理来实现一些特定的功能。下面就开始介绍声音文件的格式和在Windows环境下使用Visual C+开发工具进行声音文件编程处理的方法。一、实现方法1、RIFF文件结构和WAVE文件格式Wi
3、ndows支持两种RIFF(Resource Interchange File Format,"资源交互文件格式")格式的音频文件:MIDI的RMID文件和波形音频文件格式WAVE文件,其中在计算机领域最常用的数字化声音文件格式是后者,它是微软专门为Windows系统定义的波形文件格式(Waveform Audio),由于其扩展名为"*.wav",因而该类文件也被称为WAVE文件。为了突出重点,有的放矢,本文涉及到的声音文件所指的就是WAVE文件。常见的WAVE语音文件主要有两种,分别对应于单声道(11.025KHz采样率、8Bit的采样值)和双声道(4
4、4.1KHz采样率、16Bit的采样值)。这里的采样率是指声音信号在进行"模数"转换过程中单位时间内采样的次数。采样值是指每一次采样周期内声音模拟信号的积分值。对于单声道声音文件,采样数据为八位的短整数(short int 00H-FFH);而对于双声道立体声声音文件,每次采样数据为一个16位的整数(int),高八位和低八位分别代表左右两个声道。WAVE文件数据块包含以脉冲编码调制(PCM)格式表示的样本。在进行声音编程处理以前,首先让我们来了解一下RIFF文件和WAVE文件格式。RIFF文件结构可以看作是树状结构,其基本构成是称为"块"(Chunk)的
5、单元,每个块有"标志符"、"数据大小"及"数据"所组成,块的结构如图1所示:块的标志符(4BYTES)数据大小 (4BYTES)数据图一、 块的结构示意图从上图可以看出,其中"标志符"为4个字符所组成的代码,如"RIFF","LIST"等,指定块的标志ID;数据大小用来指定块的数据域大小,它的尺寸也为4个字符;数据用来描述具体的声音信号,它可以由若干个子块构成,一般情况下块与块是平行的,不能相互嵌套,但是有两种类型的块可以嵌套子块,他们是"RIFF"或&q
6、uot;LIST"标志的块,其中RIFF块的级别最高,它可以包括LIST块。另外,RIFF块和LIST块与其他块不同,RIFF块的数据总是以一个指定文件中数据存储格式的四个字符码(称为格式类型)开始,如WAVE文件有一个"WAVE"的格式类型。LIST块的数据总是以一个指定列表内容的4个字符码(称为列表类型)开始,例如扩展名为".AVI"的视频文件就有一个"strl"的列表类型。RIFF和LIST的块结构如下:RIFF/LIST标志符数据1大小数据1格式/列表类型数据 图二、RIFF/LIST块结构WAVE文件是非
7、常简单的一种RIFF文件,它的格式类型为"WAVE"。RIFF块包含两个子块,这两个子块的ID分别是"fmt"和"data",其中"fmt"子块由结构PCMWAVEFORMAT所组成,其子块的大小就是sizeofof(PCMWAVEFORMAT),数据组成就是PCMWAVEFORMAT结构中的数据。WAVE文件的结构如下图三所示:标志符(RIFF)数据大小格式类型("WAVE")"fmt"Sizeof(PCMWAVEFORMAT)PCMWAVEFORMAT"data
8、"声音数据大小声音数据 图三、WAVE文件结构 PCMWAVEFORMAT结构定义如下:Typedef structWAVEFORMAT wf;/波形格式;WORD wBitsPerSample;/WAVE文件的采样大小;PCMWAVEFORMAT;WAVEFORMAT结构定义如下:typedef structWORD wFormatag;/编码格式,包括WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM等WORD nChannls;/声道数,单声道为1,双声道为2;DWORD nSamplesPerSec;/采样频率;DW
9、ORD nAvgBytesperSec;/每秒的数据量;WORD nBlockAlign;/块对齐;WAVEFORMAT;"data"子块包含WAVE文件的数字化波形声音数据,其存放格式依赖于"fmt"子块中wFormatTag成员指定的格式种类,在多声道WAVE文件中,样本是交替出现的。如16bit的单声道WAVE文件和双声道WAVE文件的数据采样格式分别如图四所示:16位单声道:采样一 采样二低字节高字节低字节高字节16位双声道:采样一左声道右声道低字节高字节低字节高字节图四、WAVE文件数据采样格式 2、声音文
10、件的声音数据的读取操作操作声音文件,也就是将WAVE文件打开,获取其中的声音数据,根据所需要的声音数据处理算法,进行相应的数学运算,然后将结果重新存储与WAVE格式的文件中去。可以使用CFILE类来实现读取操作,也可以使用另外一种方法,拿就是使用Windows提供的多媒体处理函数(这些函数都以mmino打头)。这里就介绍如何使用这些相关的函数来获取声音文件的数据,至于如何进行处理,那要根据你的目的来选择不同的算法了。WAVE文件的操作流程如下:1)调用mminoOpen函数来打开WAVE文件,获取HMMIO类型的文件句柄;2)根据WAVE文件的结构,调用mmioRead、mmioWrite和m
11、mioSeek函数实现文件的读、写和定位操作;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,NUL
12、L,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&qu
13、ot;文件格式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(
14、"该声音文件不是双通道立体声文件");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);/
15、读取声音数据;mmioClose(file1, MMIO_FHOPEN);/关闭WAVE文件;return pData;3、使用MCI方法操作声音文件 WAVE声音文件一个最基本的操作就是将文件中的声音数据播放出来,用Windows提供的API函数BOOL sndPlaySound(LPCSTR lpszSound, UINT fuSound)可以实现小型WAV文件的播放,其中参数lpszSound 为所要播放的声音文件,fuSound为播放声音文件时所用的标志位。例如实现Sound.wav 文件的异步播放,只要调用函数sndPlaySound("c:windowsSound.wav
16、",SND_ASYNC)就可以了,由此可以看到sndPlaySound函数使用是很简单的。但是当WAVE文件大于100K时,这时候系统无法将声音数据一次性的读入内存,sndPlaySound函数就不能进行播放了。为了解决这个问题,你的一个选择就是用MCI方法来操作声音文件了。在使用MCI方法之前,首先需要在你开发的项目设置Project->Setting->Link->Object/library modules中加入winmm.lib。并在头文件中包括"mmsystem.h"头文件。MicroSoft API提供了MCI(The Media C
17、ontrol Interface)的方法mciSendCommand()和mciSendString()来完成WAVE文件的播放,这里仅介绍mciSendCommand()函数的使用。原型:DWORD mciSendCommand(UINT wDeviceID,UINT wMessage,DWORD dwParam1,DWORD dwParam2);参数:wDeviceID:接受消息的设备ID;Message:MCI命令消息;wParam1:命令的标志位;wParam2:所使用参数块的指针返值:调用成功,返回零;否则,返回双字中的低字存放有错误信息。在使用MCI播放声音文件时,首先要打开音频设
18、备,为此要定义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, (D
19、WORD)(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,
20、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的组合还可以实现文件的 跳跃功能。如下
21、面的代码实现了跳转到WAVE文件末端的操作:mciSendCommand (m_wDeviceID, MCI_SEEK, MCI_SEEK_TO_END, NULL)。4、DirectSound操作WAVE文件的方法MCI虽然调用简单,功能强大,可以满足声音文件处理的基本需要,但是MCI也有它的缺点,那就是它一次只能播放一个WAVE文件,有时在实际应用中,为了实现混音效果,需要同时播放两个或两个以上的WAVE文件时,就需要使用微软DirectX技术中的DirectSound了,该技术直接操作底层声卡设备,可以实现八个以上WAV文件的同时播放。实现DirectSound需要以下几个步骤:1.创建
22、及初始化DirectSound;2.设定应用程序的声音设备优先级别方式,一般为DSSCL_NORMAL;2. 将WAV文件读入内存,找到格式块、数据块位置及数据长度;3.创建声音缓冲区;4.载入声音数据;5.播放及停止: 二、编程步骤1、 启动Visual C+6.0生成一个单文档视图结构的应用程序,将该程序命名为"playsound";2、 在程序的主菜单中添加"MCI Play"、"PlaySound"菜单,并使用Class Wizard添加相应的消息响应函说,分别用不同的方法来处理声音文件;3、 在程序的"Link&q
23、uot;设置中添加"dsound.lib、dxguid.lib、winmm.lib"库,程序的视图类中包含"mmsystem.h"文件,程序的Debug目录下添加待播放的声音文件"chimes.wav和sound.wav";4、 添加代码,编译运行程序; 三、程序代码/void CPlaysoundView:OnMciplay()/下面的代码实现了WAVE声音文件的播放:/ TODO: Add your command handler code hereMCI_OPEN_PARMS mciOpenParms;M
24、CI_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_O
25、PEN,MCI_OPEN_TYPEMCI_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声音文件的播放(注意项目设置中要包含"dso
26、und.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;/WA
27、VE文件中语音数据块的长度;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 = G
28、lobalAlloc (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;pd
29、w = (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";/寻找格
30、式块,数据块位置及数据长度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_pFor
31、mat)/获取LPWAVEFORMATEX结构数据;if (dwLength < sizeof (WAVEFORMAT)return ;m_pFormat = (LPWAVEFORMATEX) pdw;break;case mmioFOURCC('d', 'a', 't', 'a'):/如果为"data"标志;if (!m_pData !m_dwSize)m_pData = (LPBYTE) pdw;/得到指向声音数据块的指针;m_dwSize = dwLength;/获取声音数据块的长度;if (m_p
32、Format)m_bend=TRUE;break;pdw = (DWORD *)(BYTE *) pdw + (dwLength + 1)&1);/修改pdw指针,继续循环;DSBUFFERDESC BufferDesc;/定义DSUBUFFERDESC结构对象;memset (&BufferDesc, 0, sizeof (BufferDesc);BufferDesc.lpwfxFormat = (LPWAVEFORMATEX)m_pFormat;BufferDesc.dwSize = sizeof (DSBUFFERDESC);BufferDesc.dwBufferBytes = m_dwSize;BufferDesc.dwFlags = 0;HRESULT hRes;LPDIRECTSOUND m_lpDirectSound;hRes = :DirectSoundCreate(0, &m_lpDirectSound, 0);/创建DirectSound对象;if( hRes != DS_OK )return;m_lpDirectSound->SetCooperativeLevel(this->GetSafeHwnd(), DSSCL_NORMAL);/设置声音设备优先级别
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 二零二五年自动化设备快速运输合同3篇
- 二零二五版家电回收与翻新销售合同范本3篇
- 二零二五版茶叶种植基地农业科技示范推广合同3篇
- 二零二五版矿山洞采矿施工环保责任合同3篇
- 二零二五年度建筑工程款抵顶工业地产使用权合同3篇
- 二零二五版LNG运输及船舶维修合同3篇
- 二零二五版企业股份回购合同协议书6篇
- 二零二五年高铁站广告牌施工与商业合作合同范本3篇
- 二零二五年度深圳物业管理合同规定2篇
- 二零二五年度防雷安全风险评估与整改合同3篇
- 直播代运营服务合同范本版
- 2024年江苏苏州中考数学试卷及答案
- 2024年山东省高中自主招生数学模拟试卷试题(含答案)
- 算术平方根2课件
- 【人教版】九年级化学上册期末试卷及答案【【人教版】】
- 四年级数学上册期末试卷及答案【可打印】
- 人教版四年级数学下册课时作业本(含答案)
- 中小学人工智能教育方案
- 高三完形填空专项训练单选(部分答案)
- 护理查房高钾血症
- 项目监理策划方案汇报
评论
0/150
提交评论