音乐播放器之源码解析五

来源:互联网 发布:mysql 5.6.25.tar.gz 编辑:程序博客网 时间:2024/06/10 04:33

音乐播放器同步歌词源码解析

歌词lyric.h头文件

#ifndef LRC_H#define LRC_Hint LyricInit(char *lrcpath);int LyricDestroy();char *GetLyricByStartTime(int startTime);char *GetLyricByPos(int pos);int GetLyricTotalLine();#endif


传入歌词路径调用LyricInit函数初始化歌词,不再使用后调用LyricDestroy销毁歌词,通过GetLyricByStartTime获取对应时间的歌词。

typedef struct LineLyric LineLyric;struct LineLyric{int startTime; // second millisecondchar szLrc[LRC_LEN_MAX];LineLyric *next;};LineLyric *g_lineLyricHead = NULL;LineLyric *g_lineLyricTail = NULL;int g_lineLyricCount = 0;


存储歌词使用单链表及g_lineLyricHeadg_lineLyricTail指向歌词头和末尾行。没一行歌词项保存有歌词的开始时间及歌词。

LyricInit函数

初始化歌词

int LyricInit(char *lrcpath){FILE *fp = NULL;char buf[LRC_LEN_MAX] = {0};WCHAR wbuf[LRC_LEN_MAX] = {0};char *p;fp = fopen(lrcpath, "r");if (fp == NULL){printf("lyric init open %s error(%d)\n", lrcpath, GetLastError());return -1;}while ((p = fgets(buf, LRC_LEN_MAX, fp)) != NULL){char *tok = "[";char *tmpval = NULL;if (*p == '\n'){continue;}tmpval = strchr(p, '[');if (tmpval == NULL){continue;}tmpval++;if (strnicmp(tmpval, "ar", 2) == 0) //!< 艺人名{}else if (strnicmp(tmpval, "ti", 2) == 0) //!< 曲名{}else if (strnicmp(tmpval, "al", 2) == 0) //!< 专辑名{}else if (strnicmp(tmpval, "by", 2) == 0) //!< 编者{}else if (strnicmp(tmpval, "offset", 6) == 0)//!< 时间补偿值{}else{char *lrc;LineLyric *llnode = NULL;float mi= 0.0;float ss = 0.0;int startTime= 0;char *left = p;char *right;lrc = strrchr(buf, ']');lrc++;do {char tmp[128] = {0};left = strchr(left, '[');if (left == NULL){break;}left++;right = strchr(left, ':');memcpy(tmp, left, right - left);mi = (float)atof(tmp);left = right+1;right = strchr(left, ']');memcpy(tmp, left, right - left);ss = (float)atof(tmp);startTime = (int)(mi*60+ss);llnode = malloc(sizeof(LineLyric));memset(llnode, 0, sizeof(LineLyric));llnode->startTime = startTime;strcpy(llnode->szLrc, lrc);llnode->next = NULL;if (g_lineLyricHead == NULL){g_lineLyricHead = llnode;g_lineLyricTail = llnode;}else{LineLyric *llprev = g_lineLyricHead;LineLyric *llnext = llprev->next;if (llnode->startTime < llprev->startTime){llnode->next = llprev;g_lineLyricHead = llnode;}else{while (llnext && llnext->startTime <= llnode->startTime){llprev = llnext;llnext = llnext->next;}llnode->next = llnext;llprev->next = llnode;if (llnext == NULL){g_lineLyricTail = llnode;}}}g_lineLyricCount++;left = right+1;} while (1);}}return 0;}


lyric歌词格式见http://baike.baidu.com/view/239396.htm解析每一行歌词并排序存储至歌词链表中。

LyricDestroy函数

销毁歌词

int LyricDestroy(){LineLyric *llnode;if (g_lineLyricHead == NULL){return 0;}llnode = g_lineLyricHead;while (llnode){LineLyric *llnext = llnode->next;free(llnode);llnode = llnext;}g_lineLyricHead = NULL;g_lineLyricTail = NULL;g_lineLyricCount = 0;return 0;}


释放歌词链表项。

GetLyricByStartTime函数

通过开始时间获取对应的歌词字符串

char *GetLyricByStartTime(int startTime){LineLyric *llnode;char *szLrc = NULL;if (g_lineLyricHead == NULL){return NULL;}llnode = g_lineLyricHead;while (llnode){if (llnode->startTime == startTime){if (szLrc == NULL){szLrc = malloc(strlen(llnode->szLrc)+1);memset(szLrc, 0, strlen(llnode->szLrc)+1);strcat(szLrc, llnode->szLrc);}else{szLrc = realloc(szLrc, strlen(szLrc)+strlen(llnode->szLrc)+2);strcat(szLrc, " ");strcat(szLrc, llnode->szLrc);}}llnode = llnode->next;}return szLrc;}


至此主要功能已经实现。

 

下一篇音乐播放器命令行界面实现源码解析