【课程设计】歌词解析项目

00. 目录

01. 项目简介

1.1 项目演示
在这里插入图片描述

1.2 涉及到技术点

  • 文件操作

  • 链表

  • 字符串处理

  • 函数封装

  • VT码

02. 环境部署(省略)

2.1 查看系统是否支持mplayer命令

deng@local:~/share/project/lrc_linux$ mplayer

Command 'mplayer' not found, but can be installed with:

sudo apt install mplayer

2.2 安装mplayer软件

deng@local:~/share/project/lrc_linux$ sudo apt install mplayer

2.3 查看mplayer是否安装成功

deng@local:~/share/project/lrc_linux$ mplayer --help
Usage:   mplayer [options] [url|path/]filename

03. LRC格式(了解)

3.1 LRC概述

lrc是英文lyric(歌词)的缩写,被用做歌词文件的扩展名。以lrc为扩展名的歌词文件可以在各类数码播放器中同步显示。LRC 歌词是一种包含着“:”形式的“标签(tag)”的、基于纯文本的歌词专用格式。最早由郭祥祥先生(Djohan)提出并在其程序中得到应用。这种歌词文件既可以用来实现卡拉OK功能(需要专门程序),又能以普通的文字处理软件查看、编辑。当然,实际操作时通常是用专门的LRC歌词编辑软件进行高效编辑的。

3.2 LRC格式

1、标准格式: [分钟:秒.毫秒] 歌词

注释:中括号、冒号、点号全都要求英文输入状态;

2、其他格式①:[分钟:秒] 歌词;

3、其他格式②:[分钟:秒:毫秒] 歌词,与标准格式相比,秒后边的点号被改成了冒号。

3.3 LRC制作

LRC文件是通过编辑器把歌词按歌曲歌词出现的时间编辑到一起,然后在播放歌曲时同步依次将歌词显示出来的,用记事本按照上述格式写好后,将扩展名改为lrc即可做出“文件名.LRC”的歌词文件。当然,要进行高效的lrc歌词制作需要专门的软件。

专门制作LRC歌词的软件有Lrc歌词编辑器2010、千千静听等,它们都支持傻瓜操作和专业操作,即针对新手,有一看就会的制作歌词的方法,针对专业人士,也有高级编辑模式,具体操作可以点击链接进入它们的专门词条查看。

还有一种文本转语音的软件在把文字导出成MP3声音文件的同时也能导出LRC文件,导出后用支持LRC的播放器播放MP3的时候LRC会被自动加载并显示出来,这方面的典型代表软件是TTSUU文本转语音软件,其典型应用是用来制作单词、句子以及课文等的双语对照朗读的MP3以及同步LRC歌词字幕,对学生学习外语很有帮助。

3.4 LRC应用

市场上的支持显示歌词的音乐播放器都有相同的规定,要求歌曲和LRC歌词的文件名相同(即除了扩展名.mp3、.wma、.lrc等不同之外,点前面的文字、文字格式要一模一样)并且放在同一目录下(即同一文件夹中),用带显示歌词功能的播放器播放歌曲时歌词就可以同步显示,方便查看和学歌。

3.5 LRC详细说明

lrc歌词文本中含有两类标签

一是标识标签,其格式为“[标识名:值]”主要包含以下预定义的标签:

[ar:歌手名]、[ti:歌曲名]、[al:专辑名]、[by:编辑者(指lrc歌词的制作人)]、[offset:时间补偿值] (其单位是毫秒,正值表示整体提前,负值相反。这是用于总体调整显示快慢的,但多数的MP3可能不会支持这种标签)。

二是时间标签,形式为“[mm:ss]”或“[mm:ss.ff]”(分钟数:秒数.百分之一秒数),时间标签需位于某行歌词中的句首部分,一行歌词可以包含多个时间标签(比如歌词中的迭句部分)。当歌曲播放到达某一时间点时,MP3就会寻找对应的时间标签并显示标签后面的歌词文本,这样就完成了“歌词同步”的功能。

  • 时间标签(Time-tag)

形式为"[mm:ss]“(分钟数:秒数)或”[mm:ss.ff]“。数字须为非负整数, 比如”[12:34.50]“是有效的,而”[0x0C:-34.50]"无效(但也有不太规范的歌词采用[00:-0.12]的方式表示负值以显示歌曲名,部分播放器是支持的)。 它可以位于某行歌词中的任意位置。一行歌词可以包含多个时间标签(比如歌词中的迭句部分)。根据这些时间标签,用户端程序会按顺序依次高亮显示歌词,从而实现卡拉OK功能。另外,标签无须排序。

  • 标识标签(ID-tags)

其格式为"[标识名:值]"。大小写等价。以下是预定义的标签。

[ar:艺人名]

[ti:曲名]

[al:专辑名]

[by:编者(指编辑LRC歌词的人)]

[offset:时间补偿值] 其单位是毫秒,正值表示整体提前,负值相反。这是用于总体调整显示快慢的。

歌词文件示例

[ti:依赖]——ti.=title,标题,即歌曲名
[ar:蔡健雅]——ar.=artist,艺术家,即歌手名
[al:MY SPACE]——al.=album,专辑,即歌曲被收录的专辑
[by:Chapter Chang]——by somebody,即LRC歌词文件的制作者
[offset:0]——补偿时值。500=0.5秒,正负值分别提前和延长相应的时间(其值多为500的倍数)
(以下为歌词内容,前面中括号内的数字为内容显示时的时值精确到毫秒;后面为在播放器上显示的内容,可以介绍歌曲的名称、演唱者和作者等ID3信息等。相同的歌词内容反复时可以在词句前加上其依次出现时的时值)
[00:00.50]蔡健雅 - 依赖
[00:07.94]词、曲:蔡健雅、陶晶莹
[00:11.60]关了灯把房间整理好
[00:15.48]凌晨三点还是睡不著
[00:19.64]你应该是不在 所以把电话挂掉
[00:30.39]在黑暗手表跟着心跳
[00:34.57]怎么慢它停也停不了
[00:39.70]我应该只是心情不好
[00:45.00]那又怎样
[00:48.50]但本来是这样
[01:21.36]朋友们对我的安慰
[01:25.20]都是同样的一个话题
[01:29.73]我一定要变得更坚强
[01:34.68]说很简单
[00:38.50]但是做却很难
[00:53.00][01:43.88][02:11.23]虽然无所谓写在脸上
[00:58.21][01:48.44][02:15.79]我还是舍不得让你离开
[01:02.97][01:53.50][02:20.60]虽然闭着眼假装听不到
[01:07.84][01:58.23][02:25.11][02:33.15]你对爱 已不再 想依赖

