[Course Design] Lyric Analysis Project

00. Catalog

01. Project Introduction

1.1 Project demo
insert image description here

1.2 Technical points involved

  • file operation

  • linked list

  • string handling

  • function encapsulation

  • VT code

02. Environment deployment (omitted)

2.1 Check whether the system supports the mplayer command

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

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

sudo apt install mplayer

2.2 Install mplayer software

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

2.3 Check whether mplayer is installed successfully

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

03. LRC format (understand)

3.1 Overview of LRC

Lrc is the abbreviation of English lyric (lyric), which is used as the extension of the lyrics file. Lyric files with an extension of lrc can be displayed synchronously on various digital players. LRC Lyrics is a plain text-based lyric-specific format that includes "tags" of the form ":". It was first proposed by Mr. Guo Xiangxiang (Djohan) and applied in his program. This kind of lyrics file can be used to realize the karaoke function (requires a special program), and can be viewed and edited with common word processing software. Of course, in actual operation, special LRC lyrics editing software is usually used for efficient editing.

3.2 LRC format

1. Standard format: [minute:second.millisecond] Lyrics

Note: Brackets, colons, and dots all require English input status;

2. Other formats ①: [minute:second] lyrics;

3. Other formats ②: [minute:second:millisecond] lyrics, compared with the standard format, the dot after the second is changed to a colon.

3.3 LRC production

The LRC file is edited by the editor to edit the lyrics together according to the time when the lyrics of the song appear, and then the lyrics will be displayed in sequence when the song is played. After writing in Notepad according to the above format, change the extension to lrc. Export the lyrics file of "filename.LRC". Of course, efficient lrc lyrics production requires specialized software.

There are Lrc Lyrics Editor 2010, Qianqian Jingting, etc., which are specialized software for making LRC lyrics. They all support fool operation and professional operation, that is, for novices, there is a method of making lyrics at a glance, and for professionals, there is also an advanced editing mode , for specific operations, you can click on the link to enter their dedicated entries to view.

There is also a text-to-speech software that can export LRC files while exporting text to MP3 sound files. After exporting, when playing MP3 with a player that supports LRC, LRC will be automatically loaded and displayed. A typical representative of this aspect The software is TTSUU text-to-speech software. Its typical application is to make bilingual MP3 and synchronous LRC lyrics and subtitles for bilingual reading of words, sentences and texts, which is very helpful for students to learn foreign languages.

3.4 LRC application

All music players on the market that support displaying lyrics have the same regulations, requiring the file name of the song and LRC lyrics to be the same (that is, except for the extension .mp3, .wma, .lrc, etc., the text and text format in front of the point It must be exactly the same) and put them in the same directory (that is, in the same folder), and the lyrics can be displayed synchronously when playing songs with a player with the function of displaying lyrics, which is convenient for viewing and learning songs.

3.5 Detailed description of LRC

There are two types of tags in the lrc lyrics text :

One is the identification label , whose format is "[identification name: value]" mainly includes the following predefined labels:

[ar: singer name], [ti: song name], [al: album name], [by: editor (referring to the producer of lrc lyrics)], [offset: time compensation value] (the unit is milliseconds, positive The value indicates the overall advance, and the negative value is the opposite. This is used to adjust the overall display speed, but most MP3s may not support this label).

The second is the time label , in the form of “[mm:ss]” or “[mm:ss.ff]” (minutes:seconds.hundredth of a second), the time label must be at the beginning of a line of lyrics Part, a line of lyrics can contain multiple time tags (such as the refrain part in the lyrics). When the song playback reaches a certain point in time, MP3 will search for the corresponding time tag and display the lyrics text behind the tag, thus completing the "lyric synchronization" function.

  • Time tag (Time-tag)

The form is "[mm:ss]" (minutes:seconds) or "[mm:ss.ff]". Numbers must be non-negative integers, such as "[12:34.50]" is valid, but "[0x0C:-34.50]" is invalid (but there are also less standardized lyrics that use [00:-0.12] to represent negative values Display the song name, some players are supported). It can be anywhere within a line of lyrics. A line of lyrics can contain multiple time tags (such as refrain parts in lyrics). According to these time tags, the client program will highlight the lyrics in sequence, thereby realizing the karaoke function. Also, the tags don't have to be sorted.

  • Identification tags (ID-tags)

Its format is "[id:value]". Case equivalence. Following are the predefined tags.

[ar: artist name]

[ti:song name]

[al:album name]

[by: editor (referring to the person who edits LRC lyrics)]

[offset: time compensation value] The unit is milliseconds, a positive value indicates the overall advance, and a negative value is the opposite. This is for overall adjustment of display speed.

Lyrics file example

[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. Terminal control code

Tips :Just call the provided interface function

console.h (can be used without implementation)

#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. Start the mplayer interface function (omitted)

Tip : No need to implement, just call the interface function temporarily

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. Delay function

#include <unistd.h>

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

#include <unistd.h>

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

07. Function encapsulation

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 function

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 code 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;
}

Results of the:

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 function

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 code 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;
}

Results of the

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 function

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 code 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;
}

operation result

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

11. lrc_song_head_free function

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 function

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 code 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;
}

operation result
insert image description here

13. lrc_color_print function

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 code 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 function

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 code 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;
}

operation result
insert image description here

15. dlist_find_by_key function (linked list)

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 function

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 code 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;
}

operation result

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 function

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 code 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;
}

operation result

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

18. lrc_make_time function

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 code 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;
}

operation result
insert image description here

19. dlist_find_by_key function test

Test code test.c (automatically refresh the lyrics verification linked list function every once in a while)

#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;
}

operation result
insert image description here

The output information is as follows:

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 function (linked list)

Sort according to the time node, no need to implement, just use it directly.

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 procedure (final)

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. Test results

insert image description here

23. Summary

24. Appendix

Guess you like

Origin blog.csdn.net/dengjin20104042056/article/details/132124764