我们要明确目的,实现歌曲歌词同步。
1.将歌词文件一次性去取到内存中。(以周董的“简单爱”为例)
a.用fopen打开歌词文件 FILE *fp = fopen(“简单爱.lrc”,"r");(r->只读)
b.使用fseek将文件流指针,要定位到文件尾部,ftell或得文件总大小;
c.使用rewind 复位文件流指针;
d.根据文件总大小从堆区申请合适的空间;
e.使用fread读取文件数据到内存中;
2.将arr指向的内存数据,按行“ ”切割,并存入字符指针数组 char *buf[128] = {NULL};
1 strtok函数切割 2 //arr指向内存存储的歌词 3 char *buf[128]={arr,NULL}; 4 int i=0; 5 //切割 6 while(buf[i++] = strtok(buf[i]," "));
已将歌词的每一行 存放 在 指针数组中 注意 记得保存 切割到的行数
3.逐行分析buf[0]代表第0行,buf[n]代表第n行
a.先单独分析前四行
原数据
[ti:简单爱]
[ar:周杰伦]
[al:范特西]
[by:大脸猫]
要得到的结果:
1 int i=0; 2 for(i=0;i<4;i++) 3 { 4 char tmp[128]=""; 5 //[ti:简单爱] -->sscanf(buf[0],"%*[^:]:%[^]]", tmp);//tmp--简单 6 buf[i];//分析 7 }
b、逐行分析剩下的行 将时间+歌词 一一对应 插入链表
链表节点的设计:
1 typedef struct lrc 2 { 3 //数据域 4 int time; 5 char lrc[128]; 6 7 //指针域 8 struct lrc *next; 9 }LRC;
4.模拟计时器 i++
计时器每走一秒,都会对链表中成员域(time)进行比较,时间相等,则输出成员域歌词(lrc_sentence)
5、滚屏(4行)
//光标定位:(注意)
6、反显 当前歌词为 红色 其他歌词为黑色
7、启动mplayer
6和7步骤都可以直接调用别人的API接口,现在我贴出代码,只可意会不可言传~~~细品
main.c
1 #include "lrc.h" 2 #include "console.h" 3 #include "start_mplayer.h" 4 #include <unistd.h> 5 6 int main(int argc, char *argv[]) 7 { 8 char *lrc_condent = NULL; 9 LRC *head = NULL; 10 char *arr[128]={lrc_condent,NULL}; 11 int i = 0; 12 13 lrc_condent = read_song_lrc("./lrc/简单爱.lrc"); 14 //printf("%s",lrc_condent); 15 arr[0] = lrc_condent; 16 //切割每一行 17 while(arr[i++] = strtok(arr[i]," ")); 18 19 head = lrc_handle(arr, head); 20 21 22 mplayer_play("./song/love.mp3"); 23 lrc_print(head); 24 25 26 return 0; 27 }
lrc.c
1 #include<stdlib.h> 2 #include <unistd.h> 3 #include "lrc.h" 4 #include"console.h" 5 LRC *lrc_create_head() 6 { 7 LRC *head = (LRC*)calloc(1, sizeof(LRC)); 8 head->next = NULL; 9 return head; 10 } 11 //取出歌词 12 char *read_song_lrc(char *lrc_name) 13 { 14 FILE *fp = fopen(lrc_name,"r"); 15 char *lrc_content = NULL; 16 unsigned long int length; 17 if(fp == NULL) 18 { 19 perror("fopen"); 20 return NULL; 21 } 22 23 fseek(fp,0,2); 24 length = ftell(fp); 25 rewind(fp); 26 lrc_content = (char *)calloc(1,length); 27 if (lrc_content == NULL) 28 { 29 perror("calloc"); 30 return NULL; 31 } 32 33 fread(lrc_content,length,1,fp); 34 fclose(fp); 35 36 return lrc_content; 37 } 38 //分割歌词 39 void lrc_strtok(char *lrc_condent) 40 { 41 char *arr[128]={lrc_condent,NULL}; 42 int i = 0; 43 44 while((arr[i++] = strtok(arr[i]," "))); 45 i= 0; 46 while(arr[i] != NULL) 47 printf("%s ", arr[i++]); 48 } 49 //顺序插入 50 LRC * lrc_insert(LRC *head, LRC tmp) 51 { 52 //1、给待插入的节点pi 申请 堆区空间 53 LRC *pi = (LRC *)calloc(1,sizeof(LRC)); 54 if(pi == NULL) 55 { 56 perror("calloc"); 57 return head; 58 } 59 60 //2、将tmp的内容 赋值给 *pi 61 *pi = tmp; 62 pi->next = NULL; 63 64 //3、链表节点pi的插入 65 if(head == NULL)//链表不存在 66 { 67 head = pi; 68 return head; 69 } 70 else//存在 71 { 72 //a、寻找插入点 73 LRC *pb = head, *pf = head; 74 while(pb->time < pi->time && pb->next != NULL) 75 { 76 pf = pb; 77 pb = pb->next; 78 } 79 80 //b、插入点的判断 81 if(pb->time >= pi->time)//头部 中部插入 82 { 83 if(pb == head)//头部之前插入 84 { 85 pi->next = head; 86 head = pi; 87 return head; 88 } 89 else//中部插入 90 { 91 pf->next = pi; 92 pi->next = pb; 93 return head; 94 } 95 } 96 else//尾部插入 97 { 98 pb->next = pi; 99 return head; 100 } 101 } 102 return head; 103 } 104 //处理歌词 105 LRC * lrc_handle(char *buf[128], LRC *head) 106 { 107 int i = 0; 108 //开头的歌手,编曲等字符串 109 char *song_infor[] = {"ti", "ar", "al", "by"}; 110 111 system("clear"); 112 while(buf[i] != NULL) 113 { 114 char flag = 0; 115 sscanf(buf[i],"%*c%c", &flag); 116 if(flag >= '0' && flag <= '9')//除了前四行 117 { 118 char *str_lrc = buf[i], *str_time = buf[i]; 119 //每遇到"["判断是否这句歌词出现的次数 120 while(*str_lrc == '[') 121 str_lrc += 10; 122 123 124 while(*str_time == '[') 125 { 126 LRC temp; 127 int minute = 0, second = 0, ms = 0; 128 //取出每个节点的时分秒 129 sscanf(str_time, "[%d:%d.%d]", &minute, &second, &ms); 130 //统一单位到ms 131 temp.time = minute * 60 + second + ((ms > 50)?1:0);//ms用四舍五入 132 //把歌词内容赋值到该次链表的lrc_sentence 133 strcpy(temp.lrc_sentence, str_lrc); 134 //循环把时间插入链表节点 135 head = lrc_insert(head, temp); 136 str_time += 10; 137 } 138 } 139 140 else 141 { 142 //拆分前四行的,拿到歌曲名等 143 144 char tmp[128]=""; 145 sscanf(buf[i], "%*[^:]:%[^]]", tmp); 146 if(i==0) 147 { 148 cusor_moveto(17,1); 149 printf("%s ", tmp); 150 } 151 else if(i==1) 152 { 153 cusor_moveto(17,2); 154 printf("%s ", tmp); 155 } 156 else if(i==2) 157 { 158 cusor_moveto(17,3); 159 printf("%s ", tmp); 160 } 161 else if(i==3) 162 { 163 cusor_moveto(17,4); 164 printf("%s ", tmp); 165 } 166 } 167 i++; 168 } 169 170 return head; 171 } 172 //歌词滚屏 173 int times = 0; 174 int screen = 0; 175 176 LRC* lrc_print(LRC *head) 177 { 178 int time=0; 179 char buf1[128]=""; 180 char buf2[128]=""; 181 char buf3[128]=""; 182 char buf4[128]=""; 183 while(1) 184 { 185 //光标定位 186 cusor_moveto(20,6); 187 printf("%02d:%02d",time/60,time%60 ); 188 fflush(stdout); 189 190 LRC *ret = search_link(head, time); 191 if(ret != NULL) 192 { 193 //滚起来 194 strcpy(buf1,buf2); 195 strcpy(buf2,buf3); 196 strcpy(buf3,buf4); 197 strcpy(buf4, ret->lrc_sentence); 198 199 cusor_moveto(15,8); 200 printf("%s ", buf1); 201 202 cusor_moveto(15,9); 203 printf("%s ", buf2); 204 205 cusor_moveto(15,10); 206 printf("%s ", buf3); 207 208 cusor_moveto(15,11); 209 set_fg_color(COLOR_RED); 210 printf("%s ", buf4);//当前歌词 211 set_fg_color(COLOR_BLACK ); 212 fflush(stdout); 213 } 214 //滚屏显示歌词 215 //第一行 216 217 218 sleep(1); 219 time++; 220 } 221 222 } 223 224 LRC* search_link(LRC *head, int time) 225 { 226 //1、判断链表是否存在 227 if(head == NULL)//不存在 228 { 229 printf("link not found "); 230 return NULL; 231 } 232 else//链表存在 233 { 234 LRC *pb = head; 235 236 //逐个将节点中的name 和 name比较 如果不相等 pb=pb->next 237 while(pb->time != time && pb->next != NULL) 238 pb = pb->next; 239 240 //判断是否找到 241 if(pb->time == time)//找到 242 return pb; 243 else//没找到 244 return NULL; 245 } 246 247 return NULL; 248 } 249 250 void mplayer_play(char * song_path) 251 { 252 pid_t pid; 253 pid=fork(); 254 if(pid<0) 255 { 256 perror("fork"); 257 } 258 else if(pid==0) 259 { 260 close(1); 261 close(2); 262 execlp("mplayer","mplayer","-slave","-quiet",song_path,NULL); 263 exit(0); 264 } 265 else; 266 }
lrc.h
1 #ifndef __LRC_H__ 2 #define __LRC_H__ 3 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <string.h> 7 8 typedef struct lrc 9 { 10 int time; 11 char lrc_sentence[128]; 12 13 struct lrc *next; 14 }LRC; 15 //创造链表头 16 LRC *lrc_create_head(void); 17 //顺序插入 18 LRC * lrc_insert(LRC *head, LRC tmp); 19 //读取歌词 20 char *read_song_lrc(char *lrc_name); 21 //切割歌词 22 void lrc_strtok(char *lrc_condent); 23 //处理歌词 24 LRC * lrc_handle(char *buf[128], LRC *head); 25 //遍历歌词 26 LRC* lrc_print(LRC *head); 27 extern LRC* search_link(LRC *head, int time); 28 void mplayer_play(char * song_path); 29 30 #endif
----------------------好的,我的第一阶段项目总结完了,写的不好,还请见谅----------------------