04. 终端控制码

提示会调用提供的接口函数即可

console.h(不需要实现 会使用即可)

#ifndef  _CONSOLE_H_
#define  _CONSOLE_H_

/*
COLOR_RED              红
COLOR_BLACK            黑
COLOR_GREEN            绿
COLOR_BLUE             蓝
COLOR_YELLOW           黄
COLOR_WHITE            白
COLOR_CYAN             青
COLOR_MAGENTA          洋红
*/
#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

void cusor_moveto(int x, int y);//光标跳转到 y行 x列
void cusor_save_pos(void);//保存光标位置
void cusor_recover_pos(void);//恢复光标位置
void cusor_hide(void);//隐藏光标
void cusor_show(void);//显示光标
void clear_screen(void);//清屏
void set_fg_color(int color);//设置字体前景色
void set_bg_color(int color);//设置字体背景色

#endif	//_CONSOLE_H_

console.c

#include <stdio.h>
#include <stdlib.h>
#include "console.h"

//光标跳转到y行 x列
void cusor_moveto(int x, int y)
{
    
    
    //ESC[y;xH
    printf("\033[%d;%dH",y,x);
    fflush(stdout);
} 

//保存光标位置
void cusor_save_pos(void)
{
    
    
    //ESC[s
    printf("\033[s");
    fflush(stdout);
} 

//恢复光标位置
void cusor_recover_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);
}

test.c

#include <stdio.h>
#include "console.h"

int main(void)
{
    
    

    printf("hello vt\n");

    //清屏
    clear_screen(); 


    cusor_moveto(100, 50);
    set_fg_color(COLOR_RED);
    printf("Hello, I Love 1000phone1\n");


    cusor_moveto(50, 100);
    set_bg_color(COLOR_BLUE);
    printf("Hello, I Love 1000phone2\n");

    return 0;
}

Makefile

TARGET:=test
CC:=gcc
OBJS:=obj/console.o obj/test.o  obj/lrc.o obj/dlist.o
CFLAGS:=-Wall

$(TARGET):$(OBJS)
	$(CC) $(CFLAGS) $^ -o $@

obj/%.o:%.c
	$(CC) -c $< -o $@


.PHONY:clean
clean:
	rm -rf $(OBJS) $(TARGET)

05. 启动mplayer接口函数(省略)

提示:不用实现,暂时会调用接口函数即可

mplayer.h

#ifndef __MPLAYER_H__
#define __MPLAYER_H__

void mplayer_play(char *path);

#endif/*__MPLAYER_H__*/


mplayer.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void mplayer_play(char *path)
{
    
    
    pid_t pid = -1;

    //创建子进程
    pid = fork();
    if (pid < 0)
    {
    
    
        perror("fork");
    }
    else if (0 == pid)
    {
    
    
        close(1);
        close(2);
        
        execlp("mplayer", "mplayer", "-slave", "-quiet", path, NULL);
    
        exit(0);
    }
    else
    {
    
    

    }
}

06. 延时函数

#include <unistd.h>

int usleep(useconds_t usec);
功能:
	
参数:
	usec 睡眠微秒
返回值:

#include <unistd.h>

unsigned int sleep(unsigned int seconds);
功能:
	
参数:
	seconds睡眠秒数
返回值:

07. 函数封装

lrc.h

#ifndef __LRC_H__
#define __LRC_H__

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "dlist.h"

//时间相关结构体类型
typedef struct _lrc_time_t{
    
    
    //分钟
    unsigned short min;    
    //秒
    unsigned short sec;
}lrc_time_t;

//歌词节点信息
typedef struct _lrc_node_t{
    
    
    int time;
    char lrcbuf[200];
}lrc_node_t;

//加载歌词文件
char *lrc_read_file(const char *filename);

//使用\r\n切割歌词
int lrc_strtok_buf(char *lrc_text[], char *ptext);

//解析lrc文件前4行 歌手 歌名 专辑 制作等等
int lrc_parse_head(char *lrc_text[], char *song_msg[]);

//显示歌曲信息 前4行
int lrc_song_head_print(char *song_msg[]);

//释放song_head内存
int lrc_song_head_free(char *song_msg[], int n);

//指定字体颜色输出字符串
int lrc_color_print(char *str, int x, int y, int color);

//显示歌词的时间
int lrc_time_print(lrc_time_t *t);

//解析歌词信息 歌词和时间
int lrc_lyric_parse(dlist_t *d, int lrc_lines, char *lrc_text[]);

//打印链表中5个节点的信息到屏幕上
int lrc_lyric_print(node_t *start, node_t *cur);

//将秒数转化为分和秒 lrc_time_t类型
int lrc_make_time(lrc_time_t *t);

#endif /*__LRC_H__*/

lrc.c

#include "lrc.h"
#include "console.h"


//加载歌词文件
char *lrc_read_file(const char *filename)
{
    
    
   
    return NULL;
}


//使用\r\n切割歌词 返回歌词的行数
int lrc_strtok_buf(char *lrc_text[], char *ptext)
{
    
    
   
    return 0;
}


//解析lrc文件前4行 歌手 歌名 专辑 制作等等
//[ti:简单爱]
//[ar:周杰伦]
//[al:范特西]
//[by:大脸猫]
int lrc_parse_head(char *lrc_text[], char *song_msg[])
{
    
    
   

    return 0;
}


//释放song_head内存
int lrc_song_head_free(char *song_msg[], int n)
{
    
    
   

    return 0;
}

//显示歌曲信息 前4行
int lrc_song_head_print(char *song_msg[])
{
    
    
    

    return 0;
}


//指定字体颜色输出字符串
int lrc_color_print(char *str, int x, int y, int color)
{
    
    
    

    return 0;
}


//显示歌词的时间
int lrc_time_print(lrc_time_t *t)
{
    
    
    
    return 0;
}



//解析歌词信息 歌词和时间
int lrc_lyric_parse(dlist_t *d, int lrc_lines, char *lrc_text[])
{
    
    
  
    return 0;
}


