基于Linux系统的C语言歌词解析

项目功能

该歌词解析器是在Ubuntu系统下实现的,可以实现歌词的滚屏实时显示、进度条及时间显示、以及字符画的显示。
项目截图:
基于Linux系统的C语言歌词解析_第1张图片

ASCII Generator软件链接:https://pan.baidu.com/s/1spQ5i9fC7kAIwyyJa-aKfg
提取码:13nz

项目实现方式

此次项目工作量较大,C语言采取分文件的方式编写;
主要分为4个 .c 文件 1个 .h 文件 还有一个Makefile文件
.c 文件分别为:
1、main.c文件主要是调用各种函数显示出主要的流程;
2、fun.c文件主要包含了各种需要调用的函数实现,包括歌词文件读取、歌词文件切割、歌词分析、启动mplayer播放器、字符画、光标移动、光标隐藏、清屏以及字体颜色设置;
3、link.c主要包含了链表的有序插入、遍历、查询以及释放;
4、display.c包含了最后显示函数的设置。

项目部分源码

第一步.将歌词文件读取到堆区空间:

//一次性将文件内容读取到堆区空间
char* get_lrc_memory(char *name[],int num)
{
    FILE *fp = NULL;
    fp = fopen(name[num-1],"r");
    if(fp == NULL)
    {
        perror("fopen");
        return NULL;
    }

    fseek(fp,0,2);//将流指针定位在文件的尾部
    unsigned long len = 0;
    len = ftell(fp);//获取文件长度
    rewind(fp);

    char *arr = NULL;
    arr = (char*)calloc(1,len+1);//根据文件长度申请空间
    if(arr == NULL)
    {
        perror("calloc");
        return NULL;
    }
    fread(arr,len,1,fp);//将文件读取到申请的空间中

    fclose(fp);
    return arr;
}

第二步.将歌词进行切割:

//将读取到的歌词文件 按行进行分割
int strtok_lrc(char *buf[])
{
    int i = 0;
    while((buf[i++] = strtok(buf[i],"\r\n")));
    return i-1;
}

第三步分析歌词
这一步中分为两小步

a.分析歌词的前四行,因为歌词中一般前四行为歌曲信息

//前四行分析 显示
void analyze_lrc_four(char *buf[])
{
    int i = 0;
    for(i=0;i<4;i++)
    {
        char tmp1[128] = "";
        char tmp2[128] = "";
        sscanf(buf[i],"[%[^:]:%[^]]",tmp1,tmp2);
        
        if(strcmp("ti",tmp1)==0)
        {
            cusor_moveto(45,1);
            printf("歌名: %s\n",tmp2);
        }
        if(strcmp("ar",tmp1)==0)
        {
            cusor_moveto(45,2);
            printf("歌手: %s\n",tmp2);
        }
        if(strcmp("al",tmp1)==0)
        {
            cusor_moveto(45,3);
            printf("专辑: %s\n",tmp2);
        }
        if(strcmp("by",tmp1)==0)
        {
            cusor_moveto(45,4);
            printf("制作: %s\n",tmp2);
        }
    }
}

b.分析后边的歌词并将其按歌词时间顺序存入链表

分析歌词 代码:

//歌词分析
LRC* analyze_lrc_last(char *buf[],const unsigned int row)
{
    int i = 4;
    LRC *head = NULL;
    for(i=4;i<row;i++)
    {
        char *str_lrc = buf[i];

        while(*str_lrc == '[')
        {
            str_lrc +=10;//str_lrc指向了歌词的位置
        }
        
        //逐个时间分析
        char *str_time = buf[i];
        while(*str_time == '[')
        {
            int m = 0;
            int s = 0;
            sscanf(str_time,"[%d:%d.41]", &m,&s);
            int time = m*60+s;//以秒为单位
        
            //将时间 和 歌词  一一对应 放入 结构体
            LRC tmp;
            tmp.time = time;
            strcpy(tmp.lrc, str_lrc);

            //调用链表的有序插入函数
            head = insert_link(head,tmp);

            //分析下一个时间
            str_time  += 10;
        }
    }
    return head;
}

链表插入代码:

//歌词 按照time的大小排序 插入链表
LRC* insert_link(LRC *head,LRC tmp)
{
    LRC *pi = (LRC*)calloc(1,sizeof(LRC));
    if(pi == NULL)
    {
        perror("calloc");
        return head;
    }
    *pi = tmp;
    pi->next = NULL;

    if(head == NULL)//不存在
    {
        head = pi;
        return head;
    }
    else //存在
    {
        //a.寻找插入点
        LRC *pd = head;
        LRC *pf = head;
        while(pd->time < pi->time && pd->next != NULL)
        {
            pf = pd;
            pd = pd->next;
        } 
        //b.插入点判断
        if(pd->time >= pi->time)//头部中部插入
        {
            if(pd == head)  //头部
            {
                pi->next = head;
                head = pi;
                return head;
            }
            else            //中间
            {
                pi->next = pd;
                pf->next = pi;
                return head;
            }
        }
        else //尾部插入
        {
            pd->next = pi;
            return head;
        }

    }

    return head;

}

链表插入之后建议进行一次链表遍历操作,以便于确认链表插入没有出现问题:
遍历链表代码如下:

//遍历链表
void print_link(LRC *head)
{
    if(head == NULL)
    {
        printf("link not find\n");
    }
    else
    {
        LRC* pb = head;
        while(pb != NULL)
        {
            printf("%d %s\n",pb->time,pb->lrc);
            pb = pb->next;
        }
    }
    return;
}

在此之后进行模拟时钟的设计,在同时启动播放器播放音乐,使时钟与音乐时间匹配,便于之后的歌词对比。
然后进行滚屏设计,此处设计一种简单的滚屏设计:

char buf1[128]="";
	char buf2[128]="";
	char buf3[128]="";
	char buf4[128]="";
	
while(1)
	{
		//光标定位
		cusor_moveto(35,5);
		printf("%02d:%02d",time/60,time%60 );
		
		fflush(stdout);

        LRC *ret = search_link(head, time);//链表查找 按时间
		if(ret != NULL)
        {
			strcpy(buf1,buf2);
			strcpy(buf2,buf3);
			strcpy(buf3,buf4);
			strcpy(buf4,ret->lrc);
			
            cusor_moveto(40,7);//光标定位
			printf("%s                     ", buf1);

			cusor_moveto(40,8);
			printf("%s                     ", buf2);
			
			cusor_moveto(40,8);
			printf("%s                     ", buf3);
			
			cusor_moveto(40,10);
			set_fg_color(COLOR_RED);
			printf("%s                     ", buf4);//当前歌词
			set_fg_color(COLOR_BLUE);
		}
		sleep(1);
        time++;
	 }

完成之后可以对项目进行一些创新,比如加入字符画;
基于Linux系统的C语言歌词解析_第2张图片
此字符画由ASCII Generator软件生成该软件可去网盘下载,链接在文章顶部。

此文章及代码完全由本人完成,以上代码不完全,只包括部分函数。

你可能感兴趣的:(基于Linux系统的C语言歌词解析)