Lrc歌词文件格式及其C++代码实现
lrc的格式

lrc的格式
LRC文件是一种歌词文件格式,用于显示歌曲的歌词。
其标准格式如下:
1. [ti:歌曲标题] - 歌曲标题,以"ti:"开头,后面跟着歌曲的标题。
2. [ar:歌手名] - 歌手名,以"ar:"开头,后面跟着歌手的名字。
3. [al:专辑名] - 专辑名,以"al:"开头,后面跟着专辑的名字。
4. [by:制作人] - 制作人,以"by:"开头,后面跟着制作人的名字。
5. [offset:时间偏移量] - 时间偏移量,以"offset:"开头,后面跟着一个整数,表示歌词时间与音乐时间的偏移量,单位是毫秒。
6. [length:歌曲长度] - 歌曲长度,以"length:"开头,后面跟着歌曲的长度,格式为"mm:ss"。
7. [00:]歌词内容- 歌词内容,以"[开始时间]"开头,后面是歌词的具体内容。
时间格式为"mm:",表示歌词出现的时间点。
用记事本按照上述格式写好后,将扩展名改为lrc即可做出“文件名.LRC”
的歌词文件。
请注意,外文名lrc、定义歌词文件的扩展名、全称lyric、编码方式ANSI
与UTF-8居多等其他格式可能与标准格式略有不同。
建议咨询专业的技术
从业者获取更多具体信息。
歌词解析器代码详情

歌词解析器代码详情共6个文件,一个文件夹。
Dir目录如下。
驱动器F 中的卷没有标签。
卷的序列号是18A6-FCB5F:\W.E\C语言编程\歌词解析器的目录2013-01-22 16:27.2013-01-22 16:27..2013-01-22 16:27lrc2012-11-19 15:29 9,215 lrc.c2011-12-12 12:17 644 lrc.h2012-09-24 15:18 2,083 main.c2013-01-22 16:27pos3 个文件11,942 字节4 个目录171,449,978,880 可用字节Pos下有文件:console.c console.h resource.h现将所有文件内容罗列于下,自行分开.c.h Main.c#include#include#include#include#include "lrc.h"#include "./pos/console.h"typedef struct time{ //表示日期时间的数据结构char minute;char second;}TIME;TIME m_time; //存储模拟时间char * song_msg[4]; //存储歌曲的信息/************************************************************** ************ 函数功能:歌词解析器整体的控制* 参数:无* 返回值:无*************************************************************** ***********/int main(){int file_length=0; // 存储lrc文件内容的大小char * file_buf=NULL; // 指向malloc的空间,其中存放着lrc 文件中所有的内容char * lrc_text[200]={NULL}; // 指向,按照\r\n 切割后的一行歌词int lrc_line=0; // lrc文件中的行数int i=0;LRC * head=NULL,*p; // head记录歌词链表头int s_time=0; // 模拟时间变量file_buf=read_src_file(&file_length,"./lrc/兰亭序.lrc"); // 从lrc 文件中读出歌词内容lrc_line=strtok_lrc_buf(lrc_text,file_buf); // 按行切割歌曲内容lrc_head_resolve(song_msg,lrc_text); // 切割歌曲信息print_song_message(song_msg); // 显示歌曲信息head=lrc_resolve(lrc_line,lrc_text); // 保存时间:歌词到链表中// print(head); // 遍历链表,用来测试链表// ShellExecute( NULL, NULL, "TTPlayer.exe","兰亭序.mp3",NULL,1); //开启千千静听m_time.second=0;m_time.minute=0;while(1) //每秒钟到链表里面去找相应的歌词,如果找到那么就显示{/** 1.定位光标,显示歌词*/GoToXY(20,5);printf("%02d:%02d",m_time.minute,m_time.second);p=search(head,s_time); //到连表里查找当前时间点对应的歌词,如果有那么就返回歌词的首地址if(p!=NULL){lrc_show(p);}/** 1.运行模拟时间*/Sleep(500); //延时,注意在windows平台Sleep(1);延时1毫秒s_time=s_time+1;++m_time.second;if(m_time.second==60){m_time.second=0;++m_time.minute;if(m_time.minute==60)m_time.minute=0;}}return 0;}/************************************************************** ***************/ lrc.h#ifndef __LRC_H__#define __LRC_H__typedef struct lrc{int time;char lrc_buf[200];struct lrc *next;}LRC;extern char * read_src_file(int *file_length,char *src_file_name);extern int strtok_lrc_buf(char *lrc_text[],char *file_buf);extern void lrc_head_resolve(char *lrc_head_info[],char * lrc_text[]);extern void print_song_message(char * msg_info[]);extern LRC * lrc_resolve(int lrc_line,char * lrc_text[]);extern LRC *InsertList(LRC* head,LRC *lrc_link);extern void print(LRC * head);extern LRC *search (LRC *head,int time);extern void lrc_show(LRC * pi);extern void print_lrc(char * lrc);#endif/************************************************************** ***************/lrc.c#include#include#include#include#include "lrc.h"#include "./pos/console.h"/************************************************************** *********** * 函数功能:读出文件内容* 参数:* file_length:整型指针,此地址中保存文件字节数。
C语言课程设计歌曲信息管理源代码

C语言课程设计歌曲信息管理源代码#include "stdio.h"#include "string.h"#include "conio.h"#include "stdlib.h"struct music_list{char name[10];char singer[25];char ci[25];char qu[25];char zhuanji[25];char fxtime[25];char fxgongsi[25];int flag;};int count=0;const int MAX_COUNT = 100;void new_music(struct music_list musics[]);void delete_music_byname(struct music_list musics[],char* name); void search_music(struct music_list musics[],char*name);void show_all(struct music_list musics[]);int main(){ int choice;char name[10];struct music_list musics[MAX_COUNT];int i;for(i=0;i<MAX_COUNT;i++){musics[i].flag = 0;}T:do{printf("*******************************************************\n");printf("\nselect:1:new music 2:search 3:delete 4:show all 0:Exit\n");printf("*******************************************************\n");printf("please:");scanf("%d",&choice);switch(choice){case 1:new_music(musics);break;case 2:printf("Name:");scanf("%s",name);search_music(musics,name);break;case 3:printf("Name:");scanf("%s",name);delete_music_byname(musics,name);break;case 4:show_all(musics);break;case 0:break;default:choice = 0;}}while(choice !=0);printf("Thanks,Bye!\n");getch();return 0;}void new_music(struct music_list musics[]) {if(count==MAX_COUNT){printf("address list is full!\n");return;}int i,j;for(i=0;i<MAX_COUNT;i++){if(musics[i].flag == 0){j = i;break;}}printf("name:");scanf("%s",musics[j].name);printf("geshou:");scanf("%s",musics[j].singer);printf("zuoci:");scanf("%s",musics[j].ci);printf("zuoqu:");scanf("%s",musics[j].qu);printf("zhuanji:");scanf("%s",musics[j].zhuanji);printf("chubanshijian:");scanf("%s",musics[j].fxtime);printf("chubangongsi:");scanf("%s",musics[j].fxgongsi);musics[j].flag = 1;count++;}void search_music(struct music_list musics[],char*name){int i,j,flag=0;if(count==0){printf("Music list is empty!\n");return;}for(i=0;i<MAX_COUNT;i++){if(strcmp(name,musics[i].name)==0 && musics[i].flag == 1){if(flag == 0) {printf("====================================================== =\n");printf("name\t",musics[i].name);printf("singer\t",musics[i].singer);printf("ci\t",musics[i].ci);printf("qu\t",musics[i].qu);printf("zhuanji\t",musics[i].zhuanji);printf("fxtime\t",musics[i].fxtime);printf("fxgongsi\t",musics[i].fxgongsi);printf("\n==================================================== ===\n");flag=1;}printf("%s\t",musics[i].name);printf("%s\t",musics[i].singer);printf("%s\t",musics[i].ci);printf("%s\t",musics[i].qu);printf("%s\t",musics[i].zhuanji);printf("%s\t",musics[i].fxtime);printf("%s\t\n",musics[i].fxgongsi);}}if(flag!=1){printf("No such a music!");}}void show_all(struct music_list musics[]){if(count==0){printf("Music list is empty!\n");return;}int i,flag=0;;for(i=0;i<MAX_COUNT;i++){if(musics[i].flag == 1){if(flag == 0) {printf("====================================================== =\n");printf("name\t",musics[i].name);printf("singer\t",musics[i].singer);printf("ci\t",musics[i].ci);printf("qu\t",musics[i].qu);printf("zhuanji\t",musics[i].zhuanji);printf("fxtime\t",musics[i].fxtime);printf("\n==================================================== ===\n");flag=1;}printf("%s\t",musics[i].name);printf("%s\t",musics[i].singer);printf("%s\t",musics[i].ci);printf("%s\t",musics[i].qu);printf("%s\t",musics[i].zhuanji);printf("%s\t",musics[i].fxtime);printf("%s\t\n",musics[i].fxgongsi);}}}void delete_music_byname(struct music_list musics[],char* name){int i,j,flag=0;if(count==0){printf("Music list is empty!\n");return;}for(i=0;i<MAX_COUNT;i++){if(strcmp(name,musics[i].name)==0 && musics[i].flag == 1){musics[i].flag = 0;count --;if(flag == 0) {printf("The music \" %s \" was deleted.\n",musics[i].name);printf("====================================================== =\n");printf("name\t",musics[i].name);printf("singer\t",musics[i].singer);printf("ci\t",musics[i].ci);printf("qu\t",musics[i].qu);printf("zhuanji\t",musics[i].zhuanji);printf("fxtime\t",musics[i].fxtime);printf("\n==================================================== ===\n");flag=1;}printf("%s\t",musics[i].name);printf("%s\t",musics[i].singer);printf("%s\t",musics[i].ci);printf("%s\t",musics[i].qu);printf("%s\t",musics[i].zhuanji);printf("%s\t",musics[i].fxtime);printf("%s\t\n",musics[i].fxgongsi);}}if(flag!=1){printf("No such a music!");}}。
C语言同步显示lrc歌词

