VC++中MCI播放音頻文件

MCI播放mp3音頻文件例程

源文件中需要包含頭文件 Mmsystem.h,在Project->Settings->Link->Object/libray module中加入庫 Winmm.lib。或添加代碼#pragma   comment(lib, "winmm.lib")

MCI_OPEN_PARMS op;

void CMCIDlg::OnPlay()
{
 // TODO: Add your control notification handler code here
 DWORD cdlen;//音頻文件長度

 op.dwCallback=NULL;
 op.lpstrAlias=NULL;
 op.lpstrDeviceType=_T("MPEGAudio");  //設備類型,大多數文件可以這樣設置
 op.lpstrElementName=_T("D:\\2.mp3"); //文件路徑
 op.wDeviceID=NULL;      //打開設備成功以後保存這個設備號備用
 UINT rs;        //接受函數返回結果
 //發送命令打開設備,成功返回0,否則返回錯誤號,第三個參數這裏必須MCI_OPEN_ELEMENT  
 rs=mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_ELEMENT,(DWORD)&op);

 mciSendCommand(NULL,MCI_SET,MCI_SET_DOOR_OPEN,NULL);

 cdlen=getinfo(op.wDeviceID,MCI_STATUS_LENGTH);//獲取音頻文件長度

 if(rs==0)        //設備打開成功就播放文件
 {
  MCI_PLAY_PARMS pp;
  pp.dwCallback=NULL;
  pp.dwFrom=0;      //開始播放的位置
  mciSendCommand(op.wDeviceID,MCI_PLAY,MCI_NOTIFY,(DWORD)&pp);
  //播放文件,如果第三個參數設爲MCI_WAIT則程序窗口會被阻塞,爲了避免這種情況可以設爲MCI_NOTIFY
 }

 Sleep(cdlen);//根據文件長度等待,與MCI_WAIT效果一樣,cdlen參數可以控制播放時間
 OnStop();        //關閉音頻文件 
}

DWORD CMCIDlg::getinfo(UINT wDeviceID,DWORD item)
{
 MCI_STATUS_PARMS mcistatusparms;
 mcistatusparms.dwCallback=(DWORD)GetSafeHwnd();
 mcistatusparms.dwItem=item;
 mcistatusparms.dwReturn=0;
 mciSendCommand(wDeviceID,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)&mcistatusparms);
 return mcistatusparms.dwReturn;
}

void CMCIDlg::OnStop()
{
 // TODO: Add your control notification handler code here
 //在WM_CLOSE消息處理過程中發送MCI_CLOSE命令關閉設備
 MCI_GENERIC_PARMS gp;
 gp.dwCallback=NULL;
 mciSendCommand(op.wDeviceID,MCI_CLOSE,MCI_WAIT,(DWORD)&gp);  
}

 ==============================================================================================

加入音樂是增強應用程序功能的所有方法中最簡單的一個。幾乎每個計算機遊戲或多媒體程序都以某種MIDI或CD音樂爲背景。音樂可以使用戶心情愉快;在合適的場合播放恰當的音樂能夠使程序員和他的VC++程序煥發光彩。

第一部分 MIDI的播放

樂器數字化接口(MIDI)是由音樂界的一些大公司(包括生產電子音樂合成器的公司)制訂的一項協議,後來被計算機產業所採用併成爲多媒體音樂文件的標準格式。MIDI文件一般較小,對硬件設備的要求高。

一、 原理

雖然MicroSoft支持MIDI文件,然而Visual C++或MFC並沒有創建任何組件來實現這種支持,但是MicroSoft API提供了三種不同的方法來實現MIDI的播放:

MCI(The Media Control Interface)。這是最基本的方法,本文將詳細討論這種方法。

流緩衝器。這種格式允許應用程序爲MIDI數據分配緩衝器。在需要精確控制MIDI播放的時候,流緩衝器將很有用處。

低級MIDI設備。需要完全控制MIDI數據的應用程序可以使用這種方法。

