音乐播放器之源码解析四
来源:互联网 发布:简单的数据分析小工具 编辑:程序博客网 时间:2024/06/06 00:45
音乐播放器播放列表实现解析
playlist.h头文件
#ifndef PLAYLIST_H#define PLAYLIST_Hint PlayListInit();int PlayListDestroy();char *GetItemFromDefaultPlaylist(int pos);int GetDefaultPlaylistTotalItem();int DefaultPlaylistAddItem(char *itempath);int DefaultPlaylistDeleteItem(int pos);int DefaultPlaylistSave();#endif
默认播放列表为default.m3u,位于可执行文件相同目录,歌曲条目用单链表存储,默认播放列表为g_playlisthead头及指向末尾项的g_playlisttail两个指针控制。
#include <windows.h>#include <stdio.h>#include <string.h>#define DEFAULT_PLAYLIST "default.m3u"typedef struct listNode listNode;struct listNode{char val[MAX_PATH];listNode *next;};listNode *g_playlisthead = NULL;listNode *g_playlisttail = NULL;int bChange = 0;int g_playlistitemcount = 0;char g_defaultlistpath[MAX_PATH] = {0};
PlayListInit函数
创建播放列表
int PlayListInit(){return MakePlayList();}int MakePlayList(){FILE *fp;char defaultlistpath[MAX_PATH] = {0};char *pplpath;char buf[MAX_PATH] = {0};GetModuleFileName(NULL, defaultlistpath, MAX_PATH);pplpath = strrchr(defaultlistpath, '\\');pplpath[1] = '\0';strcpy(g_defaultlistpath, defaultlistpath);sprintf(defaultlistpath, "%s%s", defaultlistpath, DEFAULT_PLAYLIST);fp = fopen(defaultlistpath, "r");if (fp == NULL){printf("open %s error\n", DEFAULT_PLAYLIST);return -1;}do {char *p;listNode *lnode;p = fgets(buf, MAX_PATH, fp);if (p == NULL){break;}g_playlistitemcount++;lnode = malloc(sizeof(listNode));memset(lnode->val, 0, MAX_PATH);strncpy(lnode->val, buf, strlen(buf) - 1); //不读取\nlnode->next = NULL;if (g_playlisthead == NULL){g_playlisthead = lnode;g_playlisttail = g_playlisthead;}else{g_playlisttail->next = lnode;g_playlisttail = lnode;}} while (1);return 0;}
打开default.m3u文件并循环获取每一行,每一行表示一首歌曲,分别放入播放链表g_playlisthead末尾。
PlayListDestroy函数
销毁默认播放列表
int PlayListDestroy(){return DestroyDefaultPlayList();}int DestroyDefaultPlayList(){listNode *lnode;listNode *lnodenext;if (g_playlisthead == NULL){return 0;}lnode = g_playlisthead;while (lnode){lnodenext = lnode->next;free(lnode);lnode = lnodenext;}return 0;}
释放播放链表每一项内容。
GetItemFromDefaultPlaylist函数
通过pos获取歌曲路径,pos从0开始表示第一首歌
char *GetItemFromDefaultPlaylist(int pos){int i = 0;listNode *lnode;if (g_playlisthead == NULL){return NULL;}if (pos >= g_playlistitemcount){return NULL;}lnode = g_playlisthead;while (i < pos && lnode != NULL){i++;lnode = lnode->next;}if (lnode == NULL){return NULL;}return lnode->val;}
GetDefaultPlaylistTotalItem函数
获取默认播放列表所有条目个数,g_playlistitemcount记录条目总数,在添加歌曲时递增,删除歌曲时递减。
int GetDefaultPlaylistTotalItem(){return g_playlistitemcount;}
DefaultPlaylistAddItem函数
添加歌曲,传入歌曲的绝对路径
// 添加一项,itempath绝对路径int DefaultPlaylistAddItem(char *itempath){WIN32_FIND_DATA finddata;HANDLE handle;handle = FindFirstFile(itempath, &finddata);if (INVALID_HANDLE_VALUE == handle){return -1;}if (finddata.cFileName){listNode *lnode;lnode = malloc(sizeof(listNode));memset(lnode->val, 0, MAX_PATH);strcpy(lnode->val, itempath);lnode->next = NULL;if (g_playlisthead == NULL){g_playlisthead = lnode;g_playlisttail = g_playlisthead;}else{g_playlisttail->next = lnode;g_playlisttail = lnode;}g_playlistitemcount++;bChange++;}return 0;}
DefaultPlaylistDeleteItem函数
通过pos位置删除歌曲,pos从0开始表示第一项
// 删除一项,pos从0开始int DefaultPlaylistDeleteItem(int pos){listNode *lnode;listNode *lnodeprev;int i = 0;if (pos >= g_playlistitemcount || g_playlisthead == NULL){return 0;}bChange++;// 只有一项if (g_playlistitemcount == 1){free(g_playlisthead);g_playlisthead = NULL;g_playlisttail = NULL;g_playlistitemcount--;return 0;}// 删除第一项if (pos == 0){lnode = g_playlisthead;g_playlisthead = lnode->next;free(lnode);lnode = NULL;return 0;}// 删除最后一项if (pos == g_playlistitemcount -1){lnode = g_playlisthead;while (lnode->next->next){lnode = lnode->next;}g_playlisttail = lnode;lnode = lnode->next;g_playlisttail->next = NULL;free(lnode);lnode = NULL;g_playlistitemcount--;return 0;}// 删除中间一项lnodeprev = g_playlisthead;while (i < pos - 1){lnodeprev = lnodeprev->next;i++;}lnode = lnodeprev->next;free(lnode);lnode = NULL;lnodeprev->next = NULL;g_playlistitemcount--;return 0;}
DefaultPlaylistSave函数
保存修改过的默认播放列表
int DefaultPlaylistSave(){FILE *fp;listNode *lnode;char plpath[MAX_PATH] = {0};if (bChange == 0 || g_playlistitemcount == 0 || g_playlisthead == NULL){return 0;}sprintf(plpath, "%s%s", g_defaultlistpath, DEFAULT_PLAYLIST);fp = fopen(plpath, "w+");if (fp == NULL){printf("open %s error\n", DEFAULT_PLAYLIST);return -1;}lnode = g_playlisthead;while (lnode){fputs(lnode->val, fp);//fwrite(lnode->val, 1, strlen(lnode->val), fp);fputs("\n", fp);lnode = lnode->next;}fflush(fp);fclose(fp);return 0;}
至此播放列表的实现已经完毕,其中包括初始化播放链表,通过歌曲绝对路径添加歌曲,删除歌曲及保存播放列表功能。接下来实现为显示播放时间进度及歌词。
BeginTimeEvent函数
创建定时器线程,该线程TimeEvenProc中包含显示播放时间进度、一首歌结束后默认播放下一曲、同步显示歌词功能。
void TimeEventProc(UINT wTimerID, UINT msg,DWORD dwUser,DWORD dwl,DWORD dw2){long long curpos = 0;long long stoppos = 0;int curtime = 0;int stoptime = 0;char *p = NULL;char *szLryic = NULL;char szTime[1024] = {0};double rate = 0.0;mpxGetPositions(&curpos, &stoppos);if (curpos == stoppos){// 播放下一曲WCHAR songpath[MAX_PATH] = {0};char lyricpath[MAX_PATH] = {0};char *p;playIndex++;if (playIndex > GetDefaultPlaylistTotalItem()){playIndex = 0;}p = GetItemFromDefaultPlaylist(playIndex);if (p == NULL){return;}MakeLyricPathFromSongPath(p, lyricpath);LyricDestroy();LyricInit(lyricpath);MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, p, strlen(p), songpath, MAX_PATH);mpxPlayFile(songpath);status = C_BTN_PLAY;SetWindowText(btnPlay, "pause");SetWindowText(g_hWnd, p);}curtime = (int)(curpos / (double)10000000);stoptime = (int)(stoppos / (double)10000000);sprintf(szTime, "%02d:%02d->%02d:%02d", curtime/60, curtime%60, stoptime/60, stoptime%60);SendMessage(timeStatic, WM_SETTEXT, 0, szTime);szLryic = GetLyricByStartTime(curtime);if (szLryic != NULL){SendMessage(lyricStatic, WM_SETTEXT, 0, szLryic);}}void BeginTimeEvent(){if((g_timeId = timeSetEvent(500, 1,(LPTIMECALLBACK)TimeEventProc,(DWORD_PTR)0,TIME_PERIODIC)) == 0){printf("time set event error!\n");}}
mpxGetPositions获取播放的当前位置和停止位置,当播放结束后有可能获取不到值,此时两个变量的值为初始值0,此时也表示播放已结束,此时playIndex递增并表示播放下一曲。
curpos和stoppos获取到的值需要除以10000000的结果才表示秒,然后调用SendMessage(timeStatic, WM_SETTEXT, 0, szTime)将当前播放的时间和结束时间显示在timeStatic组件上表示播放歌曲的时间进度。
通过curtime单位为1/100秒,传入GetLyricByStartTime(curtime)函数获取当前时间对应的歌词,找的对应的歌词则将歌词显示在lyricStatic组件上,实现同步显示歌词功能。
EndTimeEvent函数
销毁定时器
void EndTimeEvent(){if (g_timeId != 0){timeKillEvent(g_timeId);g_timeId = 0;}}
下一篇音乐播放器同步歌词源码解析
- 音乐播放器之源码解析四
- 音乐播放器之源码解析一
- 音乐播放器之源码解析二
- 音乐播放器之源码解析三
- 音乐播放器之源码解析五
- 音乐播放器之源码解析六
- android源码解析------Music 音乐播放器
- 音乐播放器源码
- android-音乐播放器实现及源码下载(四)
- android-音乐播放器实现及源码下载(四)
- android音乐播放器源码
- 音乐播放器源码下载
- android音乐播放器源码
- 小程序(之音乐播放器源码实现)
- android之音乐播放器
- html之音乐播放器
- Android之音乐播放器
- 音乐播放器之--在线音乐播放
- vector下标操作
- suggestTree-实现rank-ordered autocomplete suggestions的数据结构
- 11384 - Help is needed for Dexter
- 标准C++中的string类的用法总结
- 删除双向循环列表的共同节点
- 音乐播放器之源码解析四
- 黑马程序员------java学习笔记之String类
- IOS视频教程
- Qt模态与非模态
- 三次握手的简单理解
- oracle 11gR2 新增deinstall命令来卸载grid和database
- 字符串匹配
- HTML中id、name、class 区别
- HDU1506------据说是DP,我更觉得是简单的枚举