C语言同步显示lrc歌词C语言技术报告班级:学号:姓名:项目说明:1、本程序在VC环境下调试成功环境:需安装千千静听到默认路径下,同时安装vc6.0环境2、本程序完成功能:完成LRC格式歌词的文件读取、解析、结构体创建等,同时在屏幕上将解析出的歌词进行实时显示基本功能实现:1、读取文件,能正确打印到屏幕上。
2、切割字符串,正确存到一个结构体数组中。
3、能正确判断歌曲的歌名与演唱者,并打印出来。
4、实现模拟时钟的功能。
5、按顺序将歌词输出。
6、能滚动显示歌词。
7、能与时间匹配突出显示歌词的颜色。
项目流程:1、首先将歌词文件内容通过fopen全部读到一个数组song_word[][]中,然后将歌词内容保存到数组song_word1[][]。
2、通过函数message_song1()判断歌曲的歌名与演唱者,并打印出前4行的歌曲信息。
3、用函数message_song2()和strtok将同一行的歌词和时间一一对应的进行切割,并分别保存在数组lyric[][]和time[][]中,并通过Sleep(1000)将时间标签转换为以s为单位的模拟时钟。
4、在每一秒内对将时钟的时间与歌词前面的时间相比较,如果相等那么就输出当前时间后面的歌词,实现了歌词与时间的同步显示。
5、歌词的前5行依次输出,当歌词大于5行时,用函数MoveText(22,6,20,5,22,5);实现将歌词整块移动并每次显示5行。
7、GoToXY(22,m)和SetText_Color(2)实现将光标定位在当前行并且显示相应的颜色,使已显示的歌词变为白色,而刚出现的歌词变为相应的颜色。
6、在主程序运行时即可启动千千静听ShellExecute( NULL, NULL, "TTPlayer.exe",".\\LRC\\简单爱.mp3",NULL,1);代码:#include#include#include#include#include#include"console.h"//跳转到光标指定位置void GoToXY(int x,int y){HANDLE h1;COORD pos;pos.X=x;pos.Y=y;h1=GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorPosition(h1,pos);}//屏幕整块移动//参数:startx、starty:要移动的块的起始坐标// sizex、sizey:块的大小// destx、desty: 目标坐标,即要移动到得位置void MoveText(int startx, int starty, int sizex, int sizey, int destx, int desty) {SMALL_RECT rc = {startx, starty,startx+sizex, starty+sizey};COORD crDest = {destx, desty};CHAR_INFO chFill;HANDLE hout = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_SCREEN_BUFFER_INFO bInfo;GetConsoleScreenBufferInfo(hout, &bInfo);chFill.Attributes = bInfo.wAttributes;chFill.Char.AsciiChar =' ';ScrollConsoleScreenBuffer(hout, &rc, NULL, crDest, &chFill);}/*第一个值为背景色,第二个值为前景色:0 = 黑8 = 灰1 = 蓝9 = 淡蓝2 = 绿 A = 淡绿3 = 湖蓝B = 淡浅绿4 = 红 C = 淡红5 = 紫 D = 淡紫6 = 黄 E = 淡黄7 = 白 F = 亮白*///设置接下来终端显示文本的背景色和文本颜色void SetText_Color(int color){HANDLE hStdout;hStdout = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleTextAttribute(hStdout,color);}void message_song1(char song[4][100])//切割前四行{int i;char delims[]="[:]";char *result=NULL;char *sign[4]={"歌名","歌手","制作","专辑"};for(i=0;i<4;i++){strtok(song[i],delims);result= strtok(NULL,delims);printf("%s %s\n",sign[i],result);}printf("\n\n");}void message_song2(char song1[100][100],char time[100][100] ,char lyric[100][100] )//切割歌词和时间{int i,j,k1=0,k2=0,min=0,tsec=0,gsec=0,b=6;int flag=0,m=5;char delims1[]="[]";char *result1=NULL;for(j=0;song1[j][0]!='\0';j++){result1=strtok(song1[j],delims1);for(i=0;result1!=NULL;i++){if(i%2==0){strcpy(time[k1],result1);result1=strtok(NULL,delims1);k1++;}if(i%2==1){strcpy(lyric[k2],result1);result1=strtok(NULL,delims1);k2++;}}}j=0;for(i=0;;i++){GoToXY(22,5);printf("The time is:0%d:%d%d ",min,tsec,gsec); Sleep(1000);gsec++;if(gsec==10){tsec++;gsec=0;}if(tsec==6){min++;tsec=0;}for(j=0;j<50;j++){if((min==time[j][1]-48)&&(tsec==time[j][3]-48)&&(gsec==time[j][4]-48)){if(m<10) m+=1;else m=10;GoToXY(22,m);SetText_Color(2);printf("%s\t\t\t\t\n",lyric[j-1]);GoToXY(22,m-1);SetText_Color(7);printf("%s\t\t\t\t\n",lyric[j-2]);flag++;if(flag>=5)MoveText(22,6,20,5,22,5);}}}}void main(){FILE*fp;int i=0;char time[100][100]={0};char lyric[100][100]={0};charinfile[1000]={0},song_word[100][100]={0},song_word1[100][100]={0};char *result=NULL;char delims1[]="\n";ShellExecute( NULL, NULL, "TTPlayer.exe","spring.mp3",NULL,1); //执行千千静听if((fp=fopen("spring.lrc","rb"))==NULL){printf("can not open file\n");exit(0);}while(!feof(fp)){infile[i]=fgetc(fp);i++;}infile[i]='\0';fclose(fp);printf("\n");result=strtok(infile,delims1);for(i=0;result!=NULL;i++){strcpy(song_word[i],result);result++;result=strtok(NULL,delims1);}for(i=0;i<44;i++)strcpy(song_word1[i],song_word[i+4]);message_song1(song_word);message_song2(song_word1,time,lyric);}bug调试:刚开始对切割函数strtok含有多个标识符的使用理解不透彻,经过多次改变标识符观察输出结果,也就正确理解了。
lrc使用指南

lrc使用指南(实用版)目录1.LRC 文件概述2.LRC 文件的结构3.LRC 文件的编写方法4.LRC 文件的应用场景5.LRC 文件的优缺点正文【LRC 文件概述】LRC(Lyric Repository Configuration)文件是一种用于存储歌词信息的文本文件,通常与音乐文件(如 MP3、WAV 等)配套使用。
LRC 文件的主要功能是为音乐文件提供同步歌词显示,使用户在播放音乐时能够方便地查看和跟随歌词。
【LRC 文件的结构】一个 LRC 文件主要包括以下几个部分:1.文件头:包括文件的唯一标识符、版本号、字符编码等基本信息。
2.歌词块:每个歌词块包含了一行或多行歌词,以及与音乐文件对应的时间戳。
每行歌词由一个或多个单词组成,单词之间用空格分隔。
歌词块的格式为“[行号:时间戳:歌词内容]”,如“[00:00:00] 歌手 - 歌曲名 [00:00:00] 第一句歌词 [00:00:00] 第二句歌词”。
3.标签:LRC 文件支持多种标签,如歌手、专辑、风格等。
标签位于歌词块之前,用中括号 [] 包围,如“[歌手]”、“[专辑]”等。
【LRC 文件的编写方法】编写 LRC 文件可以采用文本编辑器,如 Notepad、Sublime Text 等。
以下是一个简单的 LRC 文件编写步骤:1.新建一个文本文件,并将其命名为“歌曲名.lrc”。
2.在文件中输入文件头信息,如“[lyric-file-name:M3UA:1.0]”。
3.编写歌词块,按照歌词的顺序和时间戳进行排列。
每个歌词块之间用空行分隔。
4.如果需要添加标签,将标签放在对应的歌词块之前。
5.保存文件,并将其与音乐文件放在同一目录下。
【LRC 文件的应用场景】LRC 文件广泛应用于音乐播放器、在线音乐平台等场景。
用户在播放音乐时,可以通过 LRC 文件查看同步歌词,提高音乐体验。
此外,LRC 文件也可以用于歌词共享、歌词制作等领域。
LRC歌词编辑攻略

LRC歌词编辑攻略一、相关概念:1.LRC歌词格式LRC 歌词是一种包含着“[*:*]”形式的“标签(tag)”的、基于纯文本的歌词专用格式。
最早由郭祥祥先生(Djohan)提出并在其程序中得到应用。
这种歌词文件既可以用来实现卡拉OK功能(需要专门程序),又能以普通的文字处理软件查看、编辑。
当然,实际操作时通常是用专门的LRC歌词编辑软件进行高效编辑的。
以下具体介绍LRC格式中的“标签”。
2.时间标签(Time-tag)形式为“[mm:ss]”或“[mm:ss.fff]”(分钟数:秒数)。
数字须为非负整数,比如“[12:34.5]”是有效的,而“[0x0C:-34.5]”无效。
它可以位于某行歌词中的任意位置。
一行歌词可以包含多个时间标签(比如歌词中的迭句部分)。
根据这些时间标签,用户端程序会按顺序依次高亮显示歌词,从而实现卡拉OK功能。
另外,标签无须排序。
3.标识标签(ID-tags)其格式为“[标识名:值]”。
大小写等价。
以下是预定义的标签。
[ar:艺人名][ti:曲名][al:专辑名][by:编者(指编辑LRC歌词的人)][offset:时间补偿值] 其单位是毫秒,正值表示整体提前,负值相反。
这是用于总体调整显示快慢的样例[ar:陈明][ti:《快乐老家》][al:娱乐天地][by:truly][01:02.355][00:00]This line should be sung twice[00:05.7]And this one... once only.4.LYR文件格式LYR 文件是自行定义的一种同步文件格式。
采用相同的文件名称来实现歌词同步,如:同时下载《快乐老家》.mp3 和《快乐老家》.lyr两个文件到MP3播放机中即可实现同步。
LYR文件可使用歌词编辑软件编辑的TLY文件或LRC文件转化而来。
5.LYR 使用注意事项:∙LYR 必须与待同步MP3使用相同的文件名∙LYR 与MP3的文件名称尽量控制在8个字节(即4汉字或者8个英文字符)。
歌词制作(lrc krc)全解

