歌词模拟项目c语言,C语言之歌词解析

0x00 脚下的路

不知道为啥要写这个小标题,可能是年轻的心想体验一下苍老的感觉,抑或是少年的一阵迷茫。混沌的四年,终究还是入了这一行。从初时的不知,到现在的刚开始,中间的间隔竟是四年之久,想起了陈奕迅的《十年》,但却不像医生所唱的十年那么有故事。或许这四年有这四年的价值,这四年也应有所积累。少年狂应少发,更不是什么老夫,当然也没有什么资格。之后的路应该在脚下,应是一步一步。比较喜欢的一句话,不去想目的地,才能轻松踏上旅途。少些心血来潮,多些精专。

聊以此记,舒心之惑,明己之志。

0x01 歌词解析

这是一个用c语言完成的小项目,大神们称之为玩具。不过对于对于知识的积累确有不小的作用。对于自己也是很好的训练,吃透每个小项目,吃透每一个细节,故总结之。

何为歌词解析?效果如何。刚开始必然是一片迷茫,可使用过各种播放器的我们应该对此熟悉。这是平日的歌曲播放器的部分截图:

ef692b2ddd283e7e41d35fb010ba3e27.png

管中窥豹,实现后的具体效果大致也应如此。当然,歌词解析吗?更应该了解歌词是什么样子的,有什么样子的格式(我们都明白,一切的神秘下面都隐藏着简单的道理)。这是某个词文件的部分截图:

dfe695624ff13e9b092c0a65d632fdb7.png

如此,大致便可有些许想法了:将歌词文件读取出来,逐行显示在屏幕上,并随着歌曲播放时间逐行滚动。

0x02 流程分析

通过观察歌词,可以想到使用链表存储歌词信息比较方便,因为歌词要一行一行显示,并且事先并不了解每首歌的歌词有多少句。可以将歌词的每一句存入链表的一个节点。

整个流程大致可以分为如下几块:

读取歌词文件

按行切割歌词文件

逐行分析歌词头部歌曲信息部分

逐行分析歌词正文部分,并根据每行歌词前的时间将歌词插入链表

模拟时钟,根据时间显示歌词和播放歌曲

歌词滚屏,歌词反显(当前歌词突出显示)

0x03 读取歌词文件

文本文件的读取大致分如下步骤:

打开歌词文件

计算歌词文件的大小

分配内存空间

将歌词读入内存

关闭歌词文件

/*读取歌词*/

void read_lrc(char *p_lrc, char **lrc_data)

{

/*打开歌词文件*/

FILE *fp = fopen(p_lrc, "r");

if(fp == NULL)

{

perror("fopen");

return;

}

/*计算歌词文件的大小*/

fseek(fp, 0, 2);

long lrc_len = ftell(fp);

rewind(fp);

/*分配内存空间*/

*lrc_data = (char *)calloc(1, lrc_len);

if(*lrc_data == NULL)

{

perror("ralloc");

return;

}

/*将歌词读入内存*/

fread(*lrc_data, lrc_len, 1, fp);

/*关闭文件*/

fclose(fp);

return;

}

0x04 按行切割歌词文件

歌词切割应注意如下(百度百科):

27423283ba05c9f38a9ed071c0b7caf2.png

/*将歌词逐行分割*/

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;

}

0x05 逐行分析歌词头部

歌词头部信息格式(百度百科):

618454a58a7273a046f399e10f6f9428.png

由于头部信息比较简单,所以并不把头部信息存入链表,而是直接分析后显示:

/*分析歌词头部信息*/

int analysis_lrc_head(char **buf)

{

clear_screen();

cusor_moveto(0, 0);

set_fg_color(COLOR_GREEN);

/*逐行分析头部*/

int i = 0;

while(*(buf[i] + 1) > '0')/*解释歌词信息*/

{

/*读取头部信息内容*/

char lrc[128]="";

sscanf(buf[i],"%*[^:]:%[^]]", lrc);

/*读取头部信息标签*/

char tags[10] = "";

sscanf(buf[i], "[%[^:]", tags);

cusor_moveto(35, i+1);

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;

}

0x06 逐行分析歌词正文

对于歌词正文部分,要处理的有两个方面:一方面分析每句歌词前面的时间,另一方面,将根据前面的时间将歌词插入链表。

/*分析歌词正文部分*/

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;

}

0x07 模拟时钟

使用模拟时钟的目的是模拟实现歌曲播放与歌词同步,模拟时钟和歌曲播放器同时启动,然后根据模拟时钟的时间在歌词链表中查找。

8cd5c5321589db26c38dadd959259193.png

int i = 0;/*模拟计时器*/

while(1)

{

/*根据时间i到链表中查找,并且打印歌词*/

time_delay(1);

i++;

}

0x08 歌词滚屏、歌词反选

/*模拟时钟*/

int i = 0;/*模拟计时器*/

char show[5][128] = {"","","","",""};

while(1)

{

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值