大型WAV檔案的播放 (轉)

worldblog發表於2007-12-04
大型WAV檔案的播放 (轉)[@more@]

大型WAV的

在多的設計中經常要處理檔案,用提供的sndPlaySound可以實現小型WAV檔案的播放。但是當WAV檔案大於可用時,sndPlaySound函式就不能進行播放,那麼如何利用MCI播放大型檔案呢?本文將介紹一種方法。

Windows支援兩種RIFF(re interchange file format,“資源互動檔案格式”)音訊檔案:MIDI的D檔案和波形音訊檔案格式WAV檔案,本文將介紹如何用MCI命令播放大型WAV檔案。

用sndPlaySound播放音訊檔案只需要一行程式碼。比如實現非同步播放的方法為
sndPlaySound("c:windowsding.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=(D)pWnd->m_hWnd;
  DwResult=mciSendCommand(m_nDevice,MCI_PLAY,MCI_NOTIFY,
(DWORD)(LPVOID)&mciPlayParms);

這樣就開始了WAV檔案的播放,並且在播放完畢後,MM_MCINOTIFY訊息會傳送到指定的視窗,圖1給出了一個WAV檔案播放所發生的事件序列:(1)命令播放WAV檔案並立即返回;(2)播放WAV檔案;(3)完成後傳送通知訊息。

圖1 播放WAV檔案
  完成播放後關閉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 C
{
  //Construction
  public:
  CWave();
  virtual ~CWave();

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

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

  //Members
  protected:
  MCVICEID 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 succesul,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);
  }
}


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-988069/,如需轉載,請註明出處,否則將追究法律責任。

相關文章