MCI可以通過mciSendCommand()和mciSendString()來完成,本文僅使用mciSendCommand()函數。

原型:DWORD mciSendCommand(UINT wDeviceID,UINT wMessage,DWORD dwParam1,DWORD dwParam2);

參數: wDeviceID:接受消息的設備ID

wMessage:MCI命令消息

dwParam1:命令的標誌位

dwParam2:所使用參數塊的指針

返值:調用成功,返回零;否則,返回雙字中的低字存放有錯誤信息。

二MIDI的播放控制

1. 打開設備

MCI_OPEN_PARMS OpenParms;

OpenParms.lpstrDeviceType =

(LPCSTR) MCI_DEVTYPE_SEQUENCER;//MIDI類型

OpenParms.lpstrElementName = (LPCSTR) Filename;

OpenParms.wDeviceID = 0;

mciSendCommand (NULL, MCI_OPEN,

MCI_WAIT | MCI_OPEN_TYPE |

MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT,

(DWORD)(LPVOID) &OpenParms)

MCI設備ID指明打開了哪個設備,當發送了MCI_OPEN命令時,這個值在參數塊中返回——應被保存備用。

2. 關閉設備

mciSendCommand (m_wDeviceID, MCI_CLOSE, NULL, NULL);

3. 播放

MCI_PLAY_PARMS PlayParms;

PlayParms.dwFrom = 0;

// 指定從什麼地方(時間)播放

mciSendCommand (m_wDeviceID, MCI_PLAY,

MCI_FROM, (DWORD)(LPVOID)

&PlayParms));

4. 暫停

MCI_PLAY_PARMS PlayParms;

mciSendCommand (m_wDeviceID, MCI_PAUSE, 0,

(DWORD)(LPVOID) &PlayParms);

5. 停止

mciSendCommand (m_wDeviceID, MCI_STOP, NULL, NULL);

6. 跳躍

* 跳轉到任意地方

MCI_SEEK_PARMS SeekParms;

SeekParms.dwTo = (nMinute * 60 + nSecond) * 1000;

//跳轉的目標時間,時間單位爲毫秒

mciSendCommand (m_wDeviceID, MCI_SEEK, MCI_TO

| MCI_WAIT,(DWORD)(LPVOID)

&SeekParms);

* 跳到文件頭

mciSendCommand (m_wDeviceID, MCI_SEEK,

MCI_SEEK_TO_START, NULL);

* 跳到文件尾

mciSendCommand (m_wDeviceID, MCI_SEEK,

MCI_SEEK_TO_END, NULL);

7. 查詢當前信息

MCI_STATUS_PARMS StatusParms;

StatusParms.dwItem = MCI_SEQ_STATUS_DIVTYPE;

mciSendCommand (m_wDeviceID, MCI_STATUS,

MCI_WAIT | MCI_STATUS_ITEM,

(DWORD)(LPVOID) &StatusParms);

返回信息存放於StatusParms.dwReturn中。

MCI_STATUS標誌

MCI_STATUS_LENGTH 獲得文件長度

MCI_STATUS_MODE 獲得文件播放的當前狀態

MCI_STATUS_POSITION 獲得文件播放的當前位置

MCI_STATUS_TIME_FORMAT 獲得當前的時間格式

MCI_SEQ_STATUS_DIVTYPE 判斷文件是PPQN類型還是SMPTE類型

MCI_SEQ_STATUS_TEMPO 獲得當前播放速度,PQRN類型,

此值爲節拍/分,SMPTE類型,此值爲禎/秒

8. 設置時間格式及播放速度

MCI_SET_PARMS SetParms;

SetParms.dwTimeFormat = MCI_FORMAT_MILLISECONDS;

//設置時間單位爲毫秒

mciSendCommand (m_wDeviceID,

MCI_SET, MCI_SET_TIME_FORMAT,

(DWORD)(LPVOID) &SetParms);

MCI_SEQ_SET_TEMPO 設置播放速度,

PQRN類型,此值爲節拍/分,

SMPTE類型,此值爲禎/秒