//打印链表中5个节点的信息到屏幕上
int lrc_lyric_print(node_t *start, node_t *cur)
{
    
    
    

    return 0;
}


//将秒数转化为分和秒 lrc_time_t类型
int lrc_make_time(lrc_time_t *t)
{
    
    

    return 0;
}

08. lrc_read_file函数

lrc.c

//加载歌词文件
char *lrc_read_file(const char *filename)
{
    
    
    int ret = 0;

    //文件大小
    long filesize = 0;
    
    char *ptext = NULL;

    FILE *fp = NULL;

    
    //参数检查
    if (NULL == filename)
    {
    
    
        printf("lrc_read_file NULL\n");
        goto err0;
    }

    //打开文件
    fp = fopen(filename, "r");
    if (NULL == fp)
    {
    
    
        printf("fopen failed..\n");
        goto err0;
    }

    //文件定位到文件最后
    fseek(fp, 0, SEEK_END);

    //获取文件大小
    filesize = ftell(fp);

    //动态分配空间
    ptext = malloc(filesize + 1);
    if (NULL == ptext)
    {
    
    
        printf("malloc failed...\n");
        goto err1;
    }
    memset(ptext, 0, filesize + 1);

    //文件定位到开头
    rewind(fp);

    //读取文件所有内容 
    ret = fread(ptext, filesize, 1, fp);    
    if (0 == ret)
    {
    
    
        printf("fread failed...\n");
        goto err1;
    }

    //关闭文件
    fclose(fp);

    return ptext;
err1:
    fclose(fp);
err0:
    return NULL;
}

测试代码 test.c

#include <stdio.h>
#include <unistd.h>
#include "console.h"
#include "lrc.h"

int main(void)
{
    
    
    char *ptext = NULL;

    ptext = lrc_read_file("./love.lrc");

    printf("%s", ptext);

    if (NULL != ptext)
    {
    
    
        free(ptext);
        ptext = NULL;
    }

    return 0;
}

执行结果:

deng@local:~/code/project/3lrc$ ./test 
[ti:简单爱]
[ar:周杰伦]
[al:范特西]
[by:大脸猫]
[00:04.41]周杰伦 Chow, Jay Jou
[00:10.56]简单爱(台视Star blue蓝星主题曲)
[00:18.48]词:徐若瑄 曲:周杰伦
[00:26.44]说不上为什么 我变得很主动
[00:31.37]若爱上一个人 什么都会值得去做
[02:04.94][00:36.09]我想大声宣布 对你依依不舍
[02:09.97][00:41.26]连隔壁邻居都猜到我现在的感受
[02:14.94][00:46.17]河边的风 在吹着头发 飘动
[02:19.80][00:51.25]牵着你的手 一阵莫名感动
[02:24.61][00:55.86]我想带你 回我的外婆家
[02:28.32][00:59.79]一起看着日落 一直到我们都睡着
[03:34.64][02:34.71][01:05.83]我想就这样牵着你的手不放开
[03:39.68][02:39.34][01:10.71]爱能不能够永远单纯没有悲哀
[03:44.27][02:43.90][01:15.44]我想 带你骑单车
[03:46.74][02:46.60][01:18.05]我想 和你看棒球
[03:49.77][02:49.58][01:20.71]想这样没担忧
[03:51.61][02:51.59][01:22.69]唱着歌 一直走☆
[03:54.38][02:54.35][01:25.57]我想就这样牵着你的手不放开
[03:59.19][02:59.01][01:30.41]爱可不可以简简单单没有伤害
[04:03.77][03:03.73][01:35.04]你 靠着我的肩膀
[04:06.33][03:06.26][01:37.49]你 在我胸口睡着
[04:09.13][03:09.34][01:40.57]像这样的生活
[04:11.36][03:11.26][01:42.66]我爱你 你爱我★
[03:13.76][01:44.97]想~~~ 简!简!单!单! 爱~~~
[03:23.61][01:54.30]想~~~ 简!简!单!单! 爱~~~

09. lrc_strtok_buf函数

lrc.c

//使用\r\n切割歌词 返回歌词的行数
int lrc_strtok_buf(char *lrc_text[], char *ptext)
{
    
    
    int i = 0;

    //切割获取文件第一行
    lrc_text[i] = strtok(ptext, "\r\n");

    while(NULL != lrc_text[i])
    {
    
    
        i++;
        lrc_text[i] = strtok(NULL, "\r\n");
    }

    return i;
err0:
    return -1;
}

测试代码 test.c

#include <stdio.h>
#include <unistd.h>
#include "console.h"
#include "lrc.h"

int main(void)
{
    
    
    int i = 0;

    //存储歌词的行数
    int lines = 0;

    //存储歌词每一行
    char *lrc_line_text[200] = {
    
    NULL};

    //保存歌词
    char *ptext = NULL;

    ptext = lrc_read_file("./love.lrc");

    //切割歌词 \r\n分隔
    lines = lrc_strtok_buf(lrc_line_text, ptext);
    
    printf("lines: %d\n", lines);

    for (i = 0; i < lines; i++)
    {
    
    
        printf("%s\n", lrc_line_text[i]);
    }



    //释放内存
    if (NULL != ptext)
    {
    
    
        free(ptext);
        ptext = NULL;
    }

    return 0;
}

执行结果

deng@local:~/code/project/3lrc$ ./test  
lines: 29
[ti:简单爱]
[ar:周杰伦]
[al:范特西]
[by:大脸猫]
[00:04.41]周杰伦 Chow, Jay Jou
[00:10.56]简单爱(台视Star blue蓝星主题曲)
[00:18.48]词:徐若瑄 曲:周杰伦
[00:26.44]说不上为什么 我变得很主动
[00:31.37]若爱上一个人 什么都会值得去做
[02:04.94][00:36.09]我想大声宣布 对你依依不舍
[02:09.97][00:41.26]连隔壁邻居都猜到我现在的感受
[02:14.94][00:46.17]河边的风 在吹着头发 飘动
[02:19.80][00:51.25]牵着你的手 一阵莫名感动
[02:24.61][00:55.86]我想带你 回我的外婆家
[02:28.32][00:59.79]一起看着日落 一直到我们都睡着
[03:34.64][02:34.71][01:05.83]我想就这样牵着你的手不放开
[03:39.68][02:39.34][01:10.71]爱能不能够永远单纯没有悲哀
[03:44.27][02:43.90][01:15.44]我想 带你骑单车
[03:46.74][02:46.60][01:18.05]我想 和你看棒球
[03:49.77][02:49.58][01:20.71]想这样没担忧
[03:51.61][02:51.59][01:22.69]唱着歌 一直走☆
[03:54.38][02:54.35][01:25.57]我想就这样牵着你的手不放开
[03:59.19][02:59.01][01:30.41]爱可不可以简简单单没有伤害
[04:03.77][03:03.73][01:35.04]你 靠着我的肩膀
[04:06.33][03:06.26][01:37.49]你 在我胸口睡着
[04:09.13][03:09.34][01:40.57]像这样的生活
[04:11.36][03:11.26][01:42.66]我爱你 你爱我★
[03:13.76][01:44.97]想~~~ 简!简!单!单! 爱~~~
[03:23.61][01:54.30]想~~~ 简!简!单!单! 爱~~~

