一个基于Window Media Player控件的简单播放器

最近写了一个播放器,基于media player控件的,主界面如图:关键在网络搜索歌词和播放本地LRC文件,如下:

1.网络搜索歌词首先用CWMPMedia获取当前歌曲,调用getItemInfo(_T("Title")获取当前歌曲名字,然后通过CWebBrowser2访问百度MP3搜索对应歌词,接着通过IHTMLDocument2分析获取文档源码,找到歌词所在div,并进行一些转换,放到歌词对话框中,关键代码如下:

void CNannanDlg::PlayStateChangeOcx1(long NewState) { //NewState 10代表初始化的时候,9代表正在连接,3代表正在播放 if(NewState == 3) { CWMPMedia3 media = static_cast(m_player.get_currentMedia()); for(int i=0;i

void CNannanDlg::DocumentCompleteExplorer3(LPDISPATCH pDisp, VARIANT* URL) { IHTMLDocument2* pHTMLDocument = static_cast(m_browser.get_Document()); if(pHTMLDocument) { HRESULT hr = S_OK; IHTMLElementCollection* pHTMLCollection; hr = pHTMLDocument->get_all(&pHTMLCollection); long length; hr = pHTMLCollection->get_length(&length); for(int i=0;i lp; hr=pHTMLCollection->item(CComVariant((long)i),CComVariant(),&lp); CComQIPtr pHTMLElement = lp; BSTR tagName; hr = pHTMLElement->get_tagName(&tagName); //下面两句代码将BSTR转换为CString CString name = COLE2CT(tagName); SysFreeString(tagName); if(name==_T("DIV")) { IHTMLStyle* pHTMLStyle; pHTMLElement->get_style(&pHTMLStyle); BSTR css; pHTMLStyle->get_cssText(&css); BSTR innerHTML; hr = pHTMLElement->get_innerHTML(&innerHTML); CString cssText = COLE2CT(css); SysFreeString(css); cssText = cssText.MakeLower(); cssText = cssText.Trim(); CString inner = COLE2CT(innerHTML); SysFreeString(innerHTML); if(cssText == _T("padding-left: 10px; line-height: 20px; padding-top: 1px"))//这个只针对于百度mp3的歌词搜索,歌词内容放在

里面,而这个div的style可以知道,全部源文件只有这一个div的style是这样 { inner.Replace(_T("["),_T("")); inner.Replace(_T("]"),_T("")); inner.Replace(_T("ar:"),_T("演唱:")); inner.Replace(_T("ti:"),_T("")); inner.Replace(_T("al:"),_T("专辑:")); inner.Replace(_T("by:"),_T("LRC编辑:")); inner.Replace(_T("
"),_T("/r/n")); inner.Replace(_T(""),_T("")); inner.Replace(_T(""),_T("")); int offset = inner.Find(_T("m_lrc.m_lycContent.SetWindowTextW(inner.Left(offset)); break; } } } pHTMLDocument->Release(); } } void CNannanDlg::SearchLYC(void) { IHTMLDocument2* pHTMLDocument = static_cast(m_browser.get_Document()); if(pHTMLDocument) { HRESULT hr = S_OK; IHTMLElementCollection* pHTMLCollection; hr = pHTMLDocument->get_all(&pHTMLCollection); long length; hr = pHTMLCollection->get_length(&length); for(int i=0;i lp; hr=pHTMLCollection->item(CComVariant((long)i),CComVariant(),&lp); CComQIPtr pHTMLElement = lp; BSTR tagName; hr = pHTMLElement->get_tagName(&tagName); //下面两句代码将BSTR转换为CString CString name = COLE2CT(tagName); SysFreeString(tagName); if(name==_T("DIV")) { BSTR innerHTML; hr = pHTMLElement->get_innerHTML(&innerHTML); MessageBox(innerHTML); CString inner = COLE2CT(innerHTML); SysFreeString(innerHTML); if(inner.Left(4) == _T("[ti:")) { inner.Replace(_T("
"),_T("/r/n")); inner.Replace(_T(""),_T("")); inner.Replace(_T(""),_T("")); int offset = inner.Find(_T("m_lrc.m_lycContent.SetWindowTextW(inner.Left(offset)); break; } } } pHTMLDocument->Release(); } } 

网络歌词如图:

2.读取本地LRC文件并滚动显示歌词,使用CStdioFile读取本地LRC文件,定义了一个结构体struct lycContent
{
 CString time;
 CString content;
 int rowIndex;
 int charNumber;
};用来存储每行的歌词,播放歌曲时,读取本地LRC文件,将歌词信息读取lycContent数组中,获取每行歌词对应的时间及内容,并对LRC的一些标识进行转换,如[ti:蓝莲花]转为蓝莲花,[ar:许巍]转为"演唱:许巍",接着根据lycContent中的time进行排序。定义一个计时器,每秒运行一次OnTimer,在此函数中进行歌词的同步,通过CWMPControls获取当前播放时间,格式为03:02等,遍历lycContent数组,得到时间相等的值,改变歌词对话框中相应歌词的颜色,以达到同步的效果。同时另外定义一个计时器,每隔五秒滚动用于显示歌词的richedit控件(LineScroll),以使所有歌词都能显示,关键代码如下:

bool CNannanDlg::GenerateLrcArray(CString lrcPath) { setlocale( LC_CTYPE, "chs" );//纠结了很久的乱码问题终于解决了 CString content; CStdioFile* s = new CStdioFile(); if(s->Open(lrcPath,CFile::modeReadWrite|CFile::shareDenyNone)) { int i = 0; while(s->ReadString(content)) { while(content.GetLength() != 0) { int index = content.Find(_T("[")); if(index != -1) { i++; content = content.Right(content.GetLength() - index - 1); } else { break; } } } m_lycArray = new lycContent[i]; m_lycCount = i; i = 0; s->SeekToBegin(); while(s->ReadString(content)) { while(content.GetLength() != 0) { int firLeft = content.Find(_T("[")); int firRight = content.Find(_T("]")); int lastRight = content.ReverseFind(_T(']')); if(firLeft != -1) { m_lycArray[i].rowIndex = i; m_lycArray[i].time = content.Left(firRight); m_lycArray[i].time.Replace(_T("["),_T("")); m_lycArray[i].content = content.Right(content.GetLength() - lastRight - 1); if(m_lycArray[i].content == _T("")) { m_lycArray[i].content = m_lycArray[i].time; m_lycArray[i].time = _T("99:99"); m_lycArray[i].content.Replace(_T("ar:"),_T("演唱:")); m_lycArray[i].content.Replace(_T("ti:"),_T("")); m_lycArray[i].content.Replace(_T("al:"),_T("专辑:")); m_lycArray[i].content.Replace(_T("by:"),_T("LRC编辑:")); m_lycArray[i].content.Replace(_T("offset:"),_T("时间补偿值:")); } m_lycArray[i].content = m_lycArray[i].content + _T("/t/r"); m_lycArray[i].charNumber = m_lycArray[i].content.GetLength(); i++; content = content.Right(content.GetLength() - firRight - 1); } else { break; } } } BubbleSort(m_lycCount);//歌词排序 //设置初始歌词范围 int startIndex = 0; for(int n=0;n

void CNannanDlg::OnTimer(UINT_PTR nIDEvent) { switch(nIDEvent) { case 1: { m_lrc.m_lycContent.LineScroll(1); break; } case 2: { CWMPControls control = static_cast(m_player.get_controls()); CString currentTime = control.get_currentPositionString(); int i; bool flag = false; for(i=0;i0) { m_curLrcRange.cpMin = m_curLrcRange.cpMin + m_lycArray[i-1].charNumber; m_curLrcRange.cpMax = m_curLrcRange.cpMax + m_lycArray[i].charNumber; } ZeroMemory(&cf, sizeof(CHARFORMAT)); cf.cbSize = sizeof(CHARFORMAT); cf.dwMask = CFM_BOLD | CFM_COLOR | CFM_FACE | CFM_ITALIC | CFM_SIZE | CFM_UNDERLINE; cf.crTextColor = RGB(255,0,0); //文字颜色 m_lrc.m_lycContent.SetSel(m_curLrcRange); m_lrc.m_lycContent.SetSelectionCharFormat(cf); } break; } } //CWMPControls control = static_cast(m_player.get_controls()); CDialog::OnTimer(nIDEvent); }

歌词同步如图:

 

总结:这个程序使用了一些控件,media player控件,listcontrol控件(存放播放列表),richedit2控件(存放歌词),webbrowser控件(通过百度mp3进行歌词搜索)。由于时间仓促,只实现了简单的打开,添加(文件,文件夹),最小化到托盘,主界面与歌词同时移动等等功能,快进,上下首,后退,调节音量等等在控件上可以操作,个人测试中,网络搜索歌词受网速影响,本地LRC歌词同步效果还行。

 

 

 

你可能感兴趣的:(一个基于Window Media Player控件的简单播放器)