第二部分 WAV文件的播放

一、原理

MicroSoft API提供了三種不同的方法來實現WAV的播放:

PlaySound()函數。它可以通過單行編碼來播放Wave格式的聲音。此函數有兩個限制:必須將聲音數據完整地載入物理內存;數據格式必須被所配置的某一音頻驅動器支持。根據經驗,PlaySound()適用於100K以下的文件。

MCI(The Media Control Interface),與上一章播放MIDI文件相似,可以播放100K 以上的文件。

低級Wave音頻設備。用這些設備可以運行完全控制Wave數據的應用文件。

二、 WAV文件播放控制

因爲同樣使用MCI,與上一章相同,只列出不同的部分。

1. 打開設備

將MIDI的MCI_DEVTYPE_SEQUENCER 改爲"waveaudio"

2. 錄音

MCI_RECORD_PARMS RecordParms;

mciSendCommand (m_wDeviceID, MCI_RECORD,

NULL, (DWORD)(LPVOID)

&RecordParms);

3. 保存錄音

MCI_SAVE_PARMS SaveParms;

SaveParms.lpfilename = (LPCSTR) Filename;

mciSendCommand (m_wDeviceID, MCI_SAVE,

MCI_SAVE_FILE | MCI_WAIT,

(DWORD)(LPVOID) &SaveParms);

第三部分 CD的播放

CD的獨特優勢在於,它由作曲家設計,並由音樂廠家生產。不同的計算機播放MIDI 文件時,聲音效果也不一樣,但是CD的聲音效果總是相同的。高品質的音頻對計算機用 戶產生的效果會使你感到吃驚。我們依然採用MCI播放CD,大部分的播放控制與前兩部分相同,只列出不同的部分

1. 開光驅門

mciSendCommand (m_wDeviceID, MCI_SET,

MCI_SET_DOOR_OPEN, NULL);

2. 關光驅門

mciSendCommand (m_wDeviceID, MCI_SET,

MCI_SET_DOOR_CLOSED, NULL);

3. 打開設備

將MIDI的MCI_DEVTYPE_SEQUENCER 改爲MCI_DEVTYPE_CD_AUDIO

4. 播放

指定播放起點必須經過MCI_MAKE_TMSF(Track,Minute,Second,Frame)轉化

5. 查詢當前信息

MCI_STATUS_CURRENT_TRACK 得到當前曲目

MCI_STATUS_LENGTH 得到CD或指定曲目長度

MCI_STATUS_MODE 得到驅動器的當前狀態

MCI_STATUS_NUMBER_OF_TRACKS 得到CD曲目的數目

MCI_STATUS_POSITION 得到當前格式下的位置

MCI_STATUS_READY 檢查設備是否就緒

MCI_STATUS_TIME_FORMAT 得到當前時間格式

MCI_STATUS_MEDIA_PRESENT 檢查以確認CD是否在驅動器內

MCI_CDA_STATUS_TYPE_TRACK 檢查已確認某曲目是否爲音頻曲目

注意:

使用MCI_STATUS_LENGTH參數查詢CD 及曲目長度,返回值通過調用MCI_MSF_MINUTE(),MCI_MSF_SECOND()轉換爲分、秒。

MCI_STATUS_POSITION參數返回值調用MCI_TMSF_TRACK(), MCI_TMSF_MINUTE(), MCI_TMSF_SECOND(),MCI_TMSF_FRAME才能得到當前的位置的道、分、秒、幀。

6. 跳躍

跳轉的目標必須經過MCI_MAKE_TMSF(Track,Minute,Second,Frame)轉化最好將上述三種格式分開建類,或做成動態連接庫。在 Project-- >Setting-- >Link-- >Object/library modules中加入winmm.lib,源程序中包含。

MCI調用簡單,功能強大,可以滿足日常多媒體編程的基本需要。但是,MCI一次只能播放一個文件,使用DirectSound技術可以實現八個以上WAV文件的同時播放。

 ==============================================================================================

