基于Visual C++60的声音文件操作文档格式.docx

上传人:b****4 文档编号:6762927 上传时间:2023-05-07 格式:DOCX 页数:12 大小:22.97KB
下载 相关 举报
基于Visual C++60的声音文件操作文档格式.docx_第1页
第1页 / 共12页
基于Visual C++60的声音文件操作文档格式.docx_第2页
第2页 / 共12页
基于Visual C++60的声音文件操作文档格式.docx_第3页
第3页 / 共12页
基于Visual C++60的声音文件操作文档格式.docx_第4页
第4页 / 共12页
基于Visual C++60的声音文件操作文档格式.docx_第5页
第5页 / 共12页
基于Visual C++60的声音文件操作文档格式.docx_第6页
第6页 / 共12页
基于Visual C++60的声音文件操作文档格式.docx_第7页
第7页 / 共12页
基于Visual C++60的声音文件操作文档格式.docx_第8页
第8页 / 共12页
基于Visual C++60的声音文件操作文档格式.docx_第9页
第9页 / 共12页
基于Visual C++60的声音文件操作文档格式.docx_第10页
第10页 / 共12页
基于Visual C++60的声音文件操作文档格式.docx_第11页
第11页 / 共12页
基于Visual C++60的声音文件操作文档格式.docx_第12页
第12页 / 共12页
亲,该文档总共12页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

基于Visual C++60的声音文件操作文档格式.docx

《基于Visual C++60的声音文件操作文档格式.docx》由会员分享,可在线阅读,更多相关《基于Visual C++60的声音文件操作文档格式.docx(12页珍藏版)》请在冰点文库上搜索。

基于Visual C++60的声音文件操作文档格式.docx

LIST"

等,指定块的标志ID;

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

数据用来描述具体的声音信号,它可以由若干个子块构成,一般情况下块与块是平行的,不能相互嵌套,但是有两种类型的块可以嵌套子块,他们是"

或"

标志的块,其中RIFF块的级别最高,它可以包括LIST块。

另外,RIFF块和LIST块与其他块不同,RIFF块的数据总是以一个指定文件中数据存储格式的四个字符码(称为格式类型)开始,如WAVE文件有一个"

WAVE"

的格式类型。

LIST块的数据总是以一个指定列表内容的4个字符码(称为列表类型)开始,例如扩展名为"

.AVI"

的视频文件就有一个"

strl"

的列表类型。

RIFF和LIST的块结构如下:

RIFF/LIST标志符

数据1大小

数据1

格式/列表类型

图二、RIFF/LIST块结构

WAVE文件是非常简单的一种RIFF文件,它的格式类型为"

RIFF块包含两个子块,这两个子块的ID分别是"

fmt"

和"

data"

其中"

子块由结构PCMWAVEFORMAT所组成,其子块的大小就是sizeofof(PCMWAVEFORMAT),数据组成就是PCMWAVEFORMAT结构中的数据。

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

标志符(RIFF)

数据大小

格式类型("

"

Sizeof(PCMWAVEFORMAT)

PCMWAVEFORMAT

声音数据大小

声音数据

 图三、WAVE文件结构图 

 

PCMWAVEFORMAT结构定义如下:

Typedefstruct

{

WAVEFORMATwf;

//波形格式;

WORDwBitsPerSample;

//WAVE文件的采样大小;

}PCMWAVEFORMAT;

WAVEFORMAT结构定义如下:

typedefstruct

WORDwFormatag;

//编码格式,包括WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM等

WORDnChannls;

//声道数,单声道为1,双声道为2;

DWORDnSamplesPerSec;

//采样频率;

DWORDnAvgBytesperSec;

//每秒的数据量;

WORDnBlockAlign;

//块对齐;

}WAVEFORMAT;

子块包含WAVE文件的数字化波形声音数据,其存放格式依赖于"

子块中wFormatTag成员指定的格式种类,在多声道WAVE文件中,样本是交替出现的。

如16bit的单声道WAVE文件和双声道WAVE文件的数据采样格式分别如图四所示:

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)

returnNULL;

HMMIOfile1;

//定义HMMIO文件句柄;

file1=mmioOpen((LPSTR)pString,NULL,MMIO_READWRITE);

//以读写模式打开所给的WAVE文件;

if(file1==NULL)

MessageBox("

WAVE文件打开失败!

);

ReturnNULL;

}

charstyle[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格式的文件!

PCMWAVEFORMATformat;

//定义PCMWAVEFORMAT结构对象,用来判断WAVE文件格式;

mmioSeek(file1,20,SEEK_SET);

//对打开的文件进行定位,此时指向WAVE文件的PCMWAVEFORMAT结构的数据;

mmioRead(file1,(char*)&

format,sizeof(PCMWAVEFORMAT));

//获取该结构的数据;

if(format.wf.nChannels!

=2)//判断是否是立体声声音;

该声音文件不是双通道立体声文件"

mmioSeek(file1,24+sizeof(PCMWAVEFORMAT),SEEK_SET);

//获取WAVE文件的声音数据的大小;

longsize;

size,4);

BYTE*pData;

pData=(BYTE*)newchar[size];

//根据数据的大小申请缓冲区;

mmioSeek(file1,28+sizeof(PCMWAVEFORMAT),SEEK_SET);

//对文件重新定位;

mmioRead(file1,(char*)pData,size);

//读取声音数据;

mmioClose(file1,MMIO_FHOPEN);

//关闭WAVE文件;

returnpData;

}

四、使用MCI方法操作声音文件

