分析歌词文件,将时间+歌词 组成一个节点 ,插入有序链表中 、设计模拟时钟,如果模拟时钟的时间 和链表中节点的时间相匹配, 就打印该时间点的歌词。
1、将歌词文件 一次性去取到 内存中
a、用fopen打开歌词文件 FILE *fp = fopen(“简单爱.lrc”, “r”);
b、使用fseek将文件流指针 定位到文件尾部 获得文件总大小
c、使用rewind 复位文件流置针
d、根据文件总大小 从堆区 申请 合适的空间 char *arr
e、使用fread 读取文件数据 到内存中 arr
f、关闭文件
2、将arr指向的内存数据 按行"\r\n"切割 存入 字符指针数组 char *buf[128]={NULL};
已将歌词的每一行 存放 在 指针数组中 注意 记得保存 切割到的行数
3、逐行分析 buf[0]代表第0行 buf[n] 代表第n行
a、单独分析前4行
b、逐行分析剩下的行 将时间+歌词 一一对应 插入链表
建议:此处遍历一下链表
4、启动maplayer
5、模拟时钟
6、滚屏(5行)
//光标定位:(注意)
7、反显 当前歌词为 红色 其他歌词为黑色
在做之前还怀疑自己能不能做出来,可做的过程中按照流程、步骤,尽管编写代码的过程中总会出现BUG,方法永远比问题多,比如这样提取带空格的字符串,以及调用函数、传参、返回值的类型匹配问题,这样一路坎坷的过程,也是给学习和进步空间 创造了一个宝贵的机会,后面我还想再解析多首歌曲,由于时间的关系,就只添加了进度条。加油!!!
下面是整个项目的代码
为了编译方便,这里创建了一个makefile,这样就不用每次都gcc一堆 .C文件,只需要make,敲回车,就把包含所有的.c文件编译了,
./main运行程序。
这样也方便调试结果。
makefile
exec=main
cc=gcc
obj=main.o lrc.o start_mplayer.o console.o #你要修改的地方
cflags=-Wall -g
$(exec):$(obj)
$(cc) $^ -o $@ $(cflags)
%.o:%.c
$(cc) -c $< -o $@ $(cflags)
clean:
rm $(exec) *.o
main.c
/* ************************************************************************
* Filename: main.c
* Description:
* Version: 1.0
* Created: 2020年03月09日 20时00分02秒
* Revision: none
* Compiler: gcc
* Author: YOUR NAME (),
* Company:
* ************************************************************************/
#include
#include "lrc.h"
#include
#include"start_mplayer.h"
#include
int main(int argc, char *argv[])
{
char *arr=NULL;
LRC *head=NULL;
int i=0;
arr=get_lrc();//1、将歌词文件 一次性去取到内存中
char *buf[128]={NULL};//2、将arr指向的内存数据 按行"\r\n"切割
buf[i]=strtok(arr,"\r\n");
while(buf[i]!=NULL)
{
i++;
buf[i]=strtok(NULL,"\r\n");
}
int rows=i;//29行 保存行数
head = sscanf_lrc(buf,rows,head);//3、逐行分析 buf[0]代表第0行 buf[n]代表第n行
head = insert_4(buf,head);//链表插入前四行
//print_link(head);//遍历链表
mplayer_play("../music/简单爱.mp3");//4、启动mplayer
sim_clok(head);//5、模拟时钟并打印歌词
return 0;
}
lrc.c
/* ************************************************************************
* Filename: lrc.c
* Description:
* Version: 1.0
* Created: 2020年03月09日 20时01分14秒
* Revision: none
* Compiler: gcc
* Author: YOUR NAME (),
* Company:
* ************************************************************************/
#include
#include "lrc.h"
#include
#include
#include"console.h"
#include
char *get_lrc(void)
{
//a、用fopen打开歌词文件 FILE *fp = fopen("简单爱.lrc", "r");
FILE *fp = fopen("简单爱.lrc","r");
//b、使用fseek将文件流指针 定位到文件尾部 获得文件总大小
fseek(fp,0,2);
long len=0;
len=ftell(fp);
//c、使用rewind 复位文件流置针
rewind(fp);
//d、根据文件总大小 从堆区 申请 合适的空间 char *arr
char *arr=(char *)calloc(1,len+1);
if(arr==NULL)
{
perror("calloc");
return NULL;
}
//e、使用fread 读取文件数据 到内存中 arr
fread(arr,len,1,fp);
fclose(fp);
return arr;
}
LRC * sscanf_lrc(char *buf[],int rows,LRC *head)
{
int i=4;
//b、逐行分析剩下的行 将时间+歌词 一一对应 插入链表
for(i=4;i=50)
time +=1;
else
time = time;
tmp.time = time;//提取到的时间放入tmp.time
head = insert_link(head,tmp);//调用链表的有序插入函数
str_time += 10;
}
}
return head;
}
LRC * insert_4(char *buf[],LRC *head)
{
//a、单独分析前4行
int i=0;
char lrc_4[4][12]={""};
for(i=0;i<4;i++)
{
sscanf(buf[i],"%*[^:]:%[^]]",lrc_4[i]);
}
char name[4][16]={"歌名:","歌手:","专辑:","制作:"};
char tmp1[4][32]={""};
for(i=0;i<4;i++)
{
sprintf(tmp1[i],"%s%s",name[i],lrc_4[i]);
}
for(i=3;i>=0;i--)
{
LRC tmp;
strcpy(tmp.lrc,tmp1[i]);
LRC *pi = (LRC *)calloc(1, sizeof(LRC));
if (pi == NULL)
{
perror("calloc");
return head;
}
*pi = tmp;
pi->next = NULL;
if (head == NULL)
{
head = pi;
}
else
{
pi->next = head;
head = pi;
}
}
return head;
}
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
{
LRC *pb = head, *pf = head;
while((pb->time < pi->time) && (pb->next != NULL))
{
pf = pb;
pb = pb->next;
}
if (pb->time >= pi->time)
{
if (pb == head)//头部插入
{
pi->next = head;
head = pi;
return head;
}
else//中部插入
{
pf->next = pi;
pi->next = pb;
return head;
}
}
else//尾部插入
{
pb->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;
}
void sim_clok(LRC *head)
{
int time=0;
clear_screen();
while(1)
{
cusor_moveto(12, 3);
set_fg_color(COLOR_BLACK );
printf("%02d : %02d",time/60,time%60);
fflush(stdout);
print_lrc_with_music(head,time-1);//打印歌词
progres_bar(head,time);//打印进度条
sleep(1);
time++;
}
return ;
}
void print_lrc_with_music(LRC *head,int time)
{
LRC *pb=head ;
int row=0;
char buf1[128]="";
char buf2[128]="";
char buf3[128]="";
char buf4[128]="";
char buf5[128]="";
char buf6[128]="";
char buf7[128]="";
while(row<4)
{
cusor_moveto(30,2+row);
set_fg_color(COLOR_BLUE);
printf("%s\n",pb->lrc);
pb=pb->next;
row++;
}
while (pb->time != time && pb->next->next->next->next->next->next->next != NULL)
pb = pb->next;
if (pb->time == time)
{
strcpy(buf1,pb->lrc);
strcpy(buf2,pb->next->lrc);
strcpy(buf3,pb->next->next->lrc);
strcpy(buf4,pb->next->next->next->lrc);
strcpy(buf5,pb->next->next->next->next->lrc);
strcpy(buf6,pb->next->next->next->next->next->lrc);
strcpy(buf7,pb->next->next->next->next->next->next->lrc);
set_fg_color(COLOR_RED);
cusor_moveto(15,9);
printf("%s ",buf1);
set_fg_color(COLOR_BLACK);
cusor_moveto(15,10);
printf("%s ",buf2);
cusor_moveto(15,11);
printf("%s ",buf3);
cusor_moveto(15,12);
printf("%s ",buf4);
cusor_moveto(15,13);
printf("%s ",buf5);
cusor_moveto(15,14);
printf("%s ",buf6);
cusor_moveto(15,15);
printf("%s ",buf7);
fflush(stdout);
}
return ;
}
int s=0;
void progres_bar(LRC *head,int time)
{
LRC *pb=head;
while(pb->next!=NULL)
pb=pb->next;
int time1 = pb->time+20;
cusor_moveto(5,20);
set_fg_color(COLOR_YELLOW );
printf("%02d : %02d|",time/60,time%60);
cusor_moveto(60,20);
set_fg_color(COLOR_YELLOW );
printf("|%02d : %02d",time1/60,time1%60);
cusor_moveto(13,20);
set_fg_color(COLOR_GREEN);
printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");//47
int t=s-1;
cusor_moveto(13+t,20);
if(time==time1/45*s)
{
cusor_moveto(13+s,20);
s+=1;
}
}
lrc.h
/* ************************************************************************
* Filename: lrc.h
* Description:
* Version: 1.0
* Created: 2020年03月09日 20时02分25秒
* Revision: none
* Compiler: gcc
* Author: YOUR NAME (),
* Company:
* ************************************************************************/
#ifndef __LRC_H__
#define __LRC_H__
typedef struct lrc
{
int time;
char lrc[128];
struct lrc *next;
}LRC;
extern char *get_lrc(void);
extern LRC * sscanf_lrc(char *buf[],int rows,LRC *head);
extern LRC * insert_link(LRC *head, LRC tmp);
extern LRC * insert_4(char *buf[],LRC *head);
extern void print_link(LRC *head);
extern void sim_clok(LRC *head);
extern void print_lrc_with_music(LRC *head,int time);
extern void progres_bar(LRC *head,int time);
#endif
下面的是光标定位函数,和字体颜色设置还有启动mplayer 的函数
start_mplayer.c
#include
#include
#include
//启动mplayer播放器
//参数song_path 为歌曲的路径
void mplayer_play(char * song_path)
{
pid_t pid;
pid=fork();
if(pid<0)
{
perror("fork");
}
else if(pid==0)
{
close(1);
close(2);
execlp("mplayer","mplayer","-slave","-quiet",song_path,NULL);
exit(0);
}
else
;
}
start_mplayer.h
#ifndef __START_MPLAYER_H__
#define __START_MPLAYER_H__
//启动mplayer播放器
//参数song_path 为歌曲的路径
extern void mplayer_play(char * song_path);
#endif
console.c
#include
#include
#include "console.h"
void cusor_moveto(int x, int y)
{// ESC[y;xH
printf("\033[%d;%dH",y,x);
fflush(stdout);
}
//保存光标位置
void cusor_get_pos(void)
{// ESC[s
printf("\033[s");
fflush(stdout);
}
//恢复光标位置
void cusor_set_pos(void)
{// ESC[u
printf("\033[u");
fflush(stdout);
}
//隐藏光标
void cusor_hide(void)
{
printf("\033[?25l");
}
//显示光标
void cusor_show(void)
{
printf("\33[?25h");
}
//清屏
void clear_screen(void)
{// ESC[2J
printf("\033[2J");
fflush(stdout);
}
/*
COLOR_RED 红
COLOR_BLACK 黑
COLOR_GREEN 绿
COLOR_BLUE 蓝
COLOR_YELLOW 黄
COLOR_WHITE 白
COLOR_CYAN 青
COLOR_MAGENTA 洋红
*/
//设置前景颜色
void set_fg_color(int color)
{// ESC[#m
printf("\033[%dm",color);
fflush(stdout);
}
//设置背景颜色
void set_bg_color(int color)
{// ESC[#m
printf("\033[%dm",(color+10));
fflush(stdout);
}
console.h
#ifndef _CONSOLE_H_
#define _CONSOLE_H_
#define COLOR_RED 31
#define COLOR_BLACK 30
#define COLOR_GREEN 32
#define COLOR_BLUE 34
#define COLOR_YELLOW 33
#define COLOR_WHITE 37
#define COLOR_CYAN 36
#define COLOR_MAGENTA 35
/*
COLOR_RED 红
COLOR_BLACK 黑
COLOR_GREEN 绿
COLOR_BLUE 蓝
COLOR_YELLOW 黄
COLOR_WHITE 白
COLOR_CYAN 青
COLOR_MAGENTA 洋红
*/
extern void cusor_moveto(int x, int y);//光标跳转到 y行 x列
extern void cusor_get_pos(void);//保存光标位置
extern void cusor_hide(void);//隐藏光标
extern void cusor_show(void);//显示光标
extern void cusor_set_pos(void);//恢复光标位置
extern void clear_screen(void);//清屏
extern void set_fg_color(int color);//设置字体前景色
extern void set_bg_color(int color);//设置字体背景色
#endif //_CONSOLE_H_