// main.c
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
struct lrc
{ // 定义一个链表串起时间和歌词
int time; // 时间
char lrc_buf[200]; // 歌词
int lrc_num; // 第几句歌词
struct lrc *next; // 链表的指针
};
typedef struct lrc LRC; // 结构体重定义
extern char *open_file(); // 打开文件函数
extern int strtok_deal(char *f, char **song_line); // 歌词切割函数
extern void four_deal(char **song_line, char *four[50]); // 对于前四行特殊处理
extern LRC *init(); // 确定链表头指针
extern void insert(LRC *p, LRC **head);
extern LRC *divide_deal(char **song_line, int n); // 分开时间与歌词
extern void time_delay(int sec); // 时间延迟
extern void set_fg_color(int color); // 设置前景颜色
extern void clear_screen(void); // 清屏函数
extern void set_bg_color(int color); // 设置背景颜色
extern void song_print(LRC *head, char **four); // 歌词打印+效果
char *open_file()
{
FILE *fp;
fp = fopen("../简单爱.lrc", "rb");
if (fp == NULL)
{
printf("NULL!\n");
return 0;
}
fseek(fp, 0L, SEEK_END); // 光标定位
int len = ftell(fp); // 读取字节以便申请空间
rewind(fp);
char *f = (char *)malloc(len);
fread(f, len, 1, fp); // 读取
return f;
}
int strtok_deal(char *f, char **song_line)
{
char *temp = NULL;
int k = 0;
temp = strtok(f, "\r\n"); // 遇‘\r''\n'切割
while (temp)
{
song_line[k++] = temp; // 每行读入
temp = strtok(NULL, "\r\n");
}
return k;
}
void four_deal(char **song_line, char *four[50])
{
int i;
for (i = 0; i < 4; i++)
{
char *temp = strtok(song_line[i], "[]"); // 遇'[]'的切割
four[i] = temp;
}
}
LRC *init()
{
LRC *p = (LRC *)malloc(sizeof(LRC));
p = NULL;
p->next = NULL;
return p;
}
void insert(LRC *p, LRC **head)
{ // 一边构建链表一边排序(对链表要求较高)
if (*head == NULL)
{
*head = p;
return;
}
LRC *temp = *head, *mid = *head;
while (temp->next && temp->time < p->time)
{
mid = temp;
temp = temp->next;
}
if (temp->time >= p->time)
{
p->next = temp;
mid->next = p;
return;
}
else
{
temp->next = p;
p->next = NULL;
return;
}
}
LRC *divide_deal(char **song_line, int n)
{
char song[100][100], mid[100][100] = {0};
char *temp;
LRC *head = NULL;
int k = 0, i, m = 0, q = 0;
for (i = 0; i < n; i++)
{
temp = strtok(song_line[i], "[]");
while (temp)
{
strcpy(mid[k++], temp);
temp = strtok(NULL, "[]");
}
}
for (i = 0; i < k; i++)
{
if (!isdigit(mid[i][0]))
{
strcpy(song[q++], mid[i]);
}
}
int j = 0;
for (i = 0; i < k; i++)
{
if (isdigit(*mid[i]))
{
char hh[5], mm[5], ss[5];
LRC *p = (LRC *)malloc(sizeof(LRC));
p->time = sscanf(mid[i], "%2s:%2s.%2s", hh, mm, ss);
// 这种格式可以让时间以标准形式输出
p->time = atoi(hh) * 60 + atoi(mm);
// 将时间转化为秒存储到链表中
p->lrc_num = ++m;
strcpy(p->lrc_buf, song[j]);
insert(p, &head); // 找准时机,插入链表
}
else
j++;
}
return head;
}
void time_delay(int sec)
{
int s_time, e_time;
s_time = time(NULL);
while (1)
{
e_time = time(NULL);
if (e_time == s_time + sec)
break;
}
}
void clear_screen(void)
{
printf("\033[2J");
fflush(stdout);
}
void set_fg_color(int color)
{
printf("\033[%dm", color);
fflush(stdout);
}
void set_bg_color(int color)
{
printf("\033[%dm", (color + 10));
fflush(stdout);
}
void cusor_moveto(int x, int y)
{
printf("\033[%d;%dH", y, x);
fflush(stdout);
}
/*// 函数名:song_print
// 参数:
// - head: LRC结构体指针,指向歌曲链表的头部
// - four: 字符串数组指针,包含要打印的歌曲信息
// 返回值:无*/
void song_print(LRC *head, char **four)
{
int num = 0, y = 0; // 初始化歌曲编号和纵坐标
LRC *p_mov = head; // 指向当前歌曲的指针
LRC *p_mov2; // 用于遍历歌曲链表的临时指针
LRC *p_mov_front = head, *p_mov_front2; // 指向链表中的前一个和当前歌曲的指针
int i, flag = 0; // 循环计数器和标志位
while (1)
{ // 无限循环,直到链表结束或打印完所有歌曲的信息
clear_screen(); // 清空屏幕
y = 1;// 设置纵坐标为1,表示第一行开始打印歌词
for (i = 0; i < 4; i++)// 打印歌手、歌曲名、时长和歌词信息
{
cusor_moveto(34, y++);// 移动光标到第i行的起始位置
printf("\t\t\t\t\t%s\n", four[i]);// 打印字符串元素
}
cusor_moveto(34, y++);// 移动光标到第5行的起始位置,准备打印下一行的时间信息
printf("\t\t\t\t\t %02d:%02d\n", num / 60, num % 60); // 打印时间信息(分钟:秒)
if (flag < 4)// 如果还没有打印完四行信息,则将指针移动到链表头部
p_mov_front = head;
if (num == p_mov->time)// 如果当前歌曲的时间与上一首歌相同,则继续遍历下一首
{
p_mov = p_mov->next;// 移动指针到下一首歌
flag++;// 标记已经遍历了一首新歌
if (flag > 4)// 如果已经遍历了四首新歌,则将指针移动回链表头部,以便重新开始遍历
p_mov_front = p_mov_front->next;
}
p_mov2 = p_mov;// 保存当前歌曲的指针,以备后面遍历时使用
p_mov_front2 = p_mov_front;// 保存前一个歌曲的指针,以备后面遍历时使用
while (p_mov_front2 != p_mov)// 遍历链表中的所有歌曲,并打印出每首歌曲的歌词
{
cusor_moveto(60, y++);// 移动光标到歌词行的起始位置,准备打印歌词内容
printf("\t%s\n", p_mov_front2->lrc_buf);// 打印歌词内容(假设为字符串)
p_mov_front2 = p_mov_front2->next;// 移动指针到下一首歌词所在的歌曲
}
for (i = 0; i < 5; i++)// 如果还有更多的歌曲需要打印,则继续遍历并打印歌词
{
if (i == 0)// 设置前景色和背景色,以便区分不同歌曲的歌词显示效果
{
set_fg_color(31);// 设置前景色为蓝色(31)
set_bg_color(30);// 设置背景色为黑色(30)
}
else
{
set_fg_color(37); // 设置前景色为白色(37)
set_bg_color(30);// 设置背景色为黑色(30)
}
if (p_mov2 != NULL)
{
cusor_moveto(60, y++); // 光标控制
printf("\t%s\n", p_mov2->lrc_buf);
p_mov2 = p_mov2->next;
}
}
if (p_mov == NULL)
break;
time_delay(1);
num++;
}
}
// void playMusic(char* musicFilename) {
// char command[100];
// sprintf(command, "mplayer %s", musicFilename);
// system(command);
// }
void mplayer_play(char *mplayer_play)
{
pid_t pid;
pid = fork();
if (pid < 0)
{
perror("fork");
}
else if (pid == 0)
{
close(1);
close(2);
execlp("mplayer", "mplayer", "-slave", "-quiet", mplayer_play, NULL);
exit(0);
}
else
{
return;
}
}
int main()
{
char *temp = NULL;
char *song_line[100];
int line_num, i;
char *four[50];
temp = open_file(); // open_file 打开文件
LRC *head = NULL;
line_num = strtok_deal(temp, song_line); // hang_strtok
four_deal(song_line, four);
line_num -= 4;
for (i = 0; i < line_num; i++)
{
song_line[i] = song_line[i + 4];
}
head = divide_deal(song_line, line_num);
mplayer_play("../简单爱.mp3");
song_print(head, four);
return 0;
}
Linux中c语言歌词解析
最新推荐文章于 2023-10-29 20:51:04 发布