使用MCI API,源文件中需要包含頭文件 Mmsystem.h,在Project->Settings->Link->Object/libray module中加入庫 Winmm.lib。

1、MCI簡介

MCI(Media Control Interface,媒體控制接口)向Windows程序提供了在高層次上控制媒體設備接口的能力。程序不必關心具體設備,就可以對激光唱機(CD)、視盤機、波形音頻設備、視頻播放設備和MIDI設備等媒體設備進行控制。

對於程序員來說,可以把MCI理解爲設備面板上的一排按鍵,通過選擇不同的按鍵(發送不同的MCI命令)可以讓設備完成各種功能,而不必關心設備內部實現。

比如,對於play,視盤機和CD機有不同的反應(一個是播放視頻,一個播放音頻),而對用戶來說卻只需要按同一按鈕。

應用程序通過向MCI發送命令來控制媒體設備。MCI命令接口分命令字符串和命令消息兩種,兩者具有相同的功能。命令字符串具有使用簡單的特點,但是它的執行效率不如命令消息。

所有的MCI命令字符串都是通過多媒體API函數mciSendString傳遞給MCI的,該函數的聲明爲:

  MCIERROR mciSendString(

    LPCTSTR lpszCommand,    //MCI命令字符串

    LPTSTR lpszReturnString, //存放反饋信息的緩衝區

    UINT  cchReturn,     //緩衝區的長度

    HANDLE hwndCallback    //回調窗口的句柄,一般爲NULL

  ); //若成功則返回0,否則返回錯誤碼。

該函數返回的錯誤碼可以用mciGetErrorString函數進行分析,該函數的聲明爲:

  BOOL mciGetErrorString(

    DWORD fdwError,   //函數mciSendString返回的錯誤碼

    LPTSTR lpszErrorText, //接收描述錯誤的字符串的緩衝區

    UINT  cchErrorText  //緩衝區的長度

  );

下面是使用mciSendString函數的一個簡單例子:

  char buf[50];

  MCIERROR mciError;

  mciError=mciSendString("open cdaudio",buf,strlen(buf),NULL);

  if(mciError)

  {

    mciGetErrorString(mciError,buf,strlen(buf));

    AfxMessageBox(buf);

    return;

  }

open cdaudio命令打開CD播放器,如果出錯(如驅動器內沒有CD)則返回錯誤碼,此時可以用mciGetErrorString函數取得錯誤信息字符串。

2、MCI設備

open是MCI打開設備的命令,cdaudio是MCI設備名。MCI的設備類型如下:

  animation  動畫設備

  cdaudio   CD播放器

  dat     數字音頻磁帶機

  digitalvideo 某一窗口中的數字視頻(不基於GDI)

  other    未定義的MCI設備

  overlay   重疊設備(窗口中的模擬視頻)

  scanner   圖象掃描儀

  sequencer  MIDI序列器

  videodisc  視盤機

  waveaudio  播放數字波形文件的音頻設備

設備名是在註冊表或SYSTEM.INI的[mci]部分定義的,典型的[mci]段如下:

  [mci]

  cdaudio=mcicda.drv

  sequencer=mciseq.drv

  waveaudio=mciwave.drv

  avivideo=mciavi.drv

  videodisc=mcipionr.drv

等號的左邊是設備名,右邊是對應的MCI驅動程序。當安裝了新的MCI驅動程序時,系統要用不同的設備名來區分。

3、MCI命令

使用MCI設備一般包括打開、使用和關閉三個過程,常用的MCI命令有:

  open    打開設備

  close    關閉設備

  play    開始設備播放

  stop    停止設備的播放或記錄

  record   開始記錄

  save    保存設備內容

  pause    暫停設備的播放或記錄

  resume   恢復暫停播放或記錄的設備

  seek    改變媒體的當前位置

  capacility 查詢設備能力

  info    查詢設備的信息

  status   查詢設備狀態信息

MCI的大部分命令可以控制不同的媒體設備,但其中record和save命令並不是所有MCI設備都可以使用。