我到论坛来看了一下,有很多人问krc歌词怎么做呀?还有人问谁有krc歌词的教程和副本吗?也有人说各位大神谁会制作歌词,教教我?
我也真服了你们,所以,我就写了这些来喂你们这些可怜的毛毛虫。人家花了半个晚上睡觉的时间,早上起来脸上都长了两颗圆圆的痘痘,你们要对我负责啊!(开玩笑)
现在我们来看看krc格式的歌词制作方法。
首先,我需要制作歌词的软件来帮助我。
制作软件:酷狗(电脑版)
(其实,我也希望手机能制作krc格式的歌词,因为我是手机控嘛,电脑不方便呀)
酷狗音乐,是大家非常常用的音乐播放器和音乐下载器,也是很多制作爱好者的歌词制作器。
这个制作krc格式的歌词,说来也简单(至少比lrc格式的歌词简单)。前面说到了酷狗音乐,一定是有用的,现在我就教大家用酷狗音乐制作krc格式的歌词。
......不不不是,是你们要对我的痘痘负责啊!(这个不是开玩笑的,我真的长红痘痘了啊,十几天才好了呢)
要是你们会了,不谢我的话,我就将他(不包括她)
碎~~尸~~万~~断~~ 哈哈哈哈
呵呵,吓着了吧?
[03:31.23]我 因為瞭解才分開
[03:35.84]甜蜜不能夠倒帶 怎麼重來
[03:41.38]是我辜負了妳的存在
[03:49.99]
[03:50.00]最新最好聽的傷感流行音樂與你共分享
如果你制作完成了,可以自己拿来先用一下,自己觉得还可以。你就可以通过USB或U盘上传到电脑,利用电脑的网络上传到各个通用的音乐播放器,别人将可以从你上传过的那个音乐播放器下载你上传的歌词。
[02:47.81]心疼妳為我等待 選擇離開
[02:53.47]是我一個人的悲哀
[02:57.92]我 因為瞭解才分開
LRC歌词格式简介