10. lrc_parse_head函数

lrc.c

//解析lrc文件前4行 歌手 歌名 专辑 制作等等
//[ti:简单爱]
//[ar:周杰伦]
//[al:范特西]
//[by:大脸猫]
int lrc_parse_head(char *lrc_text[], char *song_msg[])
{
    
    
    int i = 0;

    //分隔符
    char *tok[] = {
    
    "[ti", "[ar", "[al", "[by"};

    for (i = 0; i < 4; i++)
    {
    
    
        if (strncmp(lrc_text[i], tok[i], 3) == 0)
        {
    
    
            song_msg[i] = malloc(strlen(lrc_text[i]) - 4);
            if (NULL == song_msg[i])
            {
    
    
                printf("lrc_parse_head malloc failed...\n");
                break;
            }
            sscanf(lrc_text[i], "%*4s%[^]]", song_msg[i]);
        }
        else
        {
    
    
            //不存在该字段
            song_msg[i] = NULL;
        }
    }

    return 0;
}

测试代码 test.c

#include <stdio.h>
#include <unistd.h>
#include "console.h"
#include "lrc.h"

//保存歌曲的信息 前四行
char *song_msg[4];

int main(void)
{
    
    
    int i = 0;

    //存储歌词的行数
    int lines = 0;

    //存储歌词每一行
    char *lrc_line_text[200] = {
    
    NULL};

    //保存歌词
    char *ptext = NULL;

    ptext = lrc_read_file("./love.lrc");

    //切割歌词 \r\n分隔
    lines = lrc_strtok_buf(lrc_line_text, ptext);
    
    printf("lines: %d\n", lines);

    lrc_parse_head(lrc_line_text, song_msg); 

    //验证是否获取歌曲信息是否成功
    for (i = 0; i < 4; i++)
    {
    
    
        printf("%s\n", song_msg[i]);
    }


    //释放内存 song_msg[i]
    for (i = 0; i < 4; i++)
    {
    
    
        free(song_msg[i]);
    }


    //释放内存
    if (NULL != ptext)
    {
    
    
        free(ptext);
        ptext = NULL;
    }

    return 0;
}

运行结果

deng@local:~/code/project/3lrc$ ./test  
lines: 29
简单爱
周杰伦
范特西
大脸猫
deng@local:~/code/project/3lrc$ 

11. lrc_song_head_free函数

lrc.c

//释放song_head内存
int lrc_song_head_free(char *song_msg[], int n)
{
    
    
    int i = 0;

    for (i = 0; i < n; i++)
    {
    
    
        if (NULL != song_msg[i])
        {
    
    
            free(song_msg[i]);
            song_msg[i] = NULL;
        }
    }

    return 0;
}

12. lrc_song_head_print函数

lrc.c

//显示歌曲信息 前4行
int lrc_song_head_print(char *song_msg[])
{
    
    
    int i = 0;

    char *head_name[4] = {
    
    "歌名", "歌手", "专辑", "制作"};

    //清屏
    clear_screen();

    //隐藏光标
    cusor_hide();

    //设置字体颜色为蓝色
    set_fg_color(COLOR_BLUE); 

    //输出歌曲信息
    for (i = 0; i < 4; i++)
    {
    
    
        if (NULL != song_msg[i])
        {
    
    
            //移动光标到i + 1行 35列
            cusor_moveto(35, i + 1);
            printf("%s : %s\n", head_name[i], song_msg[i]);
        }
    }

    return 0;
}

测试代码 test.c

#include <stdio.h>
#include <unistd.h>
#include "console.h"
#include "lrc.h"

//保存歌曲的信息 前四行
char *song_msg[4];

int main(void)
{
    
    
    int i = 0;

    //存储歌词的行数
    int lines = 0;

    //存储歌词每一行
    char *lrc_line_text[200] = {
    
    NULL};

    //保存歌词
    char *ptext = NULL;

    ptext = lrc_read_file("./love.lrc");

    //切割歌词 \r\n分隔
    lines = lrc_strtok_buf(lrc_line_text, ptext);
    
    printf("lines: %d\n", lines);

    lrc_parse_head(lrc_line_text, song_msg); 

    lrc_song_head_print(song_msg);



    //释放内存 song_msg[i]
    lrc_song_head_free(song_msg, 4); 



    //释放内存
    if (NULL != ptext)
    {
    
    
        free(ptext);
        ptext = NULL;
    }

    return 0;
}

运行结果
在这里插入图片描述

13. lrc_color_print函数

lrc.c

//指定字体颜色输出字符串
int lrc_color_print(char *str, int x, int y, int color)
{
    
    
    //光标移动到指定位置
    cusor_moveto(x, y);

    //设置字体颜色
    set_fg_color(color);

    //输出字符串
    printf("%s\n", str);

    return 0;
}

测试代码 test.c

#include <stdio.h>
#include <unistd.h>
#include "console.h"
#include "lrc.h"

//保存歌曲的信息 前四行
char *song_msg[4];

//时间
lrc_time_t lrc_time = {
    
    0, 0};