WAVE声音文件一个最基本的操作就是将文件中的声音数据播放出来,用Windows提供的API函数BOOLsndPlaySound(LPCSTRlpszSound,UINTfuSound)可以实现小型WAV文件的播放,其中参数lpszSound为所要播放的声音文件,fuSound为播放声音文件时所用的标志位。

例如实现Sound.wav文件的异步播放,只要调用函数sndPlaySound("

c:

\windows\Sound.wav"

SND_ASYNC)就可以了,由此可以看到sndPlaySound函数使用是很简单的。

但是当WAVE文件大于100K时,这时候系统无法将声音数据一次性的读入内存,sndPlaySound函数就不能进行播放了。

为了解决这个问题,你的一个选择就是用MCI方法来操作声音文件了。

在使用MCI方法之前,首先需要在你开发的项目设置Project->

Setting->

Link->

Object/librarymodules中加入winmm.lib。

并在头文件中包括"

mmsystem.h"

头文件。

MicroSoftAPI提供了MCI(TheMediaControlInterface)的方法mciSendCommand()和mciSendString()来完成WAVE文件的播放,这里仅介绍mciSendCommand()函数的使用。

原型:

DWORDmciSendCommand(UINTwDeviceID,UINTwMessage,DWORDdwParam1,DWORDdwParam2);

参数:

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;

//打开的音频设备的ID

mciSendCommand(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声音文件的播放:

voidCTest1View:

:

OnMciPlayWave()

//TODO:

Addyourcommandhandlercodehere

MCI_OPEN_PARMSmciOpenParms;

MCI_PLAY_PARMSPlayParms;

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"

的内容),代码和注释如下:

voidCPlaysoundView:

OnPlaySound()

LPVOIDlpPtr1;

//指针1;

LPVOIDlpPtr2;

//指针2;

HRESULThResult;

DWORDdwLen1,dwLen2;

LPVOIDm_pMemory;

//内存指针;

LPWAVEFORMATEXm_pFormat;

//LPWAVEFORMATEX变量;

LPVOIDm_pData;

//指向语音数据块的指针;

DWORDm_dwSize;

//WAVE文件中语音数据块的长度;

CFileFile;

//Cfile对象;

DWORDdwSize;

//存放WAV文件长度;

//打开sound.wav文件;

if(!

File.Open("

//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();

LPDWORDpdw,pdwEnd;

DWORDdwRiff,dwType,dwLength;

if(m_pFormat)//格式块指针

m_pFormat=NULL;

if(m_pData)//数据块指针,类型:

LPBYTE

m_pData=NULL;

if(m_dwSize)//数据长度,类型:

DWORD

m_dwSize=0;

pdw=(DWORD*)m_pMemory;

dwRiff=*pdw++;

dwLength=*pdw++;

dwType=*pdw++;

if(dwRiff!

=mmioFOURCC('

R'

'

I'

F'

))

//判断文件头是否为"

字符;

if(dwType!

//判断文件格式是否为"

//寻找格式块,数据块位置及数据长度

pdwEnd=(DWORD*)((BYTE*)m_pMemory+dwLength-4);

boolm_bend=false;

while((pdw<

pdwEnd)&

&

(!

m_bend))

//pdw文件没有指到文件末尾并且没有获取到声音数据时继续;

switch(dwType)

casemmioFOURCC('

f'

m'

t'

'

):

//如果为"

标志;

m_pFormat)//获取LPWAVEFORMATEX结构数据;

if(dwLength<

sizeof(WAVEFORMAT))

m_pFormat=(LPWAVEFORMATEX)pdw;

break;

d'

a'

m_pData||!

m_dwSize)

m_pData=(LPBYTE)pdw;

//得到指向声音数据块的指针;

m_dwSize=dwLength;

//获取声音数据块的长度;

if(m_pFormat)

m_bend=TRUE;

pdw=(DWORD*)((BYTE*)pdw+((dwLength+1)&

~1));

//修改pdw指针,继续循环;

DSBUFFERDESCBufferDesc;

//定义DSUBUFFERDESC结构对象;

memset(&

BufferDesc,0,sizeof(BufferDesc));

BufferDesc.lpwfxFormat=(LPWAVEFORMATEX)m_pFormat;

BufferDesc.dwSize=sizeof(DSBUFFERDESC);

BufferDesc.dwBufferBytes=m_dwSize;

BufferDesc.dwFlags=0;

HRESULThRes;

LPDIRECTSOUNDm_lpDirectSound;

hRes=:

DirectSoundCreate(0,&

m_lpDirectSound,0);

//创建DirectSound对象;

if(hRes!

=DS_OK)

return;

m_lpDirectSound->

SetCooperativeLevel(this->

GetSafeHwnd(),DSSCL_NORMAL);

//设置声音设备优先级别为"

NORMAL"

//创建声音数据缓冲;

LPDIRECTSOUNDBUFFERm_pDSoundBuffer;

if(m_lpDirectSound->

CreateSoundBuffer(&

BufferDesc,&

m_pDSoundBuffer,0)==DS_OK)

//载入声音数据,这里使用两个指针lpPtr1,lpPtr2来指向DirectSoundBuffer缓冲区的数据,这是为了处理大型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(dwLen2>

0)

BYTE*m_pData1=(BYTE*)m_pData+dwLen1;

m_pData=(void*)m_pData1;

memcpy(lpPtr2,m_pData,dwLen2);

m_pDSoundBuffer->

Unlock(lpPtr1,dwLen1,lpPtr2,dwLen2);

DWORDdwFlags=0;

Play(0,0,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2