大型WAV文件的播放

 在多媒体软件的设计中经常要处理声音文件,用Windows提供的API函数sndPlaySound可以实现小型WAV文件的播放。但是当WAV文件大于可用内存时,sndPlaySound函数就不能进行播放,那么如何利用MCI播放大型音频文件呢?本文将介绍一种方法。

  Windows支持两种RIFF(resource interchange file format,“资源交互文件格式”)音频文件:MIDI的RMID文件和波形音频文件格式WAV文件,本文将介绍如何用MCI命令播放大型WAV文件。

  用sndPlaySound播放音频文件只需要一行代码。比如实现异步播放的方法为sndPlaySound("c:\windows\ding.wav",SND_ASYNC);

  由此可以看到,sndPlaySound的使用是很简单的。但是用sndPlaySound播放音频文件有一个限制,即整个音频文件必须全部调入可用的物理内存。因此应用sndPlaySound播放的音频文件相对较小,最大约100K。要播放大一些的音频文件(在多媒体设计中是经常要遇到的情况)需要使用MCI的功能。

  本文创建了一个Cwave类,可以处理播放音频的MCI命令,因为该类能够执行很多的MCI命令和建立了数据结构,所以只需要简单的成员函数(如OpenDevice, CloseDevice, Play和Stop)。在CWave类中抽象了特定的MCI命令和数据结构,只含几个简单的成员函数OpenDevice, CloseDevice, Play和Stop。波形音频设备是一个复合设备,如果打开波形设备,然后打开并关闭每个波形元素,最后关闭波形设备,这样可以使得播放性能更好。调用Cwave::OpenDevice就可以打开波形设备,OpenDevice将MCI_OPEN命令传递给mciSendCommand函数,如果调用成功,就用数据结构MCI_OPEN_PARMS的wDeviceID成员返回波形设备的标识符,该标识符保存在一个供以后使用的私有数据成员中。

  一旦打开了Cwace对象,通过Cwace::Play播放WAV文件就就绪了,WAV文件名和一个窗口指针被传递给Play方法以便将MCI通知消息发送到制定的窗口。

  WAV文件的播放分为两步。首先要通过分配一个MCI_OPEN_PARMS结构并给所要播放的WAV文件设置lpstrElementName成员打开WAV文件。将该结构和MCI_OPEN传递给mciSendCommand,打开WAV文件并用MCI_OPEN_PARMS结构的wDeviceID成员返回元素标识符。

  第二步是命令波形音频设备播放WAV文件。分配了MCI_PLAY_PARMS结构并将dwCallback成员设置为窗口句柄。如果要同步播放音频波形文件,就增加MCI_WAIT标志并跳过窗口句柄。这样做会使应用程序在mciSendCommand函数返回之前等待WAV文件播放完毕。最可能的情况是异步播放大型WAV文件,可以象下面那样指定MCI_NOTIFY标志并设置dwCallback成员做到这一点。
MCI_PLAY_PARMS mciPlayParms;
MciPlayParms.dwCallback=(DWORD)pWnd->m_hWnd;
DwResult=mciSendCommand(m_nDevice,MCI_PLAY,MCI_NOTIFY,(DWORD)(LPVOID)&mciPlayParms);

  这样就开始了WAV文件的播放,并且在播放完毕后,MM_MCINOTIFY消息会发送到指定的窗口,图1(图略)了一个WAV文件播放所发生的事件序列:(1)命令播放WAV文件并立即返回;(2)播放WAV文件;(3)完成后发送通知消息。

完成播放后关闭WAV文件元素是程序员的责任,简单的调用Cwave类的Stop成员函数就可以了。Stop成员函数将WAV文件标识符和MCI_CLOSE命令传递给mciSendCommand函数,不必为该命令分配一个MCI结构,下述代码关闭了WAV文件
  mciSendCommand(m)nElement,MCI_CLOSE,NULL,NULL);

播放完所有的WAV文件后必须关闭波形音频设备,Cwave类的析构函数调用Cwave::CloseDevice自动完成。

