C语言:歌词解析-简单爱(完整版_全部代码)

一、项目介绍

攀登的过程也许漫长,但巅峰的风景是值得的!
C语言的一个小项目,在与虚拟机连接的Visual Studio Code中编写实现的,可以实现歌词的滚屏,进度条、以及时间显示等。

二、了解歌词

了解歌词,前四行都是歌词信息,需要单独处理;剩下的是歌词内容,可以综合处理。
歌词展示如下:
在这里插入图片描述

三、项目流程

1.读取歌词

1.1)打开歌词文件(fopen)

fopen:打开文件

1.2)计算歌词文件大小(fseek、ftell、rewind、calloc、fread、fclose)

fessk:将文件流指针指向末尾
ftell:获取文件流指针到文件首部的字节数
rewind:复位,将文件流指针指向开头

1.3)分配内存空间(calloc)

calloc:开辟空间

1.4)将歌词读入内存,并关闭文件

fread:将读取到的歌词,存入内存
fclose:关闭文件

//读取歌词
void read_lrc(char *p_lrc, char **lrc_data)
{
   
	//打开歌词文件
	FILE *fp = fopen(p_lrc, "r");
	if(fp == NULL)
	{
   
		perror("fopen");
		return;
	}
	
	//计算歌词文件的大小
	fseek(fp, 0, SEEK_END);//fseek将文件流指针指向文件的末尾
	long lrc_len = ftell(fp);//ftell获取文件流指针到文件首部的字节数
	rewind(fp); //复位,将文件指针流指向开头
	
	//根据文件大小,分配内存空间
	*lrc_data = (char *)calloc(1, lrc_len);
	if(*lrc_data == NULL)
	{
   
		perror("ralloc");
		return;
	}
	
	//使用fread将读取到的歌词读入内存
	fread(*lrc_data, lrc_len, 1, fp);
	
	/*关闭文件*/
	fclose(fp);
	
	return;
}

2.按行切割歌词

将歌词逐行进行切割,每一行内容按照“\r\n”切割,将数据保存到数组buf中

//将歌词逐行分割
void lrctok(char ** buf, char *lrc_data)
{
   
	buf[0] = lrc_data;
	int i = 0;
	//将歌词的每一行内容读取出来
	while((buf[i] = (char *)strtok(buf[i], "\r\n")))
		i++;
	return;
}

3.逐行分析前四行歌词

在这里插入图片描述
将“ti”,“ar”,“al”,“by”转换为“歌名”,“歌手”,“专辑”,“制作”

//逐行分析头部
	int i = 0;
	while(*(buf[i] + 1) > '0')//解释歌词信息
	{
   
		//读取头部信息内容
		char lrc[128]="";
		sscanf(buf[i],"%*[^:]:%[^]]", lrc);
		
		//读取头部信息标签“ti”,“ar”,“al”,“by”
		char tags[10] = "";
		sscanf(buf[i], "[%[^:]", tags);
		
		cusor_moveto(35, i+1);
		
		//将“ti”,“ar”,“al”,“by”转换为“歌名”,“歌手”,“专辑”,“制作”
		if(strcmp(tags, "ti") == 0)
		{
   
			printf("歌名:");
		}
		else if(strcmp(tags, "ar") == 0)
		{
   
			printf("歌手:");
		}
		else if(strcmp(tags, "al") == 0)
		{
   
			printf("专辑:");
		}
		else if(strcmp(tags, "by") == 0)
		{
   
			printf("制作:");
		}
		else if(strcmp(tags, "offset") == 0)
		{
   
			printf("offset:");
		}
		printf("%s\n", lrc);
		i++;
	}
	
	//printf("%d\n", i);
	return i;
}

4.逐行分析歌词正文内容

主要分为时间和歌词两个部分,首先分析时间和歌词,然后根据时间将歌词插入链表

//分析歌词正文部分
int analysis_lrc_body(char **buf,int star_num, List *list)
{
   
	int i = star_num;//从头部信息之后开始分析
	while(buf[i])//解析歌词正文
	{
   
		char *str_lrc = buf[i];
	
		while(*str_lrc == '[')//跳过时间,指向歌词位置
			str_lrc +=10;
			
		//printf("%s\n", str_lrc);//打印当前歌词测试
		
		char *str_time = buf[i];//解析每句歌词前的时间
		while(*str_time == '[')
		{
   
			int m = 0,s = 0;
			sscanf(str_time,"[%d:%d.%*d]", &m, &s);
			int time = m*60+s;//以秒为单位
		   
			//将时间和歌词 --对应 放入结构体
			LRC *tmp = (LRC *)calloc(1, sizeof(LRC));
			if(tmp == NULL)
			{
   
				perror("calloc");
				return i;
			}
			tmp->time = time;
			strcpy(tmp->lrc, str_lrc);
       
			//调用链表的有序插入函数
			list_ins_sort(list, tmp);
		   
			//分析下一个时间
			str_time  += 10;
		}
			
		i++;
	}
	return i;
}

5.歌词滚屏

显示歌词设置为五行,调整歌词与歌曲同步偏差,根据时间显示歌词。

//模拟时钟
	int i = 0;//模拟计时器
	char show[5][128] = {
   "","","","",""};
	while(1)
	{
   

		//显示进度条
		int base = 15;//进度条从第base列起始
		set_fg_color(COLOR_RED);//颜色
		cusor_moveto(base, line + 9);
		printf("%02d:%02d|",i/60,i%60);//以mm:ss格式打印时间
		fflush(stdout);
		
		int endtime = ((LRC *)(list.tail->data))->time;
		int length = (i*1.0)/endtime*45;
		cusor_moveto(base + 6, line + 9);
		int j = 0;
		for(; j < length; j++)
		{
   
			printf(">");
		}
		cusor_moveto(base + 51, line + 9);
		printf("|%02d:%02d",endtime/60, endtime%60);
		
		
		//查找此时的歌词
		int offset = 0;//调整歌词与歌曲同步偏差
		LRC tmp;//按时间查找歌词
		tmp.time = i + offset;//初始化查找时间
		strcpy(tmp.lrc, "");
		
		Node *ret = list_search(&list, &tmp);//返回查找歌词在链表中的位置
		
		if(ret != NULL)
        {
   
			//滚动显示歌词
			strcpy(show[0], show[1]);
			strcpy(show[1], show[2]);
			strcpy(show[2], show[3]);
			strcpy(show[3], show[4]);
			strcpy(show[4], ((LRC *)(ret->data))->lrc);
				
			cusor_moveto(30, line+2);
			set_fg_color(COLOR_WHITE);
            printf("%s                             \n", show[0]);
			fflush(stdout);
			
			cusor_moveto(30, line+3);
            printf("%s                             \n", show[1]);
			fflush(stdout);
			
			cusor_moveto(30, line+4);
            printf("%s                             \n", show[2]);
			fflush(stdout);
			
			cusor_moveto(30, line+5)
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值