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);
);
可以看出,用命令消息比用命令字符串要複雜的多,但它的執行效率高。