LRC歌词格式简介
扩展名lrc的文件,是MP3播放器唯一能够识别的歌词文件。
在MP3数码播放器或千千静听中可以同步显示歌词。
lrc歌词下载到本地电脑后用“记事本”打开。
lrc歌词文本中含有两类标签:
一、标识标签其格式为“[标识名:值]”
[ar:歌手名]-artist艺术家、演唱者
[ti:歌曲名]-title题目,标题,曲目
[al:专辑名]-album唱片集、专辑
[by:编辑者]-(介词)制作者、编辑人员(一般指lrc歌词的制作人) [offset:时间补偿值]-其单位是毫秒,正值表示延迟,负值表示提前。
用于整体调整歌词显示慢(快)于音乐播放。
二时间标签,格式为“[mm:ss]”或“[mm:ss.fff]”
[mm:ss]-分钟数:秒数
[mm:ss.fff]-分钟数:秒数.毫秒数
时间标签位于某行歌词中的句首部分,一行歌词可以包含多个时间标签(比如歌词中的重迭句部分)。
三、lrc歌词实例
[ar:蔡琴]
[ti:绿岛小夜曲]
[al:蔡琴不了情2007经典歌曲香港演唱会]
[by:william王子]
[02:53.84][00:07.74]蔡琴不了情2007经典歌曲香港演唱会
[01:53.72][00:01.28]蔡琴-绿岛小夜曲
[01:58.23][00:12.85]
[00:14.66]这绿岛像一只船
[00:20.88]在月夜里摇啊摇
......。
MPC LRC歌词播放源码

}
else
return -1;
dtxt("停止");
return 0;
}
void IsBegin(int data) ห้องสมุดไป่ตู้
{
if(LrcHead!=NULL)
{
LrcState=LRC_PLAY;
}
LrcNow=P;
}
LrcResume();
}
}
void LrcLoading(int data)
{
char line[255], *ptr=line, *endline;
int32 is_over=FALSE, linelen;
LrcTemp=LrcFileBuf;
LrcFree();
timerstart(LrcTimer.h1, 10, 0, "LrcLoading", 1); //歌词处理
close(fp);
}
else
return -1;
LrcNow=LrcHead;
timerstart(LrcTimer.h2, 50, 0, "LrcCurCB", 1);
}
}
void LrcCurCB(int data)
{
i=CurTimems()/100;
if(LrcNow->time <= i)
typedef struct
{
int32 h1;
int32 h2;
int32 h3;
} lrctimerst;
lrctimerst LrcTimer; //Lrc处理定时器
C语言实现歌曲信息管理系统

C语言实现歌曲信息管理系统这篇文章主要为大家详细介绍了C语言实现歌曲信息管理系统,具有一定的参考价值,感兴趣的小伙伴们可以参考一下:系统功能:该系统以菜单方式工作,歌曲信息包括:歌名、演唱者、作词、作曲、所属专辑、出版时间、出版公司。
试设计一歌厅歌曲管理系统,使之能提供以下功能:歌曲信息录入、修改、插入、删除功能;歌曲排序浏览功能;按歌名查询、按演唱者查询等功能。
完整的实现代码如下:#include "stdio.h"#include "stdlib.h"#include "string.h"//歌曲信息包括:歌名、演唱者、作词、作曲、所属专辑、出版时间、出版公司typedef struct music{char name[20]; //歌名char singer[20]; //演唱者char authors[20]; //作词char compose[30]; //作曲char album[20]; //所属专辑char time[15]; //出版时间char company[30]; //出版公司struct music *next;}music;music *head=NULL;int length; //链表的长度void create(){music *p1,*p2;length=0;p1=(music *)malloc(sizeof(music));strcpy(p1->name,"-1");if(head==NULL)head=p1;printf("请输入音乐的歌名、演唱者、作词、作曲、所属专辑、出版时间、出版公司:/n"); while(1) //歌名为0的时候退出{p2=(music *)malloc(sizeof(music));//输入歌曲信息scanf("%s %s %s %s %s %s %s",p2->name,p2->singer,p2->authors,p2->compose,p2->album,p2->ti me,p2->company);if(strcmp(p2->name,"0")==0){printf("链表创建完成!/n");break;}length++; //链表的长度p1->next=p2;p2->next=NULL;p1=p1->next;}return ;}void ModifymusicInfo(){music *p=head->next;char name[20];printf("请输入要修改的歌曲的歌名:");getchar();scanf("%s",name);while(p!=NULL){if(strcmp(p->name,name)==0){printf("修改前,歌名为%s的歌曲的信息如下:/n",name);printf("音乐的歌名、演唱者、作词、作曲、所属专辑、出版时间、出版公司:/n");printf("%s %s %s %s %s %s %s/n",p->name,p->singer,p->authors,p->compose,p->album,p->time,p ->company);printf("请输入歌曲的新的所属专辑:");getchar();scanf("%s",p->album);printf("请输入歌曲的新出版公司:");getchar();scanf("%s",p->company);printf("修改后,歌名为%s的歌曲的信息如下:/n",name);printf("音乐的歌名、演唱者、作词、作曲、所属专辑、出版时间、出版公司:/n");printf("%s %s %s %s %s %s %s/n",p->name,p->singer,p->authors,p->compose,p->album,p->time,p ->company);return ;}p=p->next;}if(p==NULL){printf("该歌曲不存在!/n");return ;}}void display(){music *p=head->next;printf("链表中所有的歌曲信息如下:/n");printf("音乐的歌名、演唱者、作词、作曲、所属专辑、出版时间、出版公司:/n"); while(p!=NULL){printf("%s %s %s %s %s %s %s/n",p->name,p->singer,p->authors,p->compose,p->album,p->time,p ->company);p=p->next;}return ;}void search(){int num,x,flag;char name[20];music *p=head->next;printf("请选择查询的方式:/n");printf("1、按歌名查询/t 2、按演唱者查询/n");scanf("%d",&x);if(x==1){printf("需要查找的歌曲歌名为:");getchar();scanf("%s",name);while(p!=NULL){if(strcmp(p->name,name)==0){printf("歌名为%s的歌曲的信息如下:/n",name);printf("音乐的歌名、演唱者、作词、作曲、所属专辑、出版时间、出版公司:/n");printf("%s %s %s %s %s %s %s/n",p->name,p->singer,p->authors,p->compose,p->album,p->time,p ->company);return ;}p=p->next;}if(p==NULL)printf("没有这首歌曲的记录!/n");}else if(x==2){flag=0;printf("需要查找的演唱者为:");getchar();scanf("%s",name);p=head->next;while(p!=NULL){if(strcmp(p->singer,name)==0){if(flag==0){printf("演唱者为%s的歌曲的信息如下:/n",name);printf("音乐的歌名、演唱者、作词、作曲、所属专辑、出版时间、出版公司:/n");flag=1;}printf("%s %s %s %s %s %s %s/n",p->name,p->singer,p->authors,p->compose,p->album,p->time,p ->company);}p=p->next;}if(p==NULL && flag==0){printf("没有该演唱者的歌曲记录!/n");return;}}return ;}void insert(){int num,i;music *p,*q;p=head;printf("请输入你要插入位置: ");scanf("%d",&num);if(num>length){printf("找不到要插入的位置/n");return ;}else{printf("请输入你要插入的音乐的歌名、演唱者、作词、作曲、所属专辑、出版时间、出版公司:/n");q=(music *)malloc(sizeof(music));//输入歌曲信息scanf("%s %s %s %s %s %s %s",q->name,q->singer,q->authors,q->compose,q->album,q->time,q-> company);while(p!=NULL){if(strcmp(p->name,q->name)==0){printf("该歌曲已经存在,无法插入!/n");return ;}p=p->next;}p=head;for(i=0;i<num;i++)p=p->next;q->next=p->next;p->next=q;length++;printf("插入成功!/n");return ;}}void Delete(){char name[20];music *p,*q;q=head,p=head->next;printf("请输入要删除的歌曲的歌名:/n");getchar();scanf("%s",name);while(p!=NULL){if(strcmp(p->name,name)==0){q->next=p->next;free(p);length--;printf("删除成功!/n");return ;}p=p->next;q=q->next;}if(p==NULL){printf("找不到要删除的歌曲!/n");return ;}}void menu(){printf("________________________________________________________________/n"); printf("| 歌厅歌曲管理系统|/n");printf("| 0、退出系统|/n");printf("| 1、录入歌曲信息|/n");printf("| 2、显示歌曲信息|/n");printf("| 3、查找链表中的某一首歌曲|/n");printf("| 4、删除链表中指定歌曲|/n");printf("| 5、指定的位置上插入一个新结点|/n");printf("| 6、修改歌曲信息|/n");printf("________________________________________________________________/n"); return ;}int main(void){int a;menu();while(1){printf("请选择相应的功能:");scanf("%d",&a);switch(a){case 0:case 1:create();menu();break;case 2:if(head){display();menu();}else{printf("链表为空,请先建立链表!/n");menu();}break;case 3:if(head){search();menu();}else{printf("链表为空,请先建立链表!/n");menu();}break;case 4:if(head){Delete();menu();}else{printf("链表为空,请先建立链表!/n");menu();}break;case 5:if(head){menu();}else{printf("链表为空,请先建立链表!/n");menu();}break;case 6:if(head){ModifymusicInfo();menu();}else{printf("链表为空,请先建立链表!/n");menu();}break;default:break;}}system("pause");return 0;}。
LRC校验算法C语言程序

LRC校验算法C语言程序序言近日用到关于LRC检验算法,网上找了很多资料,其描述方式实在不敢恭维,为方便使用者特写下详细的计算过程,希望对你有所帮助。
By 厦大Jacky 20120814LRC校验的数据发送格式起始字符(1个字符)+数据(2n个字符)+校验值(2个字符)+结束字符(2个:回车+换行)。
LRC校验值计算数据(2n个字符)两两组成一个16进制的数值,然后将这些数值相加,将所得加值与256求模,然后用256减去所得模值,得到的数值即为检验值(即:sum%256后取反,再加1)。
范例发送数值:01050BE7FF0009数值分析:-- 起始字符;01050BE7FF00 -- 数据值;09 -- 检验值;其后还有回车换行(未标出)。
数据值拆分:010********* -->0x01 0x05 0x0B 0xE7 0xFF 0x00 求和:0x01+0x05+0x0B+0xE7+0xFF+0x00 =0x01F7;取模,取反:0x1F7%0x100=0xF7 0xF7 取反0x08加1:0x08+1=0x09 (校验值)C语言算法:uchar data[17]={0x3a,0x30,0x31,0x30,0x35,0x00,0x00,0x00,0x00,//no0x00,0x00,0x00,0x00,//status0x00,0x00, //LRCData0x0d,0x0a};//******************************************************* ************************// 语法格式:uchar LRC_Check(uchar *data,uchar length);// 实现功能:LRC数据检测算法程序// 参数:无// 返回值:LRC检验值//******************************************uchar LRC_Check(uchar *data,uchar length){uchar i;uint k;uchar result;uchar lrcdata[length];for(i=1;i<length+1;i++){if(data[i]>0x40)lrcdata[i-1]=data[i]-0x41+10;elselrcdata[i-1]=data[i]-0x30;}k=0;for(i=0;i<length/2;i++){k+=(lrcdata[2*i]*16+lrcdata[2*i+1]);}k=k%256;k=256-k;result=k%256;return result;}。
lrc歌词读取和排序算法 (1)

LRC歌词读取和排序算法已有 14280 次阅读2008-6-5 15:41代码写了其实挺久了,现在突然想起来,鼓励自己下下,呵呵代码是为了给SPCE3200做一个微型mp3播放器而做的。
界面仿千千静听,使用软件解码器解mp3,滚动条、文件列表,基本功能差不多都有了,后来突然想到为它增加歌词显示,这样才算比较完整。
所以就开始要写lrc的解释程序了。
之前对lrc有一点了解,知道它最主要的就是用时间标签表达每一句歌词需要显示的时间。
所以,lrc解释程序的最主要任务就是分析时间标签,然后将实际的歌词拿出来~~~看代码吧:#include <string.h>#include "lrc.h"#define isnumeric(a) (((a >= '0') && (a <= '9')) ? 1 : 0)void CopyLrcInfo(LRC_INFO *DstInfo, LRC_INFO *SrcInfo){DstInfo->Time = SrcInfo->Time;DstInfo->Prev = SrcInfo->Prev;DstInfo->Next = SrcInfo->Next;strcpy(DstInfo->LrcText, SrcInfo->LrcText);}LRC_INFO *GetFirstOfList(LRC_QUEUE *List){return &List->List[List->First];}u16_t InsertList(LRC_QUEUE *List, u32_t Time, char LrcText[]) {int InsertPos = -1;u16_t i;LRC_INFO *lp = &List->List[List->Last];if(List->Length == 0){List->List[0].Time = Time;strcpy(List->List[0].LrcText, LrcText);List->List[0].Prev = (void*)0;List->List[0].Next = (void*)0;List->First = 0;List->Last = 0;List->Length = 1;InsertPos = 0;}else{for(i = List->Length; i != 0; i--){if(lp->Time <= Time){if(i == List->Length){List->Last = List->Length;lp->Next = &List->List[List->Length];List->List[List->Length].Prev = lp;List->List[List->Length].Next = (void*)0;// List->First = List->Length;// lp->Prev = &List->List[List->Length];// List->List[List->Length].Prev = (void*)0;// List->List[List->Length].Next = lp;}else{LRC_INFO *temp = lp->Next;lp->Next = &List->List[List->Length];List->List[List->Length].Prev = lp;List->List[List->Length].Next = temp;temp->Prev = &List->List[List->Length];}List->List[List->Length].Time = Time;strcpy(List->List[List->Length].LrcText, LrcText);InsertPos = (List->Length = List->Length + 1);break;}else if(i == 1){List->First = List->Length;lp->Prev = &List->List[List->Length];List->List[List->Length].Prev = (void*)0;List->List[List->Length].Next = lp;List->List[List->Length].Time = Time;strcpy(List->List[List->Length].LrcText, LrcText);InsertPos = (List->Length = List->Length + 1);// List->Last = List->Length;// lp->Next = &List->List[List->Length];// List->List[List->Length].Prev = lp;// List->List[List->Length].Next = (void*)0;// List->List[List->Length].Time = Time;// strcpy(List->List[List->Length].LrcText, LrcText); // InsertPos = (List->Length = List->Length + 1);}lp = lp->Prev;}}return InsertPos;}u32_t GetLrcInfo(char *LrcFile, u32_t FileSize, LRC_QUEUE *List) {s32_t ōffsetTime = 0;u32_t CurOffset = 0;u32_t CurTime = 0;u32_t TempOffset;int Flag = 0;memset(List, 0, sizeof(*List));// List->Length = 0;// List->First = 0;// List->Last = 0;// List->List[0].Prev = (void*)0;// List->List[0].Next = (void*)0;do {if(LrcFile[CurOffset++] == '['){if(Flag == 0)if(strncmp(&LrcFile[CurOffset], "offset:", 7) == 0){CurOffset += 7;if(LrcFile[CurOffset] == '-'){Flag = -1;}elseFlag = 1;while(LrcFile[CurOffset] != ']'){OffsetTime *= 10;OffsetTime += LrcFile[CurOffset++] - '0';}OffsetTime = OffsetTime / 10 * Flag;}if(isnumeric(LrcFile[CurOffset])){char *lrc;Flag = 1;CurTime = (((LrcFile[CurOffset] - '0') * 10 + (LrcFile[CurOffset + 1] - '0')) * 60 +((LrcFile[CurOffset + 3] - '0') * 10 + LrcFile[CurOffset + 4] - '0')) * 100;CurOffset += 5;if(LrcFile[CurOffset] == '.'){CurTime += (LrcFile[CurOffset + 1] - '0') * 10 + LrcFile[CurOffset + 2] - '0';}CurOffset++;TempOffset = CurOffset;while((LrcFile[TempOffset] == '[') && isnumeric(LrcFile[TempOffset + 1])){while((LrcFile[TempOffset] != ']') && (TempOffset < FileSize))TempOffset++;TempOffset++;}lrc = &LrcFile[TempOffset];while((LrcFile[TempOffset] != 0x0d) && (LrcFile[TempOffset] != 0x0a) && (TempOffset < FileSize))TempOffset++;LrcFile[TempOffset] = '\0';InsertList(List, CurTime + OffsetTime, lrc);}// else// {// while(LrcFile[CurOffset++] != ']');// }}} while(CurOffset < FileSize);return 0;}头文件:#ifndef __LRC_H__#define __LRC_H__#define MAX_LINE 128#define MAX_LINE_LEN 255typedef int s32_t;typedef unsigned int u32_t;typedef unsigned short u16_t;typedef unsigned char u8_t;typedef struct _LRC_INFO {u32_t Time;char LrcText[MAX_LINE_LEN];struct _LRC_INFO *Prev;struct _LRC_INFO *Next;} LRC_INFO;typedef struct {LRC_INFO List[MAX_LINE];u16_t Length;u16_t First;u16_t Last;} LRC_QUEUE;u32_t GetLrcInfo(char *LrcFile, u32_t FileSize, LRC_QUEUE *List);LRC_INFO *GetFirstOfList(LRC_QUEUE *List);#endif代码主体部分用来从lrc数据的开头开始解析时间标签,检测到一个标签就将对应的歌词提取出来,并放入一个链表中。
Lrc歌词文件格式及其C++代码实现

Lrc歌词文件格式说明扩展名为Lrc格式的文件,是MP3播放器唯一能够识别的歌词文件,在MP3数码播放器或千千静听中可以区同步显示歌词。
它是一种包含着“[*:*]”形式的“标签(tag)”的、基于纯文本的歌词专用格式。
最早由郭祥祥先生(Djohan)提出并在其程序中得到应用。
这种歌词文件既可以用来实现卡拉OK 功能(需要专门程序),又能以普通的文字处理软件查看、编辑。
当然,实际操作时通常是用专门的LRC歌词编辑软件进行高效编辑的。
Lrc歌词文本中含有两类标签:一是标识标签,其格式为“[标识名:值]”主要包含以下预定义的标签:[ar:歌手名]、[ti:歌曲名]、[al:专辑名]、[by:编辑者(指lrc歌词的制作人)]、[offset:时间补偿值] (其单位是毫秒,正值表示整体提前,负值相反。
这是用于总体调整显示快慢的,但多数的MP3可能不会支持这种标签)。
二是时间标签,形式为“[mm:ss]”或“[mm:ss.fff]”(分钟数:秒数:毫秒数),时间标签需位于某行歌词中的句首部分,一行歌词可以包含多个时间标签(比如歌词中的迭句部分)。
当歌曲播放到达某一时间点时,MP3就会寻找对应的时间标签并显示标签后面的歌词文本,这样就完成了“歌词同步”的功能。
■时间标签(Time-tag)形式为"[mm:ss]"或"[mm:ss.fff]"(分钟数:秒数)。
数字须为非负整数,比如"[12:34.5]"是有效的,而"[0x0C:-34.5]"无效。
它可以位于某行歌词中的任意位置。
一行歌词可以包含多个时间标签(比如歌词中的迭句部分)。
根据这些时间标签,用户端程序会按顺序依次高亮显示歌词,从而实现卡拉OK 功能。
另外,标签无须排序。
■标识标签(ID-tags)其格式为"[标识名:值]"。
大小写等价。
以下是预定义的标签。
用于读取LRC同步歌词的类

用于读取LRC同步歌词的类用于读取LRC同步歌词的类今天心情不错,用FLASH写了一个用于读取LRC同步歌词的类,只要25行代码,完全用是用FLASH的字符串操作来分析标签的.。
下面就是这个类:package LRC{public class readlrc {public function readlrcastime(mp3playtime:Number,gc:String):String { var qsd:int;//起始点var fhz:String;for (var j:int=0; j < gc.length; j ) {if (gc.charCodeAt(j) == 58) {if (int(gc.slice(j - 2,j)) * 60 int(gc.slice(j 1,j 3)) == mp3playtime) {var i:int=0;do {i ;if (gc.charCodeAt(j i) == 93) {qsd=j i;}if (gc.charCodeAt(j i) == 13) {fhz=gc.slice(qsd 1,j i);}} while (gc.charCodeAt(j i) != 13&&j i<gc.length);}}}return fhz;}}}将此文件保存为readlrc.as。
注意:一定要把此AS文件放入一个名为LRC的文件夹中,才可以使用。
下面就用一个小示例来说明如何用这个类,新建一个AS文件,写入以下代码:package {import flash.display.MovieClip;import flash.events.Event;import .URLLoader;import .URLRequest;import flash.media.Sound;import flash.media.SoundChannel;import flash.system.System;import flash.text.T extField;import LRC.readlrc;public class mp3 extends MovieClip {private var lrcreq:URLRequest=new URLRequest("日不落.lrc");private var mp3url:URLRequest=new URLRequest("日不落.mp3");private var mymp3:Sound=new Sound();private var channel:SoundChannel=new SoundChannel();private var lrcurl:URLLoader=new URLLoader();private var tbgc:String;private var mylrc:readlrc=new readlrc();eCodePage=true;public function mp3() {mymp3.load(mp3url);channel=mymp3.play();lrcurl.load(lrcreq);lrcurl.addEventListener(PLETE,loaded);}private function enterframe(event:Event) {try {gc_txt.text=mylrc.readlrcastime(int(channel.position/1000),t bgc);} catch (error:Error) {//}}private function loaded(event:Event) {tbgc=String(event.target.data);addEventListener(Event.ENTER_FRAME,enterframe);}}}保存此文件为mp3.as。
c#歌词同步

C# 歌词同步可以桌面字幕透明显示,这个前一篇说过同步就是判断歌曲当前播放时间去匹配歌词文件里的时间段标志。
很简单的,当然你还可以自动下载歌曲的歌词并同步。
FormLrc 是显示歌词的窗体:using System.IO;using System.Text.RegularExpressions;using System.Collections;namespace MyPlayer{public partial class FormLrc : Form{public FormLrc(){TimerLrc2.Interval = 60;TimerLrc2.Tick += new EventHandler(TimerLrc2_Tick);InitializeComponent();this.DoubleBuffered = true;this.TopMost = true;timerMask.Tick += new EventHandler(timerMask_Tick);timerLrc.Tick += new EventHandler(timerLrc_Tick);timerLrc.Interval = 100;timerMask.Interval = 200;InitializeComponent();timerMask.Enabled = true;}/// <summary>/// 结构体/// </summary>struct Lrc{public Lrc(string _sTime, string _sText){sTime = _sTime;sText = _sText;}public string sTime;public string sText;public override string ToString(){return sTime + sText;}}System.Windows.Forms.Timer TimerLrc2 = new Timer(); ArrayList LrcList = new ArrayList();string sFile = "刘德华- 冰雨.lrc";string sOut = "";string sText = "";DateTime LrcTime = new DateTime();Graphics g;Bitmap bmp = new Bitmap(1024, 500);Bitmap bmpMask = new Bitmap(1024, 500);Graphics BmpG;Graphics MaskGr;Point p = new Point(2, 2);Point p1 = new Point(4, 4);Point p2 = new Point(3, 3);Brush b = new SolidBrush(Color.Red);Brush bMask = new SolidBrush(Color.Yellow);// mask color Brush b2 = new SolidBrush(Color.FromArgb(11, 211, 1, 1));//Font f = new Font("Times New Roman", 44, FontStyle.Bold); Font f = new Font("宋体", 44, FontStyle.Bold);Font f2 = new Font("宋体", 44, FontStyle.Bold);Color transColor = new Color();MemoryStream ms = new MemoryStream();int TextIndex = 0; //ths need mask text indexSystem.Windows.Forms.Timer timerMask = new Timer(); System.Windows.Forms.Timer timerLrc = new Timer();public static string SongCurrentTime = "00:00.00";private void FormTest_Load(object sender, EventArgs e) {this.Size = Screen.PrimaryScreen.Bounds.Size;//LoadLrc("刘德华- 冰雨.lrc");}public void LoadLrc(string _sFile){OpenFile(_sFile);TimerLrc2.Enabled = true;// StartShowLrc("刘德华- 冰雨.lrc");}private void button1_Click(object sender, EventArgs e) {timerMask.Enabled = false;richTextBox1.T ext = sText;panel1.Visible = true;// timerMask.Enabled = (!timerMask.Enabled); }protected override void OnPaint(PaintEventArgs e){// if (sText == "") { return; }g = e.Graphics;bmp = new Bitmap(1024, 500); ;//reset imagebmpMask = new Bitmap(1024, 124);// ms = new MemoryStream();//resetBmpG = Graphics.FromImage(bmp);transColor = bmp.GetPixel(1, 1);this.TransparencyKey = transColor;g.Clear(transColor);//g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;//g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;//BmpG.TextRenderingHint = System.Drawing.Text.T extRenderingHint.AntiAliasGridFit;g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;BmpG.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;BmpG.DrawString(sText, f2, b2, p1);BmpG.DrawString(sText, f, b2, p2);BmpG.DrawString(sText, f, b, p);//Masktry{BmpG.DrawString(sText.Substring(0, TextIndex), f2, bMask, p);// MaskGr.DrawString(sText.Substring(0, TextIndex), f, b2, p);}catch (Exception ex) { }bmp.MakeTransparent(Color.White);// bmp.Save(ms, ImageFormat.Bmp);g.DrawImage(bmp, p);// g.DrawImage(bmp, p);//this.BackgroundImage =(Image) bmp;//pictureBox1.Image = bmp;sOut += "Paint \r\n";// base.OnPaint(e);// BmpG.Dispose();}protected override void OnPaintBackground(PaintEventArgs e){// e.Graphics.DrawString("wgscd 的说法的", f, b, p);//this.TransparencyKey = transColor;sOut += "Back Paint\r\n";base.OnPaintBackground(e);}private void FormTest_Click(object sender, EventArgs e){}#region "拖动窗体"private bool moveFlag = false;private int x = 0;private int y = 0;protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e) {if (moveFlag && (e.Button == MouseButtons.Left))this.SetBounds(Left + e.X - x, Top + e.Y - y, this.Width, this.Height);base.OnMouseMove(e);}protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e) {if (!moveFlag && e.Clicks >= 1)moveFlag = true;x = e.X;y = e.Y;base.OnMouseDown(e);}protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e) {if (moveFlag)moveFlag = false;base.OnMouseUp(e);}#endregionvoid timerMask_Tick(object sender, EventArgs e){// if (sText.Trim() == "") { return; };this.Refresh();TextIndex++;if (TextIndex > sText.Length){TextIndex = 0;}}void timerLrc_Tick(object sender, EventArgs e){//LrcTime = new DateTime(2009, 10, 10, 0, 0, 0, 0);//if (TextIndex > sText.Length)//{// TextIndex = 0;//}}private void button2_Click(object sender, EventArgs e) {if (richTextBox1.Text.Trim() == "") { return; }sText = richTextBox1.Text;panel1.Visible = false;timerMask.Enabled = true;}/// <summary>//////读取歌词/// </summary>void OpenFile(string _strFile){if (!File.Exists(_strFile)){MessageBox.Show("File not fount");return;}string sContent = "";Stream oStream = null;StreamReader oReader = null;string AllLines = "";string oneLine = "";try{oStream = File.Open(_strFile, FileMode.OpenOrCreate, FileAccess.ReadWrite);oReader = new StreamReader(oStream, Encoding.GetEncoding("gb2312"));LrcList.Clear();while (!oReader.EndOfStream){oneLine = oReader.ReadLine() + "\r\n";AllLines += oneLine;regLrc(oneLine);}oReader.Close();oStream.Close();}catch (Exception ex){oReader.Close();oStream.Close();}richTextBox1.AppendText(AllLines);}/// <summary>/// match the lrcs all lines in to lrc list/// </summary>/// <param name="strInput"></param>/// <returns></returns>string regLrc(string strInput){//string sPattner="(?<t>\\[\\d[^[]+])(?<w>.*\r\n)";string sPattner = "(?<t>\\[\\d.*\\]+)(?<w>[^\\[]+\r\n)";Regex reg = new Regex(sPattner);foreach (Match mc in reg.Matches(strInput)){richTextBox1.AppendText(mc.Groups["t"].ToString() + "\r\n");richTextBox1.AppendText(mc.Value + "\r\n");LrcList.Add(new Lrc(mc.Groups["t"].ToString(), mc.Groups["w"].ToString()));}return "";}/// <summary>/// 通过时间找歌词/// </summary>/// <param name="_sTime"></param>/// <returns></returns>string m = "";Lrc findMatch = new Lrc();public string FindLrc(string _sTime){foreach (Lrc w in LrcList){// MessageBox.Show(w.ToString());if (w.sTime.Contains(_sTime.Substring(0, 6))){if (findMatch.Equals(w)) return "";findMatch = w;sText = w.sText;m += w.sText;return w.sText;}}return "";}private void showWord(object sender, EventArgs e){//[03:26.03][02:50.67][01:16.59]冷冷的冰雨在脸上胡乱的拍// FindLrc2("[02:50.67]");MessageBox.Show(m);}DateTime d1 = new DateTime(1900, 1, 1, 0, 0, 0, 0);DateTime d2;DateTime d3;TimeSpan tsp;string tTime;public void TimerLrc2_Tick(object sender, EventArgs e){FindLrc(ClassCommon.SongCrrentTime);return;//if (sText.Trim() == "") { return; };d2 = DateTime.Now;if (d1.Year == 1900)d1 = d2;return;}TimerLrc2.Enabled = false;tsp = (TimeSpan)(d2 - d1);d3 = new DateTime(1900, 1, 1, 0, tsp.Minutes, tsp.Seconds, liseconds);tTime = d3.ToString("[mm:ss.ff]");ClassCommon.SongCrrentTime = tTime;FindLrc(tTime);this.Text = tTime;TimerLrc2.Enabled = true;}}}FormLrc 界面类(FormLrc.Designer.cs):namespace MyPlayer{partial class FormLrc{/// <summary>/// Required designer variable./// </summary>private ponentModel.IContainer components = null;/// <summary>/// Clean up any resources being used./// </summary>/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>protected override void Dispose(bool disposing){if (disposing && (components != null)){components.Dispose();base.Dispose(disposing);}#region Windows Form Designer generated code/// <summary>/// Required method for Designer support - do not modify/// the contents of this method with the code editor./// </summary>private void InitializeComponent(){this.button1 = new System.Windows.Forms.Button();this.panel1 = new System.Windows.Forms.Panel();this.button2 = new System.Windows.Forms.Button();this.richTextBox1 = new System.Windows.Forms.RichTextBox();this.panel1.SuspendLayout();this.SuspendLayout();//// button1//this.button1.ForeColor = System.Drawing.SystemColors.HotTrack;this.button1.Location = new System.Drawing.Point(292, 169); = "button1";this.button1.Size = new System.Drawing.Size(169, 62);this.button1.TabIndex = 1;this.button1.Text = "添加字幕";eVisualStyleBackColor = true;this.button1.Click += new System.EventHandler(this.button1_Click);//// panel1//this.panel1.BackColor = System.Drawing.SystemColors.ActiveCaption;this.panel1.Controls.Add(this.button2);this.panel1.Controls.Add(this.richTextBox1);this.panel1.Location = new System.Drawing.Point(110, 31); = "panel1";this.panel1.Size = new System.Drawing.Size(511, 77);this.panel1.TabIndex = 3;this.panel1.Visible = false;//// button2//this.button2.BackColor = System.Drawing.SystemColors.MenuHighlight;this.button2.ForeColor = System.Drawing.SystemColors.InactiveBorder;this.button2.Location = new System.Drawing.Point(432, 3); = "button2";this.button2.Size = new System.Drawing.Size(75, 70);this.button2.TabIndex = 1;this.button2.Text = "确定";eVisualStyleBackColor = false;this.button2.Click += new System.EventHandler(this.button2_Click);//// richTextBox1//this.richTextBox1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(64)))));this.richTextBox1.Font = new System.Drawing.Font("SimHei", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));this.richTextBox1.ForeColor = System.Drawing.SystemColors.MenuHighlight;this.richTextBox1.Location = new System.Drawing.Point(4, 3); = "richTextBox1";this.richTextBox1.Size = new System.Drawing.Size(422, 70);this.richTextBox1.TabIndex = 0;this.richTextBox1.Text = "";//// FormTest//this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;this.ClientSize = new System.Drawing.Size(867, 318);this.Controls.Add(this.panel1);this.Controls.Add(this.button1);this.Cursor = System.Windows.Forms.Cursors.Hand;this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; = "FormTest";this.Text = "FormTest";this.Load += new System.EventHandler(this.FormTest_Load);this.Click += new System.EventHandler(this.FormTest_Click);this.panel1.ResumeLayout(false);this.ResumeLayout(false);}#endregionprivate System.Windows.Forms.Button button1;private System.Windows.Forms.Panel panel1;private System.Windows.Forms.RichTextBox richTextBox1;private System.Windows.Forms.Button button2;}}播放窗体类(FormPlayer.cs ):using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Text;using System.Windows.Forms;namespace MyPlayer{public partial class FormPlayer : Form{Song Music = new Song();public FormPlayer(){InitializeComponent();}private void button1_Click(object sender, EventArgs e){OpenFileDialog openFileDialog = new OpenFileDialog();openFileDialog.InitialDirectory = "c:\\";openFileDialog.Filter = "mp3文件|*.mp3|wma文件|*.wma|wav文件|*.wav";openFileDialog.RestoreDirectory = true;openFileDialog.FilterIndex = 1;openFileDialog.InitialDirectory = "E:\\music";if (openFileDialog.ShowDialog() == DialogResult.OK){timer1.Stop();Music.Stop();string fName = openFileDialog.FileName;textBox1.Text = fName;Music.FilePath = textBox1.Text;//将文件路径赋给播放类中的FilePath;Music.OpenFile();//打开播放文件,准备播放;textBox2.Text = Music.FileName;//获取文件名;textBox3.Text = Music.Duration.ToString();//获取文件长度;textBox6.Text = Music.Status().ToString();//获取文件状态;trackBar1.Value = 50;Music.SetVolume(500);//将音量设置成500;textBox5.Text = Music.TheVolume().ToString();//获取音量;timer1.Start();}}private void button3_Click(object sender, EventArgs e){Music.Pause();//暂停;textBox6.Text = Music.Status().ToString();}private void button4_Click(object sender, EventArgs e){Music.Stop();//停止;timer1.Enabled = false;textBox6.Text = Music.Status().ToString();}private void button5_Click(object sender, EventArgs e){Music.PlayHalfSpeed();//半速播放;textBox6.Text = Music.Status().ToString();}private void button6_Click(object sender, EventArgs e){Music.PlayDoubleSpeed();//倍速播放;textBox6.Text = Music.Status().ToString();}private void timer1_Tick(object sender, EventArgs e){//获取文件当前播放位置;textBox4.Text = Convert.ToString(Music.CurrentPosition);//textBox4.Text = Convert.ToString(Music.CurrentPosition.ToString("mm:ss:ff"));//textBox4.Text = (Music.CurrentPosition / 1000 / 60).ToString("00") + ":" + (Music.CurrentPosition / 1000 / 60).ToString("00");// Complete number of secondsint s = Music.CurrentPosition;TimeSpan t = new TimeSpan(1900,0,0,0,s);ClassCommon.SongCrrentTime = t.Minutes.ToString("00") + ":" + t.Seconds.ToString("00") + "." + liseconds.ToString("00");textBox4.Text = t.Minutes.ToString("00") + ":" + t.Seconds.ToString("00") + ":" + liseconds.ToString("00");return;// Seconds to displayint ss = s % 60;// Complete number of minutesint m = (s - ss) / 60;// Minutes to displayint mm = m % 60;// Complete number of hoursint h = (m - mm) / 60;// Make "hh:mm:ss"textBox4.Text = h.ToString("D2") + ":" + mm.ToString("D2") + ":" + ss.ToString("D2");}private void button7_Click(object sender, EventArgs e){//设置指定位置开始播放;Music.CurrentPosition = Convert.ToInt32(textBox8.T ext);}private void button9_Click(object sender, EventArgs e){//进行录音;Music.Record(Convert.ToInt32(textBox9.Text));}private void button10_Click(object sender, EventArgs e){Music.VolumeOn();//取消静音;}private void button11_Click(object sender, EventArgs e){Music.VolumeOff();//静音;}private void trackBar1_Scroll(object sender, EventArgs e) {//设置音量;Music.SetVolume(Convert.ToInt32(trackBar1.Value * 10));textBox5.Text = Music.TheVolume().ToString();}private void FormPlayer_Load(object sender, EventArgs e) {}FormLrc oFormLrc = new FormLrc();private void button2_Click(object sender, EventArgs e){//if(Music.FilePath){}Music.OpenFile();Music.Play();//播放;// oFormLrc.LoadLrc("刘德华- 冰雨.lrc");oFormLrc.LoadLrc("刘德华-天意.lrc");oFormLrc.Show();timer1.Enabled = true;textBox6.Text = Music.Status().ToString();}}}播放窗体界面类(FormPlayer.Designer.cs):namespace MyPlayer{partial class FormPlayer{/// <summary>/// 必需的设计器变量。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Lrc歌词文件格式说明扩展名为Lrc格式的文件,是MP3播放器唯一能够识别的歌词文件,在MP3数码播放器或千千静听中可以区同步显示歌词。
它是一种包含着“[*:*]”形式的“标签(tag)”的、基于纯文本的歌词专用格式。
最早由郭祥祥先生(Djohan)提出并在其程序中得到应用。
这种歌词文件既可以用来实现卡拉OK 功能(需要专门程序),又能以普通的文字处理软件查看、编辑。
当然,实际操作时通常是用专门的LRC歌词编辑软件进行高效编辑的。
Lrc歌词文本中含有两类标签:一是标识标签,其格式为“[标识名:值]”主要包含以下预定义的标签:[ar:歌手名]、[ti:歌曲名]、[al:专辑名]、[by:编辑者(指lrc歌词的制作人)]、[offset:时间补偿值] (其单位是毫秒,正值表示整体提前,负值相反。
这是用于总体调整显示快慢的,但多数的MP3可能不会支持这种标签)。
二是时间标签,形式为“[mm:ss]”或“[mm:ss.fff]”(分钟数:秒数:毫秒数),时间标签需位于某行歌词中的句首部分,一行歌词可以包含多个时间标签(比如歌词中的迭句部分)。
当歌曲播放到达某一时间点时,MP3就会寻找对应的时间标签并显示标签后面的歌词文本,这样就完成了“歌词同步”的功能。
■时间标签(Time-tag)形式为"[mm:ss]"或"[mm:ss.fff]"(分钟数:秒数)。
数字须为非负整数,比如"[12:34.5]"是有效的,而"[0x0C:-34.5]"无效。
它可以位于某行歌词中的任意位置。
一行歌词可以包含多个时间标签(比如歌词中的迭句部分)。
根据这些时间标签,用户端程序会按顺序依次高亮显示歌词,从而实现卡拉OK 功能。
另外,标签无须排序。
■标识标签(ID-tags)其格式为"[标识名:值]"。
大小写等价。
以下是预定义的标签。
[ar:艺人名][ti:曲名][al:专辑名][by:编者(指编辑LRC歌词的人)][offset:时间补偿值] 其单位是毫秒,正值表示整体提前,负值相反。
这是用于总体调整显示快慢的。
分钟:秒.毫秒]歌词用记事本按照上述格式写好后,将拓展名改为lrc即可做出该文件.LRC歌词是一种通过编辑器把歌词按歌曲歌词出现的时间编辑成一个文件,在播放歌曲时同步依次显示出来的一种歌词文件。
把歌曲和LRC歌词命为相同的文件名放在同一目录下,用带显示歌词功能的播放器播放歌曲时歌词就可以同步显示显示,方便查看和学歌。
(供程序员阅读参考)以下列出了开发支持LRC格式的软件时应遵守的一些标准。
无论是否在行首,行内凡具有“[*:*]”形式的都应认为是标签。
(注意:其中的冒号并非全角字符“:”)凡是标签都不应显示。
凡是标签,且被冒号分隔的两部分都为非负数,则应认为是时间标签。
因此,对于非标准形式(非“[mm:ss]”)的时间标签也应能识别(如“[0:0]”)。
凡是标签,且非时间标签的,应认为是标识标签。
标识名中大小写等价。
·为了向后兼容,应对未定义的新标签作忽略处理。
另应对注释标签([:])后的同一行内容作忽略处理。
应允许一行中存在多个标签,并能正确处理。
应能正确处理未排序的标签。
以下附上C++实现代码,支持ANSI和Unicode格式,超强纠错。
-----------------------------------------------------Lyric.h----------------------------------------------------- typedef struct{DWORD dwStartTime; // The unit is millisecondCString csLyric;} LineLyric, *PLineLyric;class CLyric{public:CLyric();~CLyric();CString m_csArtist;CString m_csTitle;CString m_csAlbum;CString m_csBy;LONG m_lOffset; // Lead time of the lyricCString m_csKey;public:BOOL Load(LPCWSTR szFileName, LONG lUserOffset = 0); // If lUserOffset > 0: ahead; if < 0: put offvoid UnLoad();BOOL GetItemByID(DWORD dwItemID, LineLyric &lyric); // Get the lyric data by dwItemIDDWORD GetTimeByID(DWORD dwItemID); // Get the lyric's start time by dwItemIDLONG GetItemIDByTime(DWORD dwTime, DWORD dwStartLineID = 0);// Search the line index by time(in milliseconds) begin at nStartLineIDDWORD GetTotalNum() { return m_dwLineNum; }BOOL IsValid() { return m_bValid; }private:BOOL m_bValid;CArray<LineLyric> m_LyricList;DWORD m_dwLineNum;BOOL m_bAnalyseTag;LONG m_lUserOffset;__forceinline BOOL ReadALine(FILE *fp, CHAR *buff, INT bufflen, INT &readlen);__forceinline void AnalyseLine(CHAR *szLine, INT nLength);__forceinline BOOL CheckTag(CHAR *szText);__forceinline LONG GetStartTime(CHAR *szTime);__forceinline BOOL ReadALineW(FILE *fp, WCHAR *buff, INT bufflen, INT&readlen);__forceinline void AnalyseLineW(WCHAR *szLine, INT nLength);__forceinline BOOL CheckTagW(WCHAR *szText);__forceinline LONG GetStartTimeW(WCHAR *szTime);__forceinline DWORD Find(DWORD dwTime); // return the line ID matched the time};-----------------------------------------------------Lyric.cpp----------------------------------------------------- #include"Lyric.h"#define MAX_LYRIC_LINE_LEN512#define MAX_LYRIC_LEN128#define MAX_LYRIC_LINE_NUM5000#define MAX_LYRIC_TIME_LEN30CLyric::CLyric(){m_bValid = FALSE;m_lUserOffset = 0;}CLyric::~CLyric(){}BOOL CLyric::Load(LPCWSTR szFileName, LONG lUserOffset){UnLoad();FILE*fp;INT readlen;m_lUserOffset = lUserOffset;fp = _tfopen(szFileName, _T("r"));if (fp == NULL){return FALSE;}WORD wUnicode_tag = 0;DWORD dwReadLen = 0;try{dwReadLen = fread((void *)&wUnicode_tag, sizeof(WCHAR), 1, fp);}catch (...){printf("CLyric::Load: fread Exception: %s!\r\n", szFileName);fclose(fp);return FALSE;}if (dwReadLen != 1){printf("CLyric::Load: read file %s failed!\r\n", szFileName);fclose(fp);return FALSE;}if (wUnicode_tag == 0xfeff) // unicode file{fclose(fp);fp = _tfopen(szFileName, _T("rb"));if (fp == NULL){return FALSE;}fseek(fp, sizeof(WCHAR), SEEK_SET);WCHAR wstr[MAX_LYRIC_LINE_LEN];do{if (!ReadALineW(fp, wstr, MAX_LYRIC_LINE_LEN, readlen)) break;if (readlen <= 0)continue;AnalyseLineW(wstr, readlen);}while (m_dwLineNum < MAX_LYRIC_LINE_NUM);}else{fseek(fp, 0L, SEEK_SET);CHAR str[MAX_LYRIC_LINE_LEN];do{if (!ReadALine(fp, str, MAX_LYRIC_LINE_LEN, readlen)) break;if (readlen <= 0)continue;AnalyseLine(str, readlen);}while (m_dwLineNum < MAX_LYRIC_LINE_NUM);}fclose(fp);m_bValid = TRUE;return TRUE;}void CLyric::UnLoad(){m_bValid = FALSE;m_csArtist.Empty();m_csTitle.Empty();m_csAlbum.Empty();m_csBy.Empty();m_lOffset = 0;m_csKey.Empty();m_LyricList.RemoveAll();m_dwLineNum = 0;m_bAnalyseTag = TRUE;m_lUserOffset = 0;}BOOL CLyric::GetItemByID(DWORD dwItemID, LineLyric &lyric) {if (dwItemID < (DWORD)m_LyricList.GetSize()){lyric = m_LyricList[dwItemID];return TRUE;}else{return FALSE;}}DWORD CLyric::GetTimeByID(DWORD dwItemID){DWORD dwTotalItem = (DWORD)m_LyricList.GetSize();if (dwTotalItem == 0)return 0;if (dwItemID < dwTotalItem){return m_LyricList[dwItemID].dwStartTime;}else{return m_LyricList[dwTotalItem-1].dwStartTime;}}LONG CLyric::GetItemIDByTime(DWORD dwTime, DWORD dwStartLineID){DWORD dwLineNum = m_LyricList.GetSize();if (dwTime <= 0 || dwLineNum == 0)return -1;for (DWORD i = dwStartLineID; i < dwLineNum; i++){if (m_LyricList[i].dwStartTime > dwTime){return i-1;}}return dwLineNum-1;}__forceinline BOOL CLyric::ReadALine(FILE *fp, CHAR *buff, INT bufflen, INT &readlen) {readlen = 0;if (feof(fp)) /* End or file, return -1 */return FALSE;int ch;do{ch = fgetc(fp);if (ch == '\r' || ch == '\n' || ch == EOF)break;if (readlen >= bufflen-1)continue; // Use continue for ignoring the remanent character of the line*buff = ch;buff++;readlen++;} while (!feof(fp));if (readlen > 0 && *(buff-1) == '\r')*(buff-1) = 0;else*buff = 0;return TRUE;}__forceinline void CLyric::AnalyseLine(CHAR *szLine, INT nLength){WCHAR szLyric[MAX_LYRIC_LEN];CHAR szTime[MAX_LYRIC_TIME_LEN];CHAR *szTimeBegin = NULL; // Begin at the next char of '['CHAR *szTimeEnd = NULL; // End at ']'CHAR *szNextTimeBegin = strchr(szLine, '[');if (szNextTimeBegin == NULL)return;szNextTimeBegin++;CHAR *szNextTimeEnd = strchr(szNextTimeBegin, ']');if (szNextTimeEnd == NULL)return;LineLyric lyric;LONG lStartTime;while (szNextTimeBegin != NULL && szNextTimeEnd != NULL)// Support multi time/tag in one line{szTimeBegin = szNextTimeBegin;szTimeEnd = szNextTimeEnd;szNextTimeBegin = strchr(szTimeEnd, '[');if (szNextTimeBegin != NULL){szNextTimeEnd = strchr(szNextTimeBegin, ']');if (szNextTimeEnd != NULL){// Find a next Time in the same line*szNextTimeBegin = 0; // Set '[' as the end flag of the stringszNextTimeBegin++;}}if (szTimeEnd > szTimeBegin+1){INT nTimeLen = min(MAX_LYRIC_TIME_LEN-1,szTimeEnd-szTimeBegin);strncpy(szTime, szTimeBegin, nTimeLen);szTime[nTimeLen] = 0;if (m_bAnalyseTag){if (CheckTag(szTime))continue;}lStartTime = GetStartTime(szTime);if (lStartTime < 0)continue;lyric.dwStartTime = max((lStartTime - m_lOffset - m_lUserOffset), 0);MultiByteToWideChar(Core_GetDefCodePage(), 0, szTimeEnd+1, -1, szLyric, MAX_LYRIC_LEN-1);lyric.csLyric = szLyric;if (lyric.csLyric.IsEmpty() && szTimeEnd+2 != 0){// To get MultiTimeLyricCHAR *szMultiTimeLyric = szTimeEnd+2;szMultiTimeLyric = strchr(szMultiTimeLyric, ']');if (szMultiTimeLyric != NULL){CHAR *szMultiTimeLyricBegin = szMultiTimeLyric+1;while (1){szMultiTimeLyric = strchr(szMultiTimeLyricBegin, '[');if (szMultiTimeLyric == NULL) // Find MultiTimeLyric, it's at the end of the line{MultiByteToWideChar(Core_GetDefCodePage(), 0, szMultiTimeLyricBegin, -1, szLyric, MAX_LYRIC_LEN-1);lyric.csLyric = szLyric;break;}else if (szMultiTimeLyric-szMultiTimeLyricBegin > 0) // Find MultiTimeLyric, it's at the middle of the line{MultiByteToWideChar(Core_GetDefCodePage(), 0, szMultiTimeLyricBegin, -1, szLyric, MAX_LYRIC_LEN-1);lyric.csLyric = szLyric;lyric.csLyric = lyric.csLyric.Mid(0,szMultiTimeLyric-szMultiTimeLyricBegin);break;}szMultiTimeLyric = strchr(szMultiTimeLyric+1, ']');if (szMultiTimeLyric == NULL) // Invalid format, has '[', but no ']'{MultiByteToWideChar(Core_GetDefCodePage(), 0, szMultiTimeLyricBegin, -1, szLyric, MAX_LYRIC_LEN-1);lyric.csLyric = szLyric;break;}szMultiTimeLyricBegin = szMultiTimeLyric+1;}}}if (m_dwLineNum > 0 || !lyric.csLyric.IsEmpty()) // First line must no be empty{if (m_dwLineNum > 0 && lyric.dwStartTime >=m_LyricList.GetAt(m_dwLineNum-1).dwStartTime)m_LyricList.Add(lyric);elsem_LyricList.InsertAt(Find(lyric.dwStartTime), lyric); // Auto sort by timem_dwLineNum++;}m_bAnalyseTag = FALSE; // Consider Tag info is at the beginning of the file}}}BOOL CLyric::CheckTag(CHAR *szText){if (_strnicmp(szText, "ar", 2) == 0){m_csArtist = szText+3;return TRUE;}if (_strnicmp(szText, "ti", 2) == 0){m_csTitle = szText+3;return TRUE;}if (_strnicmp(szText, "al", 2) == 0){m_csAlbum = szText+3;return TRUE;}if (_strnicmp(szText, "by", 2) == 0){m_csBy = szText+3;return TRUE;}if (_strnicmp(szText, "offset", 6) == 0){m_lOffset = atol(szText+7);return TRUE;}if (_strnicmp(szText, "key", 3) == 0){m_csKey = szText+4;return TRUE;}return FALSE;}__forceinline LONG CLyric::GetStartTime(CHAR *szTime){INT nMinute = 0;INT nSecond = 0;INT nMilliSecond = 0;CHAR *szMinuteEnd = strrchr(szTime, ':');if (szMinuteEnd == NULL){nMinute = 0;szMinuteEnd = szTime;}else{CHAR szMinute[10];INT nMinuteLen = min(9, szMinuteEnd-szTime);strncpy(szMinute, szTime, nMinuteLen);if (nMinuteLen > 0 && (szMinute[0] < '0' || szMinute[0] > '9')) return -1;nMinute = atoi(szMinute);if (nMinute < 0)nMinute = 0;szMinuteEnd++;}CHAR *szSecondEnd = strrchr(szMinuteEnd, '.');if (szSecondEnd == NULL){nSecond = atoi(szMinuteEnd);if (nSecond < 0)nSecond = 0;}else{CHAR szSecond[10];INT nSecondLen = min(9, szSecondEnd-szMinuteEnd);strncpy(szSecond, szMinuteEnd, nSecondLen);if (nSecondLen > 0 && (szSecond[0] < '0' || szSecond[0] > '9'))return -1;nSecond = atoi(szSecond);if (nSecond < 0)nSecond = 0;szSecondEnd++;INT nMilliSecondLen = strlen(szSecondEnd);if (nMilliSecondLen == 1)nMilliSecond = atoi(szSecondEnd) * 100;else if (nMilliSecondLen == 2)nMilliSecond = atoi(szSecondEnd) * 10;else if (nMilliSecondLen == 3)nMilliSecond = atoi(szSecondEnd);if (nMilliSecond < 0)nMilliSecond = 0;}return nMinute*60000+nSecond*1000+nMilliSecond;}__forceinline BOOL CLyric::ReadALineW(FILE *fp, WCHAR *buff, INT bufflen, INT &readlen){WCHAR *pReturn = fgetws(buff, bufflen, fp);if (pReturn == NULL)return FALSE;readlen = lstrlen(buff);if (readlen > 0 && buff[readlen-1] == _T('\n')){buff[readlen-1] = 0;readlen--;}if (readlen > 0 && buff[readlen-1] == _T('\r')){buff[readlen-1] = 0;readlen--;}return TRUE;}__forceinline void CLyric::AnalyseLineW(WCHAR *szLine, INT nLength){WCHAR szTime[MAX_LYRIC_TIME_LEN];WCHAR *szTimeBegin = NULL; // Begin at the next char of '['WCHAR *szTimeEnd = NULL; // End at ']'WCHAR *szNextTimeBegin = wcschr(szLine, _T('['));if (szNextTimeBegin == NULL)return;szNextTimeBegin++;WCHAR *szNextTimeEnd = wcschr(szNextTimeBegin, _T(']'));if (szNextTimeEnd == NULL)return;LineLyric lyric;LONG lStartTime;while (szNextTimeBegin != NULL && szNextTimeEnd != NULL)// Support multi time/tag in one line{szTimeBegin = szNextTimeBegin;szTimeEnd = szNextTimeEnd;szNextTimeBegin = wcschr(szTimeEnd, _T('['));if (szNextTimeBegin != NULL){szNextTimeEnd = wcschr(szNextTimeBegin, _T(']'));if (szNextTimeEnd != NULL){// Find a next Time in the same line*szNextTimeBegin = 0; // Set '[' as the end flag of the stringszNextTimeBegin++;}}if (szTimeEnd > szTimeBegin+1){INT nTimeLen = min(MAX_LYRIC_TIME_LEN-1,szTimeEnd-szTimeBegin);wcsncpy(szTime, szTimeBegin, nTimeLen);szTime[nTimeLen] = 0;if (m_bAnalyseTag){if (CheckTagW(szTime))continue;}lStartTime = GetStartTimeW(szTime);if (lStartTime < 0)continue;lyric.dwStartTime = max((lStartTime - m_lOffset - m_lUserOffset), 0);lyric.csLyric = szTimeEnd+1;if (lyric.csLyric.IsEmpty() && szTimeEnd+2 != 0){// To get MultiTimeLyricWCHAR *szMultiTimeLyric = szTimeEnd+2;szMultiTimeLyric = wcschr(szMultiTimeLyric, _T(']'));if (szMultiTimeLyric != NULL){WCHAR *szMultiTimeLyricBegin = szMultiTimeLyric+1;while (1){szMultiTimeLyric = wcschr(szMultiTimeLyricBegin, _T('['));if (szMultiTimeLyric == NULL) // Find MultiTimeLyric, it's at the end of the line{lyric.csLyric = szMultiTimeLyricBegin;break;}else if (szMultiTimeLyric-szMultiTimeLyricBegin > 0) // Find MultiTimeLyric, it's at the middle of the line{lyric.csLyric = szMultiTimeLyricBegin;lyric.csLyric = lyric.csLyric.Mid(0,szMultiTimeLyric-szMultiTimeLyricBegin);break;}szMultiTimeLyric = wcschr(szMultiTimeLyric+1, _T(']'));if (szMultiTimeLyric == NULL) // Invalid format, has '[', but no ']'{lyric.csLyric = szMultiTimeLyricBegin;break;}szMultiTimeLyricBegin = szMultiTimeLyric+1;}}}if (m_dwLineNum > 0 || !lyric.csLyric.IsEmpty()) // First line must no be empty{if (m_dwLineNum > 0 && lyric.dwStartTime >=m_LyricList.GetAt(m_dwLineNum-1).dwStartTime)m_LyricList.Add(lyric);elsem_LyricList.InsertAt(Find(lyric.dwStartTime), lyric); // Auto sort by timem_dwLineNum++;}m_bAnalyseTag = FALSE; // Consider Tag info is at the beginning of the file}}}BOOL CLyric::CheckTagW(WCHAR *szText){if (_wcsnicmp(szText, _T("ar"), 2) == 0){m_csArtist = szText+3;return TRUE;}if (_wcsnicmp(szText, _T("ti"), 2) == 0){m_csTitle = szText+3;return TRUE;}if (_wcsnicmp(szText, _T("al"), 2) == 0){m_csAlbum = szText+3;return TRUE;}if (_wcsnicmp(szText, _T("by"), 2) == 0){m_csBy = szText+3;return TRUE;}if (_wcsnicmp(szText, _T("offset"), 6) == 0){m_lOffset = _wtol(szText+7);return TRUE;}if (_wcsnicmp(szText, _T("key"), 3) == 0){m_csKey = szText+4;return TRUE;}return FALSE;}__forceinline LONG CLyric::GetStartTimeW(WCHAR *szTime){INT nMinute = 0;INT nSecond = 0;INT nMilliSecond = 0;WCHAR *szMinuteEnd = wcsrchr(szTime, ':');if (szMinuteEnd == NULL){nMinute = 0;szMinuteEnd = szTime;}else{WCHAR szMinute[10];INT nMinuteLen = min(9, szMinuteEnd-szTime);wcsncpy(szMinute, szTime, nMinuteLen);if (nMinuteLen > 0 && (szMinute[0] < _T('0') || szMinute[0] > _T('9'))) return -1;nMinute = _wtoi(szMinute);if (nMinute < 0)nMinute = 0;szMinuteEnd++;}WCHAR *szSecondEnd = wcsrchr(szMinuteEnd, _T('.'));if (szSecondEnd == NULL){nSecond = _wtoi(szMinuteEnd);if (nSecond < 0)nSecond = 0;}else{WCHAR szSecond[10];INT nSecondLen = min(9, szSecondEnd-szMinuteEnd);wcsncpy(szSecond, szMinuteEnd, nSecondLen);if (nSecondLen > 0 && (szSecond[0] < _T('0') || szSecond[0] > _T('9'))) return -1;nSecond = _wtoi(szSecond);if (nSecond < 0)nSecond = 0;szSecondEnd++;INT nMilliSecondLen = lstrlen(szSecondEnd);if (nMilliSecondLen == 1)nMilliSecond = _wtoi(szSecondEnd) * 100;else if (nMilliSecondLen == 2)nMilliSecond = _wtoi(szSecondEnd) * 10;else if (nMilliSecondLen == 3)nMilliSecond = _wtoi(szSecondEnd);if (nMilliSecond < 0)nMilliSecond = 0;}return nMinute*60000+nSecond*1000+nMilliSecond;}__forceinline DWORD CLyric::Find(DWORD dwTime){DWORD i = 0;for (i = 0; i < (DWORD)m_LyricList.GetSize(); i++){if (m_LyricList[i].dwStartTime > dwTime){break;}}return i; }。