自己動手寫類似酷狗播放器(2)_音樂播放模組實現

YunShell發表於2013-08-10
   上一章中,主要是介紹了WINDOWS訊息機制和模板對話方塊的建立,其實學到現在感覺windows程式設計就是各種邏輯+API函式。所以MSDN很重要。由於整個程式碼太大了,所以下面系列文章中,我只講思路以及一些控制元件的用法。原始碼以後會上傳。請大家多多支援...
	下面先上個 最後的效果圖..

     這節主要總結下最核心的播放功能,如何實現的。只提供關鍵思路。
核心思路:
1.按“新增”按鈕,將新增歌曲進入Listbox。具有數字標號+歌曲名字
            這裡包括檔案新增的操作,listBox的插入操作,字串函式的操作
2.雙擊Listbox中某個歌曲將可以播放,並且可以有時間進度條和總時間
           這裡包括 listbox響應雙擊事件,mcisendCommand和關聯結構體操作

1.新增檔案的操作

    在開始播放前,肯定要手動新增哪些要加入到播放列表中,就是上面按鈕"新增"觸發的操作。這裡涉及檔案的開啟以及多個檔案同時選中的情況。關鍵程式碼如下:

void  DoSelectFile(HWND hwnd) //選擇檔案
{
	
	OPENFILENAME ofn;  //定義一個檔案結構體
	TCHAR szOpenFileNames[80*MAX_PATH]; //開啟的檔名字
	TCHAR szPath[MAX_PATH]; //歌曲檔案的路徑 其實操作一個Mp3檔案就是通過路徑來操作的
	TCHAR szFileName[80*MAX_PATH];
	ZeroMemory(szOpenFileNames,sizeof(szOpenFileNames)/sizeof(TCHAR));
	ZeroMemory(&ofn,sizeof(ofn));
	ZeroMemory(szFileName,sizeof(szFileName));
	ZeroMemory(szPath,sizeof(szPath));  //清空 各類結構
	//配置ofn各欄位
	ofn.Flags=OFN_EXPLORER|OFN_ALLOWMULTISELECT;//指定瀏覽功能,和允許多選功能
	ofn.hwndOwner=hwnd; //父控制程式碼為當前對話方塊
	ofn.lStructSize=sizeof(ofn);//整個ofn結構體的大小   (這裡以前犯了個錯誤&ofn)
	ofn.lpstrFile=szOpenFileNames;//開啟的檔案的全路徑
	ofn.nMaxFile=sizeof(szOpenFileNames);//檔案大小的最大值
	ofn.lpstrFile[0]='\0';//指定第一個為NULL字元
	ofn.lpstrFilter=TEXT("*.mp3\0*.mp3\0*.wav\0*.wav\0All files\0*.*\0");//檔案過濾器
	if(GetOpenFileName(&ofn)) //成功返回非零 不成功為0
	{	
		TCHAR withnum_song[255];//帶數字列表的 插入到listbox的歌曲名
		ZeroMemory(withnum_song,sizeof(withnum_song)/sizeof(TCHAR));
		lstrcpyn(szPath,szOpenFileNames,ofn.nFileOffset);//獲取該多個檔案所在的目錄 單個檔案不需要加‘\’,多個檔案少個\
		if(szPath[lstrlen(szPath)-1]!='\\')    
		{
			lstrcat(szPath,TEXT("\\")); //這裡又要犯錯誤了,lstrcat是連線兩個字串,\在字串中必須是"\\"
		}
	//	MessageBox(hwnd,szPath,TEXT("szPath2"),MB_OK);
		TCHAR *p=szOpenFileNames+ofn.nFileOffset;//get the first file name
		while(*p)
		{	
			lstrcpy(fileinfo[isong].songname,p); //  儲存歌曲名     歌曲複製到 全域性檔案資訊庫
			lstrcpy(szFileName,szPath);
			lstrcat(szFileName,p);
			lstrcpy(fileinfo[isong].szfiledir,szFileName); //儲存歌曲完整路徑
			TCHAR puresn[255]; //純的songname=sn
			ZeroMemory(puresn,sizeof(puresn)/sizeof(TCHAR));
			TCHAR *pos=strrchr(p,'.');//從後往前查詢'.' .mp3的.
			lstrcpyn(puresn,p,pos-p+1);
			ZeroMemory(withnum_song,sizeof(withnum_song)/sizeof(TCHAR));
			wsprintf(withnum_song,TEXT("%02d  %s"),isong+1,puresn);
			ListBox_InsertString(hlistbox,-1,withnum_song);
			p=p+lstrlen(p)+1; //移動到下一個檔名
			ZeroMemory(szFileName,sizeof(szFileName));
			isong++; //歌曲自加1
		}
	}
}
     上面就是檔案的操作了,包括歌曲的新增和 往ListBox中插入歌曲名字。其實全部都是檔案路徑的操作,我們要得到歌曲的路徑,存於全域性變數中 我這裡是存到一個全域性結構體中,用來存放歌曲名字和路徑 。