MCI命令的使用是很隨意的,只要先打開,最後關閉,中間可以隨意調用各種命令。

(1) open 打開設備

MCI設備使用前必須先打開,當然,使用後也必須要關閉,以免影響他人的使用。

open device_name type device_type alias device_alias

  device_name     要使用的設備名,通常是文件名。

  type device_type  設備類型,例如waveaudio或sequencer,可省略。

  alias device_alias 設備別名,指定後可在其他命令中代替設備名。

(2) play 開始設備播放

MCI設備打開後即可以播放,可使用設備名或別名。

play device_alias from pos1 to pos2 wait repeat

  若省略from則從當前磁道開始播放,若省略to則播放到結束。

  若指明wait則等到播放完畢命令才返回。

  若指明repeat則會不停的重複播放。

  若同時指明wait和repeat則命令不會返回,本線程產生堵塞,通常會引起程序失去響應。

(3) 播放CD

void CTttView::OnOpenCD()

{

  mciSendString("open cdaudio",NULL,0,NULL);

  mciSendString("play cdaudio",NULL,0,NULL);

);

void CTttView::OnStopCD()

{

  mciSendString("stop cdaudio",NULL,0,NULL);

  mciSendString("close cdaudio",NULL,0,NULL);

);

還可以:

  pause cdaudio  暫停播放。

  resume cdaudio 繼續被暫停的播放。

  seek cdaudio to <位置> 移動到指定磁道。

  set cdaudio door open/closed 彈出或縮進CD盤。

(4) 播放多媒體文件

void CTttView::OnMyMenu()

{

  mciSendString("open myfolder\\tada.wav alias aa",NULL,0,NULL);

或 mciSendString("open myfolder\\flourish.mid alias aa",NULL,0,NULL);

或 mciSendString("open myfolder\\clock.avi alias aa",NULL,0,NULL);

  mciSendString("play aa wait",NULL,0,NULL);

  mciSendString("close aa",NULL,0,m_hWnd);

);

(5) 錄製聲音

void CTttView::OnStartRecord()

{

  mciSendString("open new type waveaudio alias aa",NULL,0,NULL);

  mciSendString("record aa",NULL,0,NULL);

);

void CTttView::OnStopRecord()

{

  mciSendString("save aa c:\\aaa.wav wait",NULL,0,NULL);

  mciSendString("close aa",NULL,0,NULL);

);

4、MCI命令消息

到目前爲止,我們使用的都是MCI命令字符串。可以發現,命令字符串具有簡單易學的優點,但這種接口與C/C++的風格相去甚遠,如果程序要查詢和設置大量數據,那麼用字符串的形式將很不方便。

MCI的命令消息接口提供了C語言接口,它速度更快,並且更能符合C/C++程序員的需要。

所有MCI命令消息都是通過mciSendCommand函數發送的,函數聲明爲:

  MCIERROR mciSendCommand(

    MCIDEVICEID wIDDevice,  //設備的ID,在打開設備時不用該參數

    UINT    uMsg,    //命令消息

    DWORD    fdwCommand, //命令消息的標誌

    DWORD    dwParam   //指向包含命令消息參數的結構

  ); //若成功則返回0,否則返回錯誤碼

命令消息uMsg與命令字符串是對應的,例如,open與MCI_OPEN完成的是一樣的功能。

變量wDeviceID用來保存設備的ID,系統用ID來標識不同的設備,以保證命令發給正確的對象。

void CTttView::OnMyMenu()

{

  MCI_OPEN_PARMS mciOpen;

  UINT wDeviceID;

  mciOpen.lpstrDeviceType = "avivideo";

  mciOpen.lpstrElementName = "myfolder\\clock.avi";

  mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT, (DWORD)&mciOpen);

  wDeviceID=mciOpen.wDeviceID;

  MCI_PLAY_PARMS mciPlay;

  mciSendCommand(wDeviceID, MCI_PLAY, MCI_WAIT, (DWORD)&mciPlay);

);

可以看出,用命令消息比用命令字符串要複雜的多,但它的執行效率高。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章