diff --git a/lyric_analysis/srcs/includes/lrc.h b/lyric_analysis/srcs/includes/lrc.h index 301587a..4f62642 100644 --- a/lyric_analysis/srcs/includes/lrc.h +++ b/lyric_analysis/srcs/includes/lrc.h @@ -21,5 +21,8 @@ char *get_lrc_mem_data(FILE *fp); // 获取歌词文件内容 LRC *insert_lrc_node(LRC *head, LRC new_node); // 插入歌词节点 (尾插法) LRC *search_lrc_node(LRC *head, int 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 \ No newline at end of file diff --git a/lyric_analysis/srcs/lrc.c b/lyric_analysis/srcs/lrc.c index 3e461aa..c668a68 100644 --- a/lyric_analysis/srcs/lrc.c +++ b/lyric_analysis/srcs/lrc.c @@ -1,4 +1,6 @@ #include "./includes/lrc.h" +#include "./includes/console.h" +#include "./includes/time_delay.h" FILE *open_lrc_file(const char *lrc_path) { @@ -83,4 +85,121 @@ LRC *search_lrc_node(LRC *head, int time) p = p->next; // 指向下一个节点 } 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毫秒) + } } \ No newline at end of file diff --git a/lyric_analysis/srcs/main.c b/lyric_analysis/srcs/main.c index 65cb523..91d2c2b 100644 --- a/lyric_analysis/srcs/main.c +++ b/lyric_analysis/srcs/main.c @@ -10,14 +10,10 @@ int main() const char *lrc_path = "./lrcs/简单爱.lrc"; 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); - char *lrc_mem_data = get_lrc_mem_data(lrc_fp); // 获取歌词数据 - // mplayer_play(song_path); - // 逐行解析歌词 char *lrc_lines[200] = {NULL}; // 定义歌词行指针数组 int i = 0; // 定义歌词行数 @@ -31,120 +27,22 @@ int main() lrc_lines[i] = strtok(NULL, "\r\n"); // 将剩余行歌词数据按行分割 } - // 分析前 4 行歌词 int rows = i; // 获取歌词总行数 - 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; - default: - break; - } - } + handle_first_4_lines(lrc_lines); // 处理前 4 行歌词 - // 逐行分析剩下的歌词,将时间、歌词内容保存到链表中 - 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; // 跳过前面的时间标签 - } - } + // 保存歌词信息到链表 + LRC *head = NULL; // 定义链表头指针 + head = save_to_linklist(lrc_lines, rows); // 保存到链表s // 开始播放歌曲 mplayer_play(song_path); // 启动mplayer播放器,播放歌曲 - - // 逐行打印歌词 - 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毫秒) - } + // 逐行显示歌词 + show_lrcs(head); // 显示歌词 // 释放内存,关闭文件 free(lrc_mem_data); // 释放歌词数据内存 + free(head); // 释放链表内存 + fclose(lrc_fp); // 关闭歌词文件 return 0; } \ No newline at end of file