概述
实现功能:歌词对应,歌词滚屏显示,歌词总时长,多首歌曲选择播放,进度条(附加动画)
成果演示:代码
主函数代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include"start_mplayer/start_mplayer.h"
#include"fun/fun.h"
#include "fun/console.h"
int main(int argc, char const *argv[])
{
while (1)
{
int sim_time = 0;//模拟时钟时间
unsigned long lrc_length = 0;//歌词总长度
char *ret = NULL;//存放所有歌词的地址
char *str[128]={NULL} ;//分行后的歌词地址数组
int line = 0,rea_line = 0;//line为切割分的歌词行数,rea_line 为歌词总时长
LRC *head = NULL;//链表头
char cmd[16]="";//存放指令
char song[32]="";//歌词名
//提示并输入歌曲
clear_screen();
cusor_show();
cusor_moveto(5,15);
printf("歌库现存:简单爱 只因你太美 野狼 雾里看花 烤面筋 Lemon 大花轿n");//自己添加歌曲
cusor_moveto(5,16);
printf("Please choose the song you want to listen to:n ");
cusor_moveto(5,17);
scanf("%s",song);
//获取歌词
ret = get_lrc(&lrc_length,ret,song);
if (NULL == ret)
{
cusor_moveto(20,19);
printf("该歌曲尚未收录!!!n");
cusor_moveto(20,20);
printf("拜拜了宝贝T.Tn");
sleep(2);
cusor_moveto(20,20);
printf("真的要退出了呢 n");
sleep(2);
cusor_moveto(20,20);
printf("退出成功!!!T.T n");
sleep(2);
clear_screen();
cusor_show();
return 0;
}
//printf("lrc_length=%lu,%pn",lrc_length,ret);
//歌词分行
line = cut_lrc(ret,str);
//printf("%d",line);
//歌词存放
head = save_lrc(head,str,line);
rea_line = print_link(head);//获取歌词时长
//printf("%d",rea_line);
//播放歌曲
mplayer_play(song);
//启动模拟时钟,进行输出
sim_clock(head,str,sim_time,rea_line);
//放完一首歌,进行人机交互
cusor_moveto(20,23);
printf("Do you want to keep listening?yes or non");
cusor_moveto(20,24);
scanf("%s",cmd);
if (strcmp(cmd,"no")==0)
{
break;
}
else if (strcmp(cmd,"yes")==0)
{
continue;
}
else
{
printf("I don't know,I'm going to default to yes!n");
}
free(*str);
}
return 0;
}
功能函数:
包括获取歌词,将歌词分行,每句歌词存进链表节点,模拟时钟,查找对应时间的歌词
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include <math.h>
#include"fun.h"
#include "console.h"
因为这里是将歌词放在了一个子文件夹song里,所以获取歌词时候要注意文件地址
/**********************获取歌词******************/
char * get_lrc(unsigned long *length,char *data,char *path)
{
char buf[32]="";
sprintf(buf,"./song/%s.lrc",path);
FILE *fp = NULL;
fp = fopen(buf,"r");
if (NULL == fp)
return NULL;
sscanf(buf,"%[^lrc]",path);
/**********************获取文件长度******************/
fseek(fp,0,2);//流指针指到末尾
*length = ftell(fp);//获取长度
rewind(fp);//指针复位
//申请堆区空间
data = (char *)calloc(1,*length);
if (NULL == data)
{
perror("calloc");
return NULL ;
}
//一次性读取内容
fread(data,*length,1,fp);
//关闭文件
fclose(fp);
return data;
}
strtok函数切割歌词
/**********************歌词分行******************/
int cut_lrc(char *buf,char **str)
{
int i = 0;
//第一次切割
str[i] = strtok(buf, "rn");
//第2~n切割
while(str[i] != NULL)//保证上一次切割正常 才有进行下一次切割的必要
{
i++;
str[i] = strtok(NULL,"rn");
//while(str[i++] = strtok(str[i],"rn"));
}
return i;
}
/**********************歌词存放******************/
/**********************前四行*******************/
void save_lrc_four(char **str)
{
int i = 0;
char tmp[32]="",name[32]="";
for(i=0;i<4;i++)
{
sscanf(str[i],"[%[^:]:%[^]]",tmp,name);
if (strcmp(tmp,"ti") == 0)
{
set_fg_color(COLOR_BLUE);
cusor_moveto(45, 2);
printf("歌名:%sn",name);
}
else if (strcmp(tmp,"ar") == 0)
{
cusor_moveto(45, 3);
printf("歌手:%sn",name);
}
else if (strcmp(tmp,"al") == 0)
{
cusor_moveto(45, 4);
printf("专辑:%sn",name);
}
else if (strcmp(tmp,"by") == 0)
{
cusor_moveto(45, 5);
printf("来自:%sn",name);
}
}
return;
}
/**********************歌词内容存放******************/
LRC * save_lrc(LRC *head,char **str,int n)
{
LRC pb;
int i = 0;
//歌词输出
for ( i = 4; i < n; i++)
{
char *str_lrc = str[i];
//指向歌词位置
while('[' == *str_lrc)
str_lrc += 10;
//时间用s为单位
char *str_time = str[i];
while ('[' == *str_time)
{
int min = 0,sec = 0,time = 0;
sscanf(str_time,"[%d:%d:%*d]",&min,&sec);
time = min*60+sec;
//printf("%dn",time);
//时间,歌词一一对应插入链表节点
pb.time = time;
strcpy(pb.lrc,str_lrc);
//有序插入
head = insert_link(head,pb);
str_time += 10;
}
}
return head;
}
有序插入的方法将歌词放入链表储存
/**********************有序插入******************/
LRC * insert_link(LRC *head,LRC pb)
{
LRC *pi = (LRC *)calloc(1,sizeof(LRC));
if (NULL ==pi)
{
perror("calloc");
return head;
}
//pb赋值给pi
*pi = pb;
pi->next = NULL;
if (NULL == head)
{
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;
}
}
}
查找与时间对应的歌词
/**********************查找节点******************/
LRC* search_link(LRC *head, int time)
{
//1、判断链表是否存在
if(head == NULL)//不存在
{
printf("link not foundn");
return NULL;
}
else//链表存在
{
LRC *pb = head;
//逐个将节点中的time 和 time比较 如果不相等 pb=pb->next
while(pb->time != time && pb->next != NULL)
pb = pb->next;
//判断是否找到
if(pb->time == time)//找到
return pb;
else//没找到
return NULL;
}
return NULL;
}
创建一个模拟时钟,模拟时间变化,得到时间寻找歌词
/**********************模拟时钟******************/
void sim_clock(LRC *head,char **str,int time,int end)
{
LRC *ret = NULL;
char buf[12][128]={""};
int n=5, x, y;
char prb[31]="******************************";//30个*
int s = 0;
clear_screen();
cusor_moveto(0,5);
save_lrc_four(str);
while(1)
{
/**********************大风车啊吱悠悠的转******************/
if (time %2 == 0)
{
cusor_moveto(0,3);
for (y = 2 * n + 1; y >= -2 * n - 1; y--)
{
for (x = -2 * n - 1; x <= 2 * n + 1; x++)
{
if (x == 0 && y == 0)putchar(' ');
else if (abs(x) + abs(y) <= 2 * n + 1 && (x==0||y==0||(double)y/x>fabs((double)y/x)/((double)y/x)))putchar('*');
else putchar(' ');
}
putchar('n');
}
}
else
{
cusor_moveto(0,3);
for (x = 2 * n + 1; x >= -2 * n - 1; x--)
{
for (y = -2 * n - 1; y <= 2 * n + 1; y++)
{
if (y == 0 && x == 0)putchar(' ');
else if (abs(y) + abs(x) <= 2 * n + 1 && (x==0||y==0||(double)y/x>fabs((double)y/x)/((double)y/x)))putchar('*');
else putchar(' ');
}
putchar('n');
}
}
save_lrc_four(str);//输出四个歌头
cusor_hide();//隐藏光标
/**********************时间******************/
cusor_moveto(29,20);//移动到20行29列
printf("%02d:%02d",time/60,time%60);
/**********************进度条******************/
s=time*sizeof(prb)/end;//end歌曲总长度
prb[s]='>';//*变>
printf("|%s |",prb);//进度条
/**********************歌曲总时长******************/
cusor_moveto(68,20);//移动到20行66列
printf("%02d:%02d",end/60,end%60);
fflush(stdout);
/**********************查找时间对应歌词输出******************/
ret = search_link(head,time);//查找歌词
if (NULL != ret)
{
int i =0;
for(i=0;i<11;i++)
{
strcpy(buf[i],buf[i+1]);
}
strcpy(buf[11],ret->lrc);
for ( i = 0; i < 11; i++)
{
cusor_moveto(36,7+i);
printf("%s ",buf[i]);
}
cusor_moveto(36,18);
set_fg_color(COLOR_RED);
printf("%s ",buf[11]);
set_fg_color(COLOR_BLUE);
fflush(stdout);
if (ret->next==NULL)
{
sleep(5);
break;
}
}
sleep(1);
time++;
}
return;
}
得到歌词的最后一句对应的时间,看做最终时间,但是误差较大
/**********************遍历节点******************/
int print_link(LRC *head)
{
int i = 0;
if(head == NULL)//链表不存在
{
printf("link not findn");
return 0;
}
else
{
LRC *pb = head;
while(pb != NULL)
{
i=pb->time;
//pb指向下一个节点
pb = pb->next;
}
}
return i+5;
}
功能函数库
#ifndef __FUN_H__
#define __FUN_H__
typedef struct lrc
{
int time;
char lrc[128];
struct lrc *next;
}LRC;
extern void sim_clock(LRC *head,char **str,int time,int end);//模拟时钟 参数time 为模拟时钟时间
extern char * get_lrc(unsigned long *length,char *data,char *path);//获取歌词 参数length 为文件长度 data 为文件内容 返回存文件字符串的空间地址
extern int cut_lrc(char *buf,char **str);//分割歌词 参数buf 为文件内容 str 为切割后的文件
extern LRC * save_lrc(LRC *head,char **str,int n);//保存歌词
extern void save_lrc_four(char **str);//歌头内容
extern LRC * insert_link(LRC *head,LRC pb);//有序插入
extern LRC* search_link(LRC *head, int time);//查找链表
extern int print_link(LRC *head);//遍历链表
#endif
光标定位及颜色改变代码
#include <stdio.h>
#include <stdlib.h>
#include "console.h"
void cusor_moveto(int x, int y)
{// ESC[y;xH
printf("