typedef struct   //defined a information struct for song
{
	TCHAR songname[50];     //注意這個值過小 可能導致 輸入的資訊有誤,要保證有絕對空間  查了半天的錯
	TCHAR szfiledir[100];
}FileInfo;
FileInfo fileinfo[255];   //檔案資訊 只能存255首歌曲
     歌曲的名字,我們希望有標號,並且希望歌曲名字不帶.mp3的字樣,這裡就是擷取的方法,利用字串函式的操作,來獲取我們想要的檔名字。當我們同時選取了多個檔案時,實際上在記憶體中存在的形式就是該檔案的目錄+各個檔名字,每個檔名字以一個'\0'隔開。在呼叫完(GetOpenFileName(&ofn)這個函式成功後,會將你選擇的檔名全部存於該 ofn.lpstrFile=szOpenFileNames.也就是存於szOpenFileNames的陣列中。

所以剩下要做兩件事: 1.獲取每首歌曲完整路徑    2.拼寫出每個歌曲的名字 
將獲取的名字 格式化 加上數字,就插入到Listbox中即可。具體的參見工程中的程式碼。

2.播放音樂

      在上面我們大概瞭解了這麼新增檔案和修改檔名,剩下的就是要播放了,其實要播放一首歌曲很簡單,只需要條用mciSendCommand().函式即可,比如下面程式碼就可以播放一首歌曲
	mciSendCommand(DeviceId,MCI_PLAY,MCI_FROM|MCI_NOTIFY,(DWORD)(LPVOID)&mciplay);
引數1:是要播放的裝置號 引數2:是要播放的命令,引數3:是從哪裡播放和播放完傳送給主視窗一個通知
引數4:是結構體。每個mcisendcommand 都要關聯一個結構體,這要關聯播放mciplay
MCIDEVICEID DeviceId=0;		//開啟的裝置ID號
MCI_OPEN_PARMS mciopen;  //開啟結構體
MCI_PLAY_PARMS mciplay;	 //播放結構體
MCI_SET_PARMS  mciset;   //設定時間格式
MCI_SEEK_PARMS mciseek;	// 設定跳轉到
MCI_STATUS_PARMS mcistatus; //播放狀態 獲得歌曲總長度
具體的意思 和怎麼使用查詢 MSDN手冊。
      思路:就是先配置 mciopen。指定開啟的路徑(就是音樂檔案的路徑)成功開啟後,得到一個裝置號,然後用該裝置號來操作,比如播放,暫停,關閉..附加的功能 比如獲取 歌曲狀態,得到歌曲的總時間。
下面程式碼演示了怎麼開啟裝置和獲取歌曲總時間長度
BOOL DoPlay(HWND hwnd,INT index)  
{	
	mciopen.lpstrElementName=fileinfo[index].szfiledir;	//給開啟裝置指定路徑
	mciSendCommand(DeviceId,MCI_STOP,0,0); 
	mciSendCommand(DeviceId,MCI_CLOSE,0,0);	//先關閉全部變數的裝置
	if(0==mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_ELEMENT,(DWORD)(LPVOID)&mciopen))  //成功返回為0
	{	
	//	MessageBox(hwnd,TEXT("MCIOPEN開啟裝置成功"),TEXT(""),MB_OK);
		DeviceId=mciopen.wDeviceID;//成功開啟後將ID號保留下來。
		mciset.dwTimeFormat=MCI_FORMAT_MILLISECONDS; //config mciset time format
		mciSendCommand(DeviceId,MCI_SET,MCI_WAIT|MCI_FORMAT_MILLISECONDS,(DWORD)(LPMCI_SET_PARMS)&mciset);//設定歌曲的長度以Ms度量	
		mcistatus.dwItem=MCI_STATUS_LENGTH; 
		mciSendCommand(DeviceId,MCI_STATUS,MCI_WAIT|MCI_STATUS_ITEM,(DWORD)(LPMCI_STATUS_PARMS)&mcistatus);
		DWORD dwsonglen=mcistatus.dwReturn/1000; //返回歌曲的總長度 ms級別的 dwsonglen單位是秒
		SendDlgItemMessage(hwnd,IDC_SLIDER_SONG,TBM_SETRANGE,TRUE,MAKELPARAM(0,dwsonglen));//設定Silder的兩端範圍

		mciplay.dwFrom=0;//從0開始播放
		mciplay.dwCallback=(DWORD)hwnd;//播放完畢後,通該視窗處理函式
		mciSendCommand(DeviceId,MCI_PLAY,MCI_FROM|MCI_NOTIFY,(DWORD)(LPVOID)&mciplay);//開始播放
		ListBox_SetCurSel(hlistbox,iIndex);  //設定當前選中巨集
		return TRUE;
	}
	else 
		MessageBox(hwnd,TEXT("開啟歌曲錯誤"),TEXT("errror!"),MB_OK);
		return FALSE;
}
 下個模組繼續...              							

相關文章