int main(void)
{
    
    
    int i = 0;

    //存储歌词的行数
    int lines = 0;

    //存储歌词每一行
    char *lrc_line_text[200] = {
    
    NULL};

    //保存歌词
    char *ptext = NULL;

    ptext = lrc_read_file("./love.lrc");

    //切割歌词 \r\n分隔
    lines = lrc_strtok_buf(lrc_line_text, ptext);
    
    printf("lines: %d\n", lines);

    //解析歌词信息 前4行
    lrc_parse_head(lrc_line_text, song_msg); 

    //输出歌词信息 前4行
    lrc_song_head_print(song_msg);

    //测试控制字体颜色输出字符串
    lrc_color_print("千锋扫地僧", 40, 5, COLOR_RED);





    //释放内存 song_msg[i]
    lrc_song_head_free(song_msg, 4); 



    //释放内存
    if (NULL != ptext)
    {
    
    
        free(ptext);
        ptext = NULL;
    }

    return 0;
}

14. lrc_time_print函数

lrc.c

//显示歌词的时间
int lrc_time_print(lrc_time_t *t)
{
    
    
    char str[32];

    memset(str, 0, 32);
    sprintf(str, "%02d:%02d", t->min, t->sec);

    lrc_color_print(str, 40, 5, COLOR_BLUE);

    return 0;
}

测试代码 test.c

#include <stdio.h>
#include <unistd.h>
#include "console.h"
#include "lrc.h"

//保存歌曲的信息 前四行
char *song_msg[4];

//时间
lrc_time_t lrc_time = {
    
    0, 0};

int main(void)
{
    
    
    int i = 0;

    //存储歌词的行数
    int lines = 0;

    //存储歌词每一行
    char *lrc_line_text[200] = {
    
    NULL};

    //保存歌词
    char *ptext = NULL;

    ptext = lrc_read_file("./love.lrc");

    //切割歌词 \r\n分隔
    lines = lrc_strtok_buf(lrc_line_text, ptext);
    
    printf("lines: %d\n", lines);

    //解析歌词信息 前4行
    lrc_parse_head(lrc_line_text, song_msg); 

    //输出歌词信息 前4行
    lrc_song_head_print(song_msg);

    //显示歌词时间
    lrc_time_print(&lrc_time);



    //释放内存 song_msg[i]
    lrc_song_head_free(song_msg, 4); 



    //释放内存
    if (NULL != ptext)
    {
    
    
        free(ptext);
        ptext = NULL;
    }

    return 0;
}

运行结果
在这里插入图片描述

15. dlist_find_by_key函数(链表)

dlist.h

//通过key检索链表节点数据
node_t *dlist_find_by_key(dlist_t *d, void *key, cmp_t my_cmp);

dlist.c

//通过key检索链表节点数据
node_t *dlist_find_by_key(dlist_t *d, void *key, cmp_t my_cmp)
{
    
    
    int i = 0;
    node_t *tmp = NULL;

    //参数检查
    if (NULL == d || NULL == key || NULL == my_cmp
        || NULL == d->p)
    {
    
    
        printf("dlist_find_by_key NULL\n");
        goto err0;
    }

    //指向第一个节点
    tmp = d->p;

    do {
    
    
        if (my_cmp(tmp->data, key) == 0) 
        {
    
    
            break;
        }

        i++;

        tmp = tmp->next;
    }while(tmp != d->p);

    //找不到的情形
    if (i == d->count)
    {
    
    
        goto err0;
    }


    return tmp;
err0:
    return NULL;
}

16. lrc_lyric_parse函数

lrc.c

//解析歌词信息 歌词和时间 然后插入到链表中
int lrc_lyric_parse(dlist_t *d, int lrc_lines, char *lrc_text[])
{
    
    
    int i = 0;
    int j = 0;
    int min;
    int sec;

    //歌词节点信息
    lrc_node_t node;

    int time_array[10] = {
    
    0};
    int time_counts = 0;

    char *src = NULL;

    if (NULL == d || NULL == lrc_text)
    {
    
    
        printf("lrc_lyric_parse NULL\n");
        goto err0;
    }

    if (lrc_lines <= 0)
    {
    
    
        printf("歌词行数<= 0\n");
        goto err0;
    }


    //从第5行开始解析 前面4行是基本信息
    for (i = 4; i < lrc_lines; i++)
    {
    
    
        //[00:26.44]说不上为什么 我变得很主动
        src = lrc_text[i]; 

        //同一句歌词重复次数
        time_counts = 0;

        //解析时间 一句歌词可能有多个时间 重复 
        while('[' == *src) 
        {
    
    
            sscanf(src, "[%2d:%2d", &min, &sec);
            time_array[time_counts++] = min * 60 + sec;

            //[00:26.44] 有十个字符
            src = src + 10;
        }

        //解析完一行所有的时间后,src就为歌词的首地址
        //根据歌词的时间个数, 将歌词和时间保存到链表中
        for (j = 0; j < time_counts; j++)
        {
    
    
            memset(&node, 0, sizeof(node));
            node.time = time_array[j]; 
            strcpy(node.lrcbuf, src);

            dlist_append(d, &node);
        }
    }

    return 0;
err0:
    return -1;
}

测试代码 test.c

#include <stdio.h>
#include <unistd.h>
#include "console.h"
#include "lrc.h"

//保存歌曲的信息 前四行
char *song_msg[4];


int my_print(void *data)
{
    
    
    lrc_node_t *l = data;

    printf("%d %s\n", l->time, l->lrcbuf);
}


//时间
lrc_time_t lrc_time = {
    
    0, 0};

int main(void)
{
    
    
    int i = 0;

    //链表
    dlist_t *d = NULL;

    //存储歌词的行数
    int lines = 0;

    //存储歌词每一行
    char *lrc_line_text[200] = {
    
    NULL};

    //保存歌词
    char *ptext = NULL;

    ptext = lrc_read_file("./love.lrc");

    //切割歌词 \r\n分隔
    lines = lrc_strtok_buf(lrc_line_text, ptext);
    
    printf("lines: %d\n", lines);

    //解析歌词信息 前4行
    lrc_parse_head(lrc_line_text, song_msg); 

    //输出歌词信息 前4行
    lrc_song_head_print(song_msg);

    //显示歌词时间
    lrc_time_print(&lrc_time);


    //链表
    d = dlist_create(sizeof(lrc_node_t));

    //链表遍历
    lrc_lyric_parse(d, lines, lrc_line_text);

    dlist_traverse(d, my_print);

    printf("counts: %d\n", dlist_count(d));



    //链表销毁
    dlist_destroy(d);

    if (NULL != d)
    {
    
    
        free(d);
        d = NULL;
    }


    //释放内存 song_msg[i]
    lrc_song_head_free(song_msg, 4); 


    //释放内存
    if (NULL != ptext)
    {
    
    
        free(ptext);
        ptext = NULL;
    }

    return 0;
}

