程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 如何播放大型WAV文件

如何播放大型WAV文件

編輯:關於VC++

平時,你在多媒體軟件的設計中是怎樣處理聲音文件的呢?使用Windows 提供的API函數 sndPlaySound來實現WAV文件的播放?但是,你有沒有遇到過這種情況呢:當WAV文件大於可用內存時,sndPlaySound 函數就不能進行播放!!!那麼,如何利用MCI播放大型音頻文件呢?

本文將介紹一種方法。

Windows支持兩種RIFF(resource interchange file format,“資源交互文件格式”)音 頻文件:MIDI的RMID文件和波形音頻文件格式WAV文件,本文將介紹如何用MCI命令播放大型W AV文件。用sndPlaySound播放音頻文件只需要一行代碼。比如實現異步播放的方法為 sndPlaySound("c:\windows\ding.wav",SND_ASYNC);

由此可以看到,sndPlaySound 的使用是很簡單的。但是用sndPlaySound播放音頻文件有 一個限制,即整個音頻文件必須全部調入可用的物理內存。因此應用sndPlaySound播放的音頻 文件相對較小,最大約100K。要播放大一些的音頻文件(在多媒體設計中是經常要遇到的情況 )需要使用MCI的功能。這裡創建了一個Cwave類,可以處理播放音頻的MCI命令,因為該類能夠 執行很多的MCI命令和建立了數據結構,所以只需要簡單的成員函數(如OpenDevice, CloseDe vice, Play和Stop)。在CWave類中抽象了特定的MCI命令和數據結構,只含幾個簡單的成員函 數OpenDevice, CloseDevice, Play和Stop。波形音頻設備是一個復合設備,如果打開波形設 備,然後打開並關閉每個波形元素,最後關閉波形設備,這樣可以使得播放性能更好。調用C wave::OpenDevice就可以打開波形設備,OpenDevice將MCI_OPEN命令傳遞給mciSendCommand函 數,如果調用成功,就用數據結構MCI_OPEN_PARMS的wDeviceID成員返回波形設備的標識符, 該標識符保存在一個供以後使用的私有數據成員中。一旦打開了Cwace對象,通過Cwace::Pla y播放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標志並跳過窗口句柄。這樣做會使應用程序在mciSendComman d函數返回之前等待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消息會發送到指定的窗口。一個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::Close Device自動完成。 將本文中介紹的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 <stdafx.h>
#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);
  }
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved