歌词解析: 大致上能用了,还有时间对不上的bug
This commit is contained in:
parent
67c99a9e29
commit
3691ae713b
|
@ -21,5 +21,8 @@ char *get_lrc_mem_data(FILE *fp); // 获取歌词文件内容
|
||||||
LRC *insert_lrc_node(LRC *head, LRC new_node); // 插入歌词节点 (尾插法)
|
LRC *insert_lrc_node(LRC *head, LRC new_node); // 插入歌词节点 (尾插法)
|
||||||
LRC *search_lrc_node(LRC *head, int time); // 查找歌词节点 (根据时间点查找歌词节点)
|
LRC *search_lrc_node(LRC *head, int time); // 查找歌词节点 (根据时间点查找歌词节点)
|
||||||
// LRC *search_lrc_node(LRC *head, long time); // 查找歌词节点 (根据时间点查找歌词节点) (用于毫秒级延时)
|
// LRC *search_lrc_node(LRC *head, long time); // 查找歌词节点 (根据时间点查找歌词节点) (用于毫秒级延时)
|
||||||
|
void handle_first_4_lines(char *lrc_lines[]); // 处理前 4 行歌词
|
||||||
|
LRC *save_to_linklist(char *lrc_lines[], int rows); // 保存到链表
|
||||||
|
void show_lrcs(LRC *head); // 显示歌词
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -1,4 +1,6 @@
|
||||||
#include "./includes/lrc.h"
|
#include "./includes/lrc.h"
|
||||||
|
#include "./includes/console.h"
|
||||||
|
#include "./includes/time_delay.h"
|
||||||
|
|
||||||
FILE *open_lrc_file(const char *lrc_path)
|
FILE *open_lrc_file(const char *lrc_path)
|
||||||
{
|
{
|
||||||
|
@ -84,3 +86,120 @@ LRC *search_lrc_node(LRC *head, int time)
|
||||||
}
|
}
|
||||||
return NULL; // 没有找到指定时间点的歌词
|
return NULL; // 没有找到指定时间点的歌词
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handle_first_4_lines(char *lrc_lines[])
|
||||||
|
{
|
||||||
|
clear_screen(); // 清屏
|
||||||
|
cusor_hide(); // 隐藏光标
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
char tmp[200] = ""; // 定义临时字符串
|
||||||
|
sscanf(lrc_lines[i], "%*[^:]:%[^]]", tmp); // 从歌词行中提取时间信息, "%*[^:]:%[^]]" 表示跳过第一个冒号,然后读取到第一个右中括号为止的内容
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
cusor_moveto(25, 2); // 将光标移动到指定位置
|
||||||
|
printf("歌曲: %s\n", tmp);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
cusor_moveto(25, 3); // 将光标移动到指定位置
|
||||||
|
printf("歌手: %s\n", tmp);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
cusor_moveto(25, 4); // 将光标移动到指定位置
|
||||||
|
printf("专辑: %s\n", tmp);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
cusor_moveto(25, 5); // 将光标移动到指定位置
|
||||||
|
printf("制作: %s\n", tmp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存到链表
|
||||||
|
LRC *save_to_linklist(char *lrc_lines[], int rows)
|
||||||
|
{
|
||||||
|
// 逐行分析剩下的歌词,将时间、歌词内容保存到链表中
|
||||||
|
LRC *head = NULL; // 定义歌词链表头指针
|
||||||
|
for (int i = 4; i < rows; i++)
|
||||||
|
{
|
||||||
|
char *str_lrc = lrc_lines[i]; // 获取歌词行
|
||||||
|
while (*str_lrc == '[') // 每当遇到'['时,就跳过
|
||||||
|
str_lrc += 10; // 跳过前面的时间标签
|
||||||
|
char *str_time = lrc_lines[i]; // 获取歌词行
|
||||||
|
while (*str_time == '[')
|
||||||
|
{
|
||||||
|
//秒级计数
|
||||||
|
int m = 0, s = 0; // 定义分钟和秒数
|
||||||
|
sscanf(str_time, "[%d:%d.%*d]", &m, &s); // 从歌词行中提取时间信息
|
||||||
|
int time = m * 60 + s; // 计算歌词时间点
|
||||||
|
|
||||||
|
// // 毫秒级计数 (这里有问题,待解决)
|
||||||
|
// int m = 0, s = 0, ms = 0; // 定义分钟和秒数和毫秒数
|
||||||
|
// sscanf(str_time, "[%d:%d.%d]", &m, &s, &ms); // 从歌词行中提取时间信息
|
||||||
|
// int time = (m * 60 + s) * 1000 + ms; // 计算歌词时间点: 毫秒数转换为秒数, 1000ms = 1s
|
||||||
|
|
||||||
|
LRC tmp;
|
||||||
|
tmp.time = time; // 保存歌词时间点
|
||||||
|
strcpy(tmp.lrc_buf, str_lrc); // 保存歌词内容
|
||||||
|
tmp.lrc_cur_num = i; // 保存当前歌词行数
|
||||||
|
head = insert_lrc_node(head, tmp); // 将歌词节点插入到链表中
|
||||||
|
str_time += 10; // 跳过前面的时间标签
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return head; // 返回链表头指针
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_lrcs(LRC *head)
|
||||||
|
{
|
||||||
|
|
||||||
|
// 逐行打印歌词
|
||||||
|
int t = 0;
|
||||||
|
// long t = 0; // 用于毫秒级延时
|
||||||
|
char buf1[200] = "";
|
||||||
|
char buf2[200] = "";
|
||||||
|
char buf3[200] = "";
|
||||||
|
char buf4[200] = "";
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
set_fg_color(COLOR_BLUE); // 设置前景颜色为红色
|
||||||
|
cusor_moveto(29, 7); // 将光标移动到指定位置
|
||||||
|
printf("%02d:%02d", t / 60, t % 60); // 打印歌曲播放时间
|
||||||
|
// 打印歌曲播放时间 (毫秒级延时)
|
||||||
|
// printf("%02d:%02d", t / (60 * 1000), (t / 1000) % 60);
|
||||||
|
fflush(stdout); // 刷新输出缓冲区,立即输出
|
||||||
|
LRC *ret = search_lrc_node(head, t); // 查找歌词节点
|
||||||
|
if (ret != NULL) // 如果找到歌词节点
|
||||||
|
{
|
||||||
|
// 用于歌词滚动轮换
|
||||||
|
strcpy(buf1, buf2); // 将buf2中的内容复制到buf1中
|
||||||
|
strcpy(buf2, buf3); // 将buf3中的内容复制到buf2中
|
||||||
|
strcpy(buf3, buf4); // 将buf4中的内容复制到buf3中
|
||||||
|
strcpy(buf4, ret->lrc_buf); // 将歌词内容复制到buf4中
|
||||||
|
|
||||||
|
cusor_moveto(17, 9); // 将光标移动到指定位置
|
||||||
|
printf("\033[K"); // 清除从光标到行尾的内容
|
||||||
|
printf("%s", buf1); // 打印歌词内容
|
||||||
|
|
||||||
|
cusor_moveto(17, 10); // 将光标移动到指定位置
|
||||||
|
printf("\033[K"); // 清除从光标到行尾的内容
|
||||||
|
printf("%s", buf2); // 打印歌词内容
|
||||||
|
|
||||||
|
cusor_moveto(17, 11); // 将光标移动到指定位置
|
||||||
|
printf("\033[K"); // 清除从光标到行尾的内容
|
||||||
|
printf("%s", buf3); // 打印歌词内容
|
||||||
|
|
||||||
|
set_fg_color(COLOR_RED); // 设置红色前景色
|
||||||
|
cusor_moveto(17, 12); // 将光标移动到指定位置
|
||||||
|
printf("\033[K"); // 清除从光标到行尾的内容
|
||||||
|
printf("%s", buf4); // 打印歌词内容
|
||||||
|
set_fg_color(COLOR_BLUE);
|
||||||
|
fflush(stdout); // 刷新输出缓冲区,立即输出
|
||||||
|
}
|
||||||
|
time_delay(1); // 延时1秒
|
||||||
|
t++; // 时间加1
|
||||||
|
// delay_ms(1); // 延时1毫秒 (毫秒级延时)
|
||||||
|
// t += 1000; // 时间加1 (1毫秒)
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,14 +10,10 @@ int main()
|
||||||
const char *lrc_path = "./lrcs/简单爱.lrc";
|
const char *lrc_path = "./lrcs/简单爱.lrc";
|
||||||
|
|
||||||
FILE *lrc_fp = open_lrc_file(lrc_path); // 打开歌词文件
|
FILE *lrc_fp = open_lrc_file(lrc_path); // 打开歌词文件
|
||||||
|
|
||||||
long lrc_size = get_lrc_size(lrc_fp); // 获取并打印歌词文件大小
|
long lrc_size = get_lrc_size(lrc_fp); // 获取并打印歌词文件大小
|
||||||
// printf("歌词大小为: %ld Byte\n", lrc_size);
|
// printf("歌词大小为: %ld Byte\n", lrc_size);
|
||||||
|
|
||||||
char *lrc_mem_data = get_lrc_mem_data(lrc_fp); // 获取歌词数据
|
char *lrc_mem_data = get_lrc_mem_data(lrc_fp); // 获取歌词数据
|
||||||
|
|
||||||
// mplayer_play(song_path);
|
|
||||||
|
|
||||||
// 逐行解析歌词
|
// 逐行解析歌词
|
||||||
char *lrc_lines[200] = {NULL}; // 定义歌词行指针数组
|
char *lrc_lines[200] = {NULL}; // 定义歌词行指针数组
|
||||||
int i = 0; // 定义歌词行数
|
int i = 0; // 定义歌词行数
|
||||||
|
@ -31,120 +27,22 @@ int main()
|
||||||
lrc_lines[i] = strtok(NULL, "\r\n"); // 将剩余行歌词数据按行分割
|
lrc_lines[i] = strtok(NULL, "\r\n"); // 将剩余行歌词数据按行分割
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分析前 4 行歌词
|
|
||||||
int rows = i; // 获取歌词总行数
|
int rows = i; // 获取歌词总行数
|
||||||
|
|
||||||
clear_screen(); // 清屏
|
handle_first_4_lines(lrc_lines); // 处理前 4 行歌词
|
||||||
cusor_hide(); // 隐藏光标
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
{
|
|
||||||
char tmp[200] = ""; // 定义临时字符串
|
|
||||||
sscanf(lrc_lines[i], "%*[^:]:%[^]]", tmp); // 从歌词行中提取时间信息, "%*[^:]:%[^]]" 表示跳过第一个冒号,然后读取到第一个右中括号为止的内容
|
|
||||||
switch (i)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
cusor_moveto(25, 2); // 将光标移动到指定位置
|
|
||||||
printf("歌曲: %s\n", tmp);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
cusor_moveto(25, 3); // 将光标移动到指定位置
|
|
||||||
printf("歌手: %s\n", tmp);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
cusor_moveto(25, 4); // 将光标移动到指定位置
|
|
||||||
printf("专辑: %s\n", tmp);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
cusor_moveto(25, 5); // 将光标移动到指定位置
|
|
||||||
printf("制作: %s\n", tmp);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 逐行分析剩下的歌词,将时间、歌词内容保存到链表中
|
// 保存歌词信息到链表
|
||||||
LRC *head = NULL; // 定义歌词链表头指针
|
LRC *head = NULL; // 定义链表头指针
|
||||||
for (int i = 4; i < rows; i++)
|
head = save_to_linklist(lrc_lines, rows); // 保存到链表s
|
||||||
{
|
|
||||||
char *str_lrc = lrc_lines[i]; // 获取歌词行
|
|
||||||
while (*str_lrc == '[') // 每当遇到'['时,就跳过
|
|
||||||
str_lrc += 10; // 跳过前面的时间标签
|
|
||||||
char *str_time = lrc_lines[i]; // 获取歌词行
|
|
||||||
while (*str_time == '[')
|
|
||||||
{
|
|
||||||
//秒级计数
|
|
||||||
int m = 0, s = 0; // 定义分钟和秒数
|
|
||||||
sscanf(str_time, "[%d:%d.%*d]", &m, &s); // 从歌词行中提取时间信息
|
|
||||||
int time = m * 60 + s; // 计算歌词时间点
|
|
||||||
|
|
||||||
// // 毫秒级计数 (这里有问题,待解决)
|
|
||||||
// int m = 0, s = 0, ms = 0; // 定义分钟和秒数和毫秒数
|
|
||||||
// sscanf(str_time, "[%d:%d.%d]", &m, &s, &ms); // 从歌词行中提取时间信息
|
|
||||||
// int time = (m * 60 + s) * 1000 + ms; // 计算歌词时间点: 毫秒数转换为秒数, 1000ms = 1s
|
|
||||||
|
|
||||||
LRC tmp;
|
|
||||||
tmp.time = time; // 保存歌词时间点
|
|
||||||
strcpy(tmp.lrc_buf, str_lrc); // 保存歌词内容
|
|
||||||
tmp.lrc_cur_num = i; // 保存当前歌词行数
|
|
||||||
head = insert_lrc_node(head, tmp); // 将歌词节点插入到链表中
|
|
||||||
str_time += 10; // 跳过前面的时间标签
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 开始播放歌曲
|
// 开始播放歌曲
|
||||||
mplayer_play(song_path); // 启动mplayer播放器,播放歌曲
|
mplayer_play(song_path); // 启动mplayer播放器,播放歌曲
|
||||||
|
// 逐行显示歌词
|
||||||
// 逐行打印歌词
|
show_lrcs(head); // 显示歌词
|
||||||
int t = 0;
|
|
||||||
// long t = 0; // 用于毫秒级延时
|
|
||||||
char buf1[200] = "";
|
|
||||||
char buf2[200] = "";
|
|
||||||
char buf3[200] = "";
|
|
||||||
char buf4[200] = "";
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
set_fg_color(COLOR_BLUE); // 设置前景颜色为红色
|
|
||||||
cusor_moveto(29, 7); // 将光标移动到指定位置
|
|
||||||
printf("%02d:%02d", t / 60, t % 60); // 打印歌曲播放时间
|
|
||||||
// 打印歌曲播放时间 (毫秒级延时)
|
|
||||||
// printf("%02d:%02d", t / (60 * 1000), (t / 1000) % 60);
|
|
||||||
fflush(stdout); // 刷新输出缓冲区,立即输出
|
|
||||||
LRC *ret = search_lrc_node(head, t); // 查找歌词节点
|
|
||||||
if (ret != NULL) // 如果找到歌词节点
|
|
||||||
{
|
|
||||||
// 用于歌词滚动轮换
|
|
||||||
strcpy(buf1, buf2); // 将buf2中的内容复制到buf1中
|
|
||||||
strcpy(buf2, buf3); // 将buf3中的内容复制到buf2中
|
|
||||||
strcpy(buf3, buf4); // 将buf4中的内容复制到buf3中
|
|
||||||
strcpy(buf4, ret->lrc_buf); // 将歌词内容复制到buf4中
|
|
||||||
|
|
||||||
cusor_moveto(17, 9); // 将光标移动到指定位置
|
|
||||||
printf("\033[K"); // 清除从光标到行尾的内容
|
|
||||||
printf("%s", buf1); // 打印歌词内容
|
|
||||||
|
|
||||||
cusor_moveto(17, 10); // 将光标移动到指定位置
|
|
||||||
printf("\033[K"); // 清除从光标到行尾的内容
|
|
||||||
printf("%s", buf2); // 打印歌词内容
|
|
||||||
|
|
||||||
cusor_moveto(17, 11); // 将光标移动到指定位置
|
|
||||||
printf("\033[K"); // 清除从光标到行尾的内容
|
|
||||||
printf("%s", buf3); // 打印歌词内容
|
|
||||||
|
|
||||||
set_fg_color(COLOR_RED); // 设置红色前景色
|
|
||||||
cusor_moveto(17, 12); // 将光标移动到指定位置
|
|
||||||
printf("\033[K"); // 清除从光标到行尾的内容
|
|
||||||
printf("%s", buf4); // 打印歌词内容
|
|
||||||
set_fg_color(COLOR_BLUE);
|
|
||||||
fflush(stdout); // 刷新输出缓冲区,立即输出
|
|
||||||
}
|
|
||||||
time_delay(1); // 延时1秒
|
|
||||||
t++; // 时间加1
|
|
||||||
// delay_ms(1); // 延时1毫秒 (毫秒级延时)
|
|
||||||
// t += 1000; // 时间加1 (1毫秒)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 释放内存,关闭文件
|
// 释放内存,关闭文件
|
||||||
free(lrc_mem_data); // 释放歌词数据内存
|
free(lrc_mem_data); // 释放歌词数据内存
|
||||||
|
free(head); // 释放链表内存
|
||||||
|
fclose(lrc_fp); // 关闭歌词文件
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
Loading…
Reference in New Issue