运行结果

deng@local:~/code/project/3lrc$ ./test  
lines: 29

                                  歌名 :   简单爱
                                  歌手 :   周杰伦
                                  专辑 :   范特西
                                  制作 :   大脸猫
                                       00:00
4 周杰伦 Chow, Jay Jou
10 简单爱(台视Star blue蓝星主题曲)
18 词:徐若瑄 曲:周杰伦
26 说不上为什么 我变得很主动
31 若爱上一个人 什么都会值得去做
124 我想大声宣布 对你依依不舍
36 我想大声宣布 对你依依不舍
129 连隔壁邻居都猜到我现在的感受
41 连隔壁邻居都猜到我现在的感受
134 河边的风 在吹着头发 飘动
46 河边的风 在吹着头发 飘动
139 牵着你的手 一阵莫名感动
51 牵着你的手 一阵莫名感动
144 我想带你 回我的外婆家
55 我想带你 回我的外婆家
148 一起看着日落 一直到我们都睡着
59 一起看着日落 一直到我们都睡着
214 我想就这样牵着你的手不放开
154 我想就这样牵着你的手不放开
65 我想就这样牵着你的手不放开
219 爱能不能够永远单纯没有悲哀
159 爱能不能够永远单纯没有悲哀
70 爱能不能够永远单纯没有悲哀
224 我想 带你骑单车
163 我想 带你骑单车
75 我想 带你骑单车
226 我想 和你看棒球
166 我想 和你看棒球
78 我想 和你看棒球
229 想这样没担忧
169 想这样没担忧
80 想这样没担忧
231 唱着歌 一直走☆
171 唱着歌 一直走☆
82 唱着歌 一直走☆
234 我想就这样牵着你的手不放开
174 我想就这样牵着你的手不放开
85 我想就这样牵着你的手不放开
239 爱可不可以简简单单没有伤害
179 爱可不可以简简单单没有伤害
90 爱可不可以简简单单没有伤害
243 你 靠着我的肩膀
183 你 靠着我的肩膀
95 你 靠着我的肩膀
246 你 在我胸口睡着
186 你 在我胸口睡着
97 你 在我胸口睡着
249 像这样的生活
189 像这样的生活
100 像这样的生活
251 我爱你 你爱我★
191 我爱你 你爱我★
102 我爱你 你爱我★
193 想~~~ 简!简!单!单! 爱~~~
104 想~~~ 简!简!单!单! 爱~~~
203 想~~~ 简!简!单!单! 爱~~~
114 想~~~ 简!简!单!单! 爱~~~

counts: 57
deng@local:~/code/project/3lrc$ 

17. lrc_lyric_print函数

lrc.c

//打印链表中5个节点的信息到屏幕上
int lrc_lyric_print(node_t *start, node_t *cur)
{
    
    
    int i = 0;

    lrc_node_t *lrc_node = NULL;

    for (i = 0; i < 5; i++)
    {
    
    
        lrc_node = (lrc_node_t*)start->data;
        //红色高亮显示节点
        if(start == cur)
        {
    
    
            lrc_color_print(lrc_node->lrcbuf, 30, 6 + i, COLOR_RED); 
        }
        else
        {
    
    
            lrc_color_print(lrc_node->lrcbuf, 30, 6 + i, COLOR_BLUE); 
        }

        //指向链表下一个节点
        start = start->next;
    }

    return 0;
}

测试代码 test.c

#include <stdio.h>
#include <unistd.h>
#include "console.h"
#include "lrc.h"

//保存歌曲的信息 前四行
char *song_msg[4];


int my_print(void *data)
{
    
    
    lrc_node_t *l = data;

    printf("%d %s\n", l->time, l->lrcbuf);
}


//时间
lrc_time_t lrc_time = {
    
    0, 0};

int main(void)
{
    
    
    int i = 0;

    //链表
    dlist_t *d = NULL;

    //存储歌词的行数
    int lines = 0;

    //存储歌词每一行
    char *lrc_line_text[200] = {
    
    NULL};

    //保存歌词
    char *ptext = NULL;

    ptext = lrc_read_file("./love.lrc");

    //切割歌词 \r\n分隔
    lines = lrc_strtok_buf(lrc_line_text, ptext);
    
    printf("lines: %d\n", lines);

    //解析歌词信息 前4行
    lrc_parse_head(lrc_line_text, song_msg); 

    //输出歌词信息 前4行
    lrc_song_head_print(song_msg);

    //显示歌词时间
    lrc_time_print(&lrc_time);


    //链表
    d = dlist_create(sizeof(lrc_node_t));

    //歌词解析
    lrc_lyric_parse(d, lines, lrc_line_text);
    
    //测试显示前面五条歌词
    lrc_lyric_print(d->p, NULL);


    //链表销毁
    dlist_destroy(d);

    if (NULL != d)
    {
    
    
        free(d);
        d = NULL;
    }


    //释放内存 song_msg[i]
    lrc_song_head_free(song_msg, 4); 


    //释放内存
    if (NULL != ptext)
    {
    
    
        free(ptext);
        ptext = NULL;
    }

    return 0;
}

运行结果

                                  歌名 :   简单爱
                                  歌手 :   周杰伦
                                  专辑 :   范特西
                                  制作 :   大脸猫
                                       00:00
                             周杰伦 Chow, Jay Jou
                             简单爱(台视Star blue蓝星主题曲)
                             词:徐若瑄 曲:周杰伦
                             说不上为什么 我变得很主动
                             若爱上一个人 什么都会值得去做
deng@local:~/code/project/3lrc$ 

18. lrc_make_time函数

lrc.c

//将秒数转化为分和秒 lrc_time_t类型
int lrc_make_time(lrc_time_t *t)
{
    
    
    t->sec++;
    if (60 == t->sec)
    {
    
    
        t->sec = 0; 
        t->min++;

        if (60 == t->min)
        {
    
    
            t->min = 0;
        }
    }

    return 0;
}

测试代码 test.c

#include <stdio.h>
#include <unistd.h>
#include "console.h"
#include "lrc.h"

//保存歌曲的信息 前四行
char *song_msg[4];


