学会在Linux环境下用c语言多文件制作lrc歌词解析器
效果:
需要掌握的知识
1. 链表的熟悉运用。
懂得在链表的插入,排序。
2. 学会Linux下基本命令指令。
sudo apt-get install vim //下载vim
sudo apt-get install gcc //下载编译软件gcc
ls //查看当前目录下的文件
cd Desktop/ (Tab 会自动补全唷) //进入桌面
vim main.c //编辑main.c文件
进入vim后点击i进入编辑模式
按下Esc后,点击’Shift‘+ ‘;’ ,输入wq 即可保存
gcc main.c other.c other.h -o main
//把main.c 与other.c 与other.h 文件 编译成main可执行文件
./main //运行文件
基本思想
一般的lrc文件长成这样…
大致思想是…
- 将歌词与时间切割出来
- 用链表使其一句歌词对应一个时间
- 设置时钟函数记录时间
- 最后清屏加时间延迟以及效果显示
下面是代码:
//other.h文件
#ifndef __OTHER_H__ //防止重定义格式
#define __OTHER_H__
struct lrc { //定义一个链表串起时间和歌词
int time; //时间
char lrc_buf[200]; //歌词
int lrc_num; //第几句歌词
struct lrc *next; //链表的指针
};
typedef struct lrc LRC; //结构体重定义
extern char *open_file(); //打开文件函数
extern int strtok_deal(char *f, char **song_line); //歌词切割函数
extern void four_deal(char **song_line, char *four[50]); //对于前四行特殊处理
extern LRC *init(); //确定链表头指针
extern void insert(LRC *p, LRC **head);
extern LRC *divide_deal(char **song_line, int n); //分开时间与歌词
extern void time_delay(int sec); //时间延迟
extern void set_fg_color(int color); //设置前景颜色
extern void clear_screen(void); //清屏函数
extern void set_bg_color(int color); //设置背景颜色
extern void song_print(LRC *head, char **four); //歌词打印+效果
#endif
//other.c
#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
#include"other.h"
char *open_file(){
FILE *fp;
fp = fopen("love.lrc", "rb");
if(fp == NULL) {
printf("NULL!\n");
return 0;
}
fseek(fp, 0L, SEEK_END); //光标定位
int len = ftell(fp); //读取字节以便申请空间
rewind(fp);
char *f = (char *) malloc (len);
fread(f, len, 1, fp); //读取
return f;
}
int strtok_deal(char *f, char **song_line){
char *temp = NULL;
int k = 0;
temp = strtok(f, "\r\n"); //遇‘\r''\n'切割
while(temp){
song_line[k++] = temp; //每行读入
temp = strtok(NULL, "\r\n");
}
return k;
}
void four_deal(char **song_line, char *four[50]){
int i;
for(i = 0; i < 4; i++){
char *temp = strtok(song_line[i], "[]"); //遇'[]'的切割
four[i] = temp;
}
}
LRC* init() {
LRC *p = (LRC *) malloc (sizeof(LRC));
p = NULL;
p->next = NULL;
return p;
}
void insert(LRC *p, LRC **head) { //一边构建链表一边排序(对链表要求较高)
if(*head == NULL) {
*head = p;
return ;
}
LRC *temp = *head, *mid = *head;
while(temp->next && temp->time < p->time){
mid = temp;
temp = temp->next;
}
if(temp->time >= p->time){
p->next = temp;
mid->next = p;
return ;
} else {
temp->next = p;
p->next = NULL;
return ;
}
}
LRC *divide_deal(char **song_line, int n){
char song[100][100], mid[100][100] = {0};
char *temp;
LRC *head = NULL;
int time[50], k = 0, i, m = 0, q = 0, flag[100];
for(i = 0; i < n; i++){
temp = strtok(song_line[i], "[]");
while(temp){
strcpy(mid[k++], temp);
temp = strtok(NULL, "[]");
}
}
for(i = 0; i < k; i++){
if(!isdigit(mid[i][0])){
strcpy(song[q++], mid[i]);
}
}
int j = 0;
for(i = 0; i < k; i++){
if(isdigit(*mid[i])){
char hh[5], mm[5], ss[5];
LRC *p = (LRC *)malloc(sizeof(LRC));
p->time = sscanf(mid[i], "%2s:%2s.%2s", hh, mm, ss);
//这种格式可以让时间以标准形式输出
p->time = atoi(hh)*60 + atoi(mm);
//将时间转化为秒存储到链表中
p->lrc_num = ++m;
strcpy(p->lrc_buf,song[j]);
insert(p, &head); //找准时机,插入链表
} else j++;
}
return head;
}
void time_delay(int sec){
int s_time,e_time;
s_time=time(NULL);
while(1)
{
e_time=time(NULL);
if(e_time==s_time+sec)
break;
}
}
void clear_screen(void){
printf("\033[2J");
fflush(stdout);
}
void set_fg_color(int color){
printf("\033[%dm",color);
fflush(stdout);
}
void set_bg_color(int color){
printf("\033[%dm",(color+10));
fflush(stdout);
}
void cusor_moveto(int x, int y){
printf("\033[%d;%dH",y,x);
fflush(stdout);
}
void song_print(LRC *head, char **four){
int num = 0, y = 0;
LRC *p_mov=head;
LRC *p_mov2;
LRC *p_mov_front=head, *p_mov_front2;
int i,flag=0;
while(1){
clear_screen();
y = 1;
for(i = 0; i < 4; i++){
cusor_moveto(34, y++);
printf("\t\t\t\t\t%s\n", four[i]);
}
cusor_moveto(34, y++);
printf("\t\t\t\t\t %02d:%02d\n", num/60, num%60);
if(flag<4)
p_mov_front=head;
if(num==p_mov->time){
p_mov=p_mov->next;
flag++;
if(flag>4)
p_mov_front=p_mov_front->next;
}
p_mov2 = p_mov;
p_mov_front2=p_mov_front;
while(p_mov_front2!=p_mov){
cusor_moveto(60, y++);
printf("\t%s\n",p_mov_front2->lrc_buf);
p_mov_front2=p_mov_front2->next;
}
for(i=0;i<5;i++){
if(i==0){
set_fg_color(31);
set_bg_color(30);
}else{
set_fg_color(37);
set_bg_color(30);
}
if(p_mov2!=NULL){
cusor_moveto(60, y++); //光标控制
printf("\t%s\n",p_mov2->lrc_buf);
p_mov2=p_mov2->next;
}
}
if(p_mov==NULL)
break;
time_delay(1);
num++;
}
}
//main.c
#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<time.h>
#include"other.h"
int main(){
char *temp = NULL;
char *song_line[100];
int line_num, i;
char *four[50];
temp = open_file(); //open_file 打开文件
LRC *head = NULL;
line_num = strtok_deal(temp, song_line); //hang_strtok
four_deal(song_line, four);
line_num -= 4;
for(i = 0; i < line_num; i++){
song_line[i] = song_line[i+4];
}
head = divide_deal(song_line, line_num);
song_print(head, four);
return 0;
}