以前,一直想写一个音乐播放器,但VC还没有完全学完,有些东西还练的很少,实力还不够,这是学完VC后,练习了很多东西,看了不少VC的知识,所以才决定写的。
这是2013年3月份写的,当时没有写在博客中,现在,将它写下来与大家分享,共同进步。
1.首先,音乐播放器最基本的还是如何播放音乐,解决了这个问题,即使不用界面,也能播放音乐了。VC中的MCI可以播放音乐。(MCI(Media Control Interface)媒体控制接口是MircroSoft提供的一组多媒体设备和文件的标准接口它的好处是可以方便地控制绝大多数多媒体设备包括音频、视频、影碟、录像等多媒体设备而不需要知道它们的内部工作状况。但是古人云成也萧何败也萧何。MCI虽然看上去高大全但对于一些高级应用来说它是远远不够的。 上面的话也不是我说的但低级中级应用是完全凑合的。 MCI向Windows程序提供了在高层次上控制媒体设备接口的能力。程序不必关心具体设备就可以对激光唱机CD、视盘机、波形音频设备、视频播放设备和MIDI设备等媒体设备进行控制。对于程序员来说可以把MCI理解为设备面板上的一排按键通过选择不同的按键发送不同的MCI命令可以让设备完成各种功能而不必关心设备内部实现。比如对于play视盘机和CD机有不同的反应一个是播放视频一个播放音频而对用户来说却只需要按同一按钮。)
2.其次,就是界面的设计,这可以仿照酷狗或QQ之类的播放器。
1)显示音乐列表。(我用Access记录音乐文件的位置,这样方便查找歌曲,采用ADO方式访问数据库)
2)播放暂停、前一首后一首、音量、歌词等按钮或控件。
3)搜索音乐,将文件中的歌曲添加到音乐列表等。
4)显示歌词。
截个图看看先:
由于当时的水平有限,虽然界面看起来还可以,但实际内部架构设计的不合理,没能很好地分类及应用好的设计模式(当时还没咋学设计模式),具体的代码就不传了。只将关键的技术或知识用代码让大家看一下:
1)由于要访问数据库,所以必须设计数据库的访问,这里我采用ADO的方式访问数据库,将其单独写在一个数据库连接类中(ADOConn)。
该类只负责连接数据库,读取数据库中的数据、写数据并跟新到数据库中及关闭数据库链接等。这个类写好之后,只要是用ADO方式连接数据库,都可以直接拿去使用,复用性很好。
部分代码:
class ADOConn
{
public:
ADOConn();
virtual ~ADOConn();
void OnInitADOConn();
void ExitConnect();
_RecordsetPtr &GetRecordSet(_bstr_t bstrSQL);
BOOL ExecuteSQL(_bstr_t bstrSQL);
_ConnectionPtr m_pConnection;
_RecordsetPtr m_pRecordset;
};
void ADOConn::OnInitADOConn()
{
CMuscicPlayerApp *app=(CMuscicPlayerApp*)AfxGetApp();
CString strpath=app->strPath;
HRESULT hr;
::CoInitialize(NULL); //初始化OLE/COM环境
hr=m_pConnection.CreateInstance("ADODB.Connection"); //创建connection对象
// 在ADO操作中建议语句中要常用try...catch()来捕获错误信息,
// 因为它有时会经常出现一些意想不到的错误。
try
{
if(SUCCEEDED(hr))
{
CString dbPath="Provider=Microsoft.Jet.OLEDB.4.0;Data Source="+strpath+"SongData.mdb";
hr=m_pConnection->Open(_bstr_t(dbPath),"","",adModeUnknown);
}
// _bstr_t strConnect="Provider=SQLOLEDB;Server=LENOVO-PC;DataBase=Study;uid=sa;pwd=zyc123";
// m_pConnection->Open(strConnect,"","",adModeUnknown);
}
//捕获异常
catch(_com_error e)
{
AfxMessageBox(e.Description());
}
}
void ADOConn::ExitConnect()
{
//关闭记录集和连接
if(m_pRecordset!=NULL)
m_pRecordset->Close();
m_pConnection->Close();
//释放环境
::CoUninitialize();
}
_RecordsetPtr& ADOConn::GetRecordSet(_bstr_t bstrSQL)
{
try
{
//连接数据库,如果conection对象为空,则重新连接数据库
if(m_pConnection==NULL)
OnInitADOConn();
//创建记录集对象
m_pRecordset.CreateInstance(__uuidof(Recordset));
//取得表中的记录
m_pRecordset->Open(bstrSQL,m_pConnection.GetInterfacePtr(),adOpenDynamic,adLockOptimistic,adCmdText);
}
catch(_com_error e)
{
e.Description();
}
//返回记录集
return m_pRecordset;
}
BOOL ADOConn::ExecuteSQL(_bstr_t _bstrSQL)
{
_variant_t RecordsAffected;
try
{
//是否已连接数据库
if(m_pConnection==NULL)
OnInitADOConn();
m_pConnection->Execute(_bstrSQL,NULL,adCmdText);
return true;
}
catch(_com_error e)
{
e.Description();
return false;
}
}
2)MCI播放音乐
代码:
//必要的参数声明
MCI_OPEN_PARMS mciOpen;
MCI_PLAY_PARMS mciPlay;
MCI_DGV_SETAUDIO_PARMS mciSetAudioPara;
UINT DeviceID;
DWORD Volume;
DWORD CdLen,Cdfrom;
//打开MCI
char buf[128]={0};
MCIERROR mciError;
mciOpen.lpstrDeviceType = "mpegvideo";
mciOpen.lpstrElementName = strFilePath;//播放文件的地址,支持格式mp3
mciError = mciSendCommand(0,MCI_OPEN,MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,(DWORD)&mciOpen);
if(mciError)
{
mciGetErrorString(mciError,buf,128);
}
//播放
DeviceID = mciOpen.wDeviceID ;
CdLen = Getinfo(MCI_STATUS_LENGTH);
Cdfrom=MCI_MAKE_HMS(0,0,0);
SetVolume();
mciError = mciSendCommand(DeviceID,MCI_PLAY,0 ,(DWORD)&mciPlay);
if(mciError)
{
MessageBox("send MCI_PLAY command failed!") ;
}
//暂停
dwReturn = mciSendCommand(DeviceID,MCI_PAUSE,0 ,(DWORD)&mciPlay);
if (dwReturn) {
MessageBox("MCI stop error");
}
//停止
DWORD dwReturn = 0;
dwReturn = mciSendCommand(DeviceID,MCI_STOP,0 ,(DWORD)&mciPlay);
//关闭MCI
dwReturn = mciSendCommand(DeviceID,MCI_CLOSE,0 ,(DWORD)&mciPlay);
3.读歌词,这部分实际就是读文件,只要将歌词文件中的时间读出来,然后与当前歌曲的播放时间进行比较,就可以确定显示哪一行歌词。
这是我写的读歌词代码,不是很好,但能读:
BOOL CMuscicPlayerDlg::OpenLyric()
{
double minute=0,second=0;
int Length,i=0;
CString strminute,strsecond;
int nSongName=0,nSinger=0,al=0,by=0;
CStdioFile file;
CFileException fileException;
if(!file.Open(strLyricPath,CFile::modeRead,&fileException)) //逐行读取字符串
{
//MessageBox("找不到该歌词文件");
return FALSE;
}
while( file.ReadString( szLine ) )
{
//strText +="\n";
//strText += szLine;
nSongName=szLine.Find("ti:");
nSinger=szLine.Find("ar:");
al=szLine.Find("al:");
by=szLine.Find("by:");
if(1==nSongName||1==nSinger||1==al||1==by)
{
Length=szLine.GetLength();
szLine=szLine.Right(Length-4);
Length=szLine.GetLength();
szLine=szLine.Left(Length-1);
minute=second=0.0;
}
else
{
Length=szLine.GetLength();
szLine=szLine.Right(Length-1);
strminute=szLine.Left(2);
Length=szLine.GetLength();
szLine=szLine.Right(Length-3);
strsecond=szLine.Left(5);
szLine=szLine.Right(Length-9);
minute=atof(strminute);
second=atof(strsecond);
}
StrLyric[i].strLyric=szLine;
StrLyric[i].time=(DWORD)(minute*60+second)*1000;
LyricLine=i;
i++;
}
return TRUE;
}