int my_print(void *data)
{
    
    
    lrc_node_t *l = data;

    printf("%d %s\n", l->time, l->lrcbuf);
}


//时间
lrc_time_t lrc_time = {
    
    0, 0};

int main(void)
{
    
    
    int i = 0;

    int sec = 0;

    //链表
    dlist_t *d = NULL;

    //存储歌词的行数
    int lines = 0;

    //存储歌词每一行
    char *lrc_line_text[200] = {
    
    NULL};

    //保存歌词
    char *ptext = NULL;

    ptext = lrc_read_file("./love.lrc");

    //切割歌词 \r\n分隔
    lines = lrc_strtok_buf(lrc_line_text, ptext);
    
    printf("lines: %d\n", lines);

    //解析歌词信息 前4行
    lrc_parse_head(lrc_line_text, song_msg); 

    //输出歌词信息 前4行
    lrc_song_head_print(song_msg);

    //显示歌词时间
    lrc_time_print(&lrc_time);


    //链表
    d = dlist_create(sizeof(lrc_node_t));

    //歌词解析
    lrc_lyric_parse(d, lines, lrc_line_text);
    
    //测试显示前面五条歌词
    lrc_lyric_print(d->p, NULL);

    //开始计时显示歌词
    while(1)
    {
    
    
        //显示歌词时间
        lrc_time_print(&lrc_time);
        



        //每隔一秒钟刷新一次
        sleep(1);
        sec++;
        //时间结构体赋值
        lrc_make_time(&lrc_time); 

    }


    //显示光标
    cusor_show();

    //链表销毁
    dlist_destroy(d);

    if (NULL != d)
    {
    
    
        free(d);
        d = NULL;
    }


    //释放内存 song_msg[i]
    lrc_song_head_free(song_msg, 4); 


    //释放内存
    if (NULL != ptext)
    {
    
    
        free(ptext);
        ptext = NULL;
    }

    return 0;
}

运行结果
在这里插入图片描述

19. dlist_find_by_key函数测试

测试代码 test.c (每隔一段时间自动刷新歌词 验证链表功能)

#include <stdio.h>
#include <unistd.h>
#include "console.h"
#include "lrc.h"

//保存歌曲的信息 前四行
char *song_msg[4];


int my_print(void *data)
{
    
    
    lrc_node_t *l = data;

    printf("%d %s\n", l->time, l->lrcbuf);
}

int my_cmp(void *data, void *key)
{
    
    
    lrc_node_t  *t = data; 

    return t->time - *(int*)key;
}


//时间
lrc_time_t lrc_time = {
    
    0, 0};

int main(void)
{
    
    
    int i = 0;

    int sec = 0;

    //链表
    dlist_t *d = NULL;
    node_t *start = NULL;

    //存储歌词的行数
    int lines = 0;

    //存储歌词每一行
    char *lrc_line_text[200] = {
    
    NULL};

    //保存歌词
    char *ptext = NULL;

    ptext = lrc_read_file("./love.lrc");

    //切割歌词 \r\n分隔
    lines = lrc_strtok_buf(lrc_line_text, ptext);
    
    printf("lines: %d\n", lines);

    //解析歌词信息 前4行
    lrc_parse_head(lrc_line_text, song_msg); 

    //输出歌词信息 前4行
    lrc_song_head_print(song_msg);

    //显示歌词时间
    lrc_time_print(&lrc_time);


    //链表
    d = dlist_create(sizeof(lrc_node_t));

    //歌词解析
    lrc_lyric_parse(d, lines, lrc_line_text);

    
    //测试显示前面五条歌词
    lrc_lyric_print(d->p, NULL);

    //统计显示歌词节点数
    i = 0;
    //开始计时显示歌词
    while(1)
    {
    
    
        //显示歌词时间
        //lrc_time_print(&lrc_time);
        
        //通过时间查找链表节点
        start = dlist_find_by_key(d, &sec, my_cmp);
        if (NULL != start)
        {
    
    
            i++;
            my_print(start->data);

            //结束循环
            if (i == d->count)
            {
    
    
                printf("歌词显示完毕\n");
                break;
            }
        }

        //每隔一秒钟刷新一次
        sleep(1);
        sec++;
        //时间结构体赋值
        lrc_make_time(&lrc_time); 

    }


    //显示光标
    cusor_show();

    //链表销毁
    dlist_destroy(d);

    if (NULL != d)
    {
    
    
        free(d);
        d = NULL;
    }


    //释放内存 song_msg[i]
    lrc_song_head_free(song_msg, 4); 


    //释放内存
    if (NULL != ptext)
    {
    
    
        free(ptext);
        ptext = NULL;
    }

    return 0;
}

运行结果
在这里插入图片描述

输出信息如下:

deng@local:~/code/project/3lrc$ ./test  
lines: 29

                                  歌名 :   简单爱
                                  歌手 :   周杰伦
                                  专辑 :   范特西
                                  制作 :   大脸猫
                                       00:00
                             周杰伦 Chow, Jay Jou
                             简单爱(台视Star blue蓝星主题曲)
                             词:徐若瑄 曲:周杰伦
                             说不上为什么 我变得很主动
                             若爱上一个人 什么都会值得去做
4 周杰伦 Chow, Jay Jou
10 简单爱(台视Star blue蓝星主题曲)
18 词:徐若瑄 曲:周杰伦
26 说不上为什么 我变得很主动
31 若爱上一个人 什么都会值得去做
36 我想大声宣布 对你依依不舍
41 连隔壁邻居都猜到我现在的感受
46 河边的风 在吹着头发 飘动
51 牵着你的手 一阵莫名感动
55 我想带你 回我的外婆家
59 一起看着日落 一直到我们都睡着
65 我想就这样牵着你的手不放开
70 爱能不能够永远单纯没有悲哀
75 我想 带你骑单车
78 我想 和你看棒球
80 想这样没担忧
82 唱着歌 一直走☆
85 我想就这样牵着你的手不放开
90 爱可不可以简简单单没有伤害
95 你 靠着我的肩膀
97 你 在我胸口睡着
100 像这样的生活
102 我爱你 你爱我★
104 想~~~ 简!简!单!单! 爱~~~
114 想~~~ 简!简!单!单! 爱~~~
124 我想大声宣布 对你依依不舍
129 连隔壁邻居都猜到我现在的感受
134 河边的风 在吹着头发 飘动
139 牵着你的手 一阵莫名感动
144 我想带你 回我的外婆家
148 一起看着日落 一直到我们都睡着
154 我想就这样牵着你的手不放开
159 爱能不能够永远单纯没有悲哀
163 我想 带你骑单车
166 我想 和你看棒球
169 想这样没担忧
171 唱着歌 一直走☆
174 我想就这样牵着你的手不放开
179 爱可不可以简简单单没有伤害
183 你 靠着我的肩膀
186 你 在我胸口睡着
189 像这样的生活
191 我爱你 你爱我★
193 想~~~ 简!简!单!单! 爱~~~
203 想~~~ 简!简!单!单! 爱~~~
214 我想就这样牵着你的手不放开
219 爱能不能够永远单纯没有悲哀
224 我想 带你骑单车
226 我想 和你看棒球
229 想这样没担忧
231 唱着歌 一直走☆
234 我想就这样牵着你的手不放开
239 爱可不可以简简单单没有伤害
243 你 靠着我的肩膀
246 你 在我胸口睡着
249 像这样的生活
251 我爱你 你爱我★
歌词显示完毕
deng@local:~/code/project/3lrc$ 