将本文中介绍的CWave类加入到自己的程序中,就可以方便的应用它播放音频文件了。

 
 //建立Cwave类,放在Wave.h文件中 
  class CWave:public CObject 
  { 
//Construction 
public: 
CWave(); 
virtual ~CWave(); 

//Operations 
  public: 
DWORD OpenDevice(); 
DWORD CloseDevice(); 
DWORD Play(CWnd *pParentWnd,LPCSTR pFileName); 
DWORD Stop(); 

//Implementation 
protected: 
void DisplayErrorMsg(DWORD dwError); 

//Members 
protected: 
MCIDEVICEID m_nDeviceID; 
MCIDEVICEID m_nElementID; 
  }; 

  //Cwave类的实现代码,Cwave.cpp 

  #include 
  #include "cwave.h" 

  CWave::CWave() 
  { 
   m_nDeviceID=0; 
   m_nElementID=0; 
  } 

  CWave::~CWave() 
  { 
   if(m_nElementID) 
   Stop(); 
   if(m_nDeviceID) 
   CloseDevice(); 
  } 

  DWORD CWave::OpenDevice() 
  { 
   DWORD dwResult=0; 
   if (m_nDeviceID) 

MCI_OPEN_PARMS mciOpenParms; 
   mciOpenParms.lpstrDeviceType=(LPSTR)MCI_DEVTYPE_WAVEFORM_AUDIO; 
//open the wave device 
  dwResult=mciSendCommand(NULL,MCI_OPEN, 
MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_WAIT, 
(DWORD)(LPVOID)&mciOpenParms); 
//save device identifier,will use eith other MCI commands 
m_nDeviceID=mciOpenParms.wDeviceID; 
//display error message if failed 
if(dwResult) 
DisplayErrorMsg(dwResult); 
} 
//return result of MCI operation 
return dwResult; 
  } 

  DWORD CWave::CloseDevice() 
  { 
   DWORD dwResult=0; 

//close if currently open 
if(m_nDeviceID) 
{ 

//close the MCI device 
dwResult=mciSendCommand(m_nDeviceID,MCI_CLOSE,NULL,NULL); 

//display error message if failed 
if(dwResult) 
DisplayErrorMsg(dwResult); 

//set identifier to close state 
else 
m_nDeviceID=0; 
} 

//return result of MCI operation 
return dwResult; 
  } 

  DWORD CWave::Play(CWnd* pWnd,LPCSTR pFileName) 
  { 
MCI_OPEN_PARMS mciOpenParms; 
//initialize structure 
memset(&mciOpenParms,0,sizeof(MCI_OPEN_PARMS)); 

//set the WAV file name to be played 
mciOpenParms.lpstrElementName=pFileName; 

//first open the device 
DWORD dwResult=mciSendCommand(m_nDeviceID,MCI_OPEN, 
MCI_OPEN_ELEMENT,(DWORD)(LPVOID)&mciOpenParms); 

//display error message if failed 
if(dwResult) 
DisplayErrorMsg(dwResult); 

//if successful,instruct the device to play the WAV file 
else 
{ 

//save element indentifier 
m_nElementID=mciOpenParms.wDeviceID; 

MCI_PLAY_PARMS mciPlayParms; 

//set the window that will receive notification message 
mciPlayParms.dwCallback=(DWORD)pWnd->m_hWnd; 

//instruct device to play file 
dwResult=mciSendCommand(m_nElementID,MCI_PLAY, 
MCI_NOTIFY,(DWORD)(LPVOID)&mciPlayParms); 

//display error and close element if failed 
if(dwResult) 
{ 
DisplayErrorMsg(dwResult); 
Stop(); 
} 
} 

//return result of MCI operation 
return dwResult; 
  } 

  DWORD CWave::Stop() 
  { 

   DWORD dwResult=0; 

   //close if element is currently open 
   if(m_nElementID) 
   { 
   dwResult=mciSendCommand(m_nElementID,MCI_CLOSE,NULL,NULL); 

   //display error message if failed 
   if(dwResult) 
   DisplayErrorMsg(dwResult); 

   //set identifier to closed state 
   else 
   m_nElementID=0; 
   } 
   return dwResult; 
  } 

  void CWave::DisplayErrorMsg(DWORD dwError) 
  { 
   //check if there was an error 
   if(dwError) 
   { 
   //character string that contains error message 
   char szErrorMsg[MAXERRORLENGTH]; 

   //retrieve string associated error message 
   if(!mciGetErrorString(dwError,szErrorMsg,sizeof(szErrorMsg))) 
   strcpy(szErrorMsg,"Unknown Error"); 
   //display error string in message box 
   AfxMessageBox(szErrorMsg); 
   } 
  } 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值