20. dlist_sort_by_key函数(链表)

根据时间节点排序,无需实现,直接使用即可。

dlist.h

//根据关键字排序
int dlist_select_sort(dlist_t *d,  cmp_t my_cmp);

dlistc


//排序链表 选择排序
int dlist_select_sort(dlist_t *d,  cmp_t my_cmp)
{
    
    
    node_t *tmp_i;
    node_t *tmp_j;
    node_t *tmp_k;

    void *tmp_data = NULL;


    //参数检查
    if (NULL == d || NULL == my_cmp)
    {
    
    
        printf("dlist_select_sort NULL\n");
    }


    //分配空间
    tmp_data = malloc(d->size);
    if (NULL == tmp_data)
    {
    
    
        printf("malloc failed...\n");
        goto err0;
    }
    memset(tmp_data, 0, d->size);

    tmp_i = d->p;
    do{
    
    

        tmp_k = tmp_i;

        tmp_j = tmp_i->next;
        do{
    
    

            if (my_cmp(tmp_k->data, tmp_j->data) > 0)
            {
    
    
                tmp_k = tmp_j;
            }

            tmp_j = tmp_j->next;
        }while(tmp_j != d->p);



        if (tmp_k != tmp_i)
        {
    
    
            memcpy(tmp_data, tmp_k->data, d->size);
            memcpy(tmp_k->data, tmp_i->data, d->size);
            memcpy(tmp_i->data, tmp_data, d->size);

        }
    

        tmp_i = tmp_i->next;

    }while(tmp_i != d->p->prev);


    //释放内存
    free(tmp_data);

    return 0;
err0:
    return -1;
}

21. 测试程序(最终)

test.c

#include <stdio.h>
#include <unistd.h>
#include "console.h"
#include "lrc.h"

//保存歌曲的信息 前四行
char *song_msg[4];


int my_print(void *data)
{
    
    
    lrc_node_t *l = data;

    printf("%d %s\n", l->time, l->lrcbuf);
}

int my_cmp(void *data, void *key)
{
    
    
    lrc_node_t  *t = data; 

    return t->time - *(int*)key;
}


//时间
lrc_time_t lrc_time = {
    
    0, 0};

int main(void)
{
    
    
    int i = 0;

    int sec = 0;

    //链表
    dlist_t *d = NULL;
    node_t *start = NULL;

    //存储歌词的行数
    int lines = 0;

    //存储歌词每一行
    char *lrc_line_text[200] = {
    
    NULL};

    //保存歌词
    char *ptext = NULL;

    ptext = lrc_read_file("./love.lrc");

    //切割歌词 \r\n分隔
    lines = lrc_strtok_buf(lrc_line_text, ptext);
    
    printf("lines: %d\n", lines);

    //解析歌词信息 前4行
    lrc_parse_head(lrc_line_text, song_msg); 

    //输出歌词信息 前4行
    lrc_song_head_print(song_msg);

    //显示歌词时间
    lrc_time_print(&lrc_time);


    //链表
    d = dlist_create(sizeof(lrc_node_t));

    //歌词解析
    lrc_lyric_parse(d, lines, lrc_line_text);

    //排序歌词
    dlist_select_sort(d, my_cmp);
    
    //测试显示前面五条歌词
    lrc_lyric_print(d->p, NULL);

    //统计显示歌词节点数
    i = 0;
    //开始计时显示歌词
    while(1)
    {
    
    
        //显示歌词时间
        lrc_time_print(&lrc_time);
        
        //通过时间查找链表节点
        start = dlist_find_by_key(d, &sec, my_cmp);
        if (NULL != start)
        {
    
    
            i++;
            //my_print(start->data);

            //输出歌词信息 前4行
            lrc_song_head_print(song_msg);
            //显示歌词时间
            lrc_time_print(&lrc_time);
            
            
            //前面3行 不滚动显示
            if (i <= 3)
            {
    
    
                lrc_lyric_print(d->p, start);
            }
            else if (i >= d->count - 5) //最后5行 不滚动显示
            {
    
    
                //d->p->prev->prev->prev->prev->prev 表示倒数第五个节点
                lrc_lyric_print(d->p->prev->prev->prev->prev->prev, start);
            }
            else
            {
    
    
                //start->prev->prev表示当前节点前面两个节点
                lrc_lyric_print(start->prev->prev, start);
            }



            //结束循环
            if (i == d->count)
            {
    
    
                //printf("歌词显示完毕\n");
                break;
            }
        }

        //每隔一秒钟刷新一次
        sleep(1);
        sec++;
        //时间结构体赋值
        lrc_make_time(&lrc_time); 

    }


    //显示光标
    cusor_show();

    //链表销毁
    dlist_destroy(d);

    if (NULL != d)
    {
    
    
        free(d);
        d = NULL;
    }


    //释放内存 song_msg[i]
    lrc_song_head_free(song_msg, 4); 


    //释放内存
    if (NULL != ptext)
    {
    
    
        free(ptext);
        ptext = NULL;
    }

    return 0;
}

22. 测试结果

在这里插入图片描述

23. 总结

24. 附录

猜你喜欢

转载自blog.csdn.net/dengjin20104042056/article/details/132124764