欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Ubuntu下实现歌词解析

程序员文章站 2022-03-26 12:28:34
我们要明确目的,实现歌曲歌词同步。 1.将歌词文件一次性去取到内存中。(以周董的“简单爱”为例) a.用fopen打开歌词文件 FILE *fp = fopen(“简单爱.lrc”,"r");(r->只读) b.使用fseek将文件流指针,要定位到文件尾部,ftell或得文件总大小; c.使用rew ......

我们要明确目的,实现歌曲歌词同步。

1.将歌词文件一次性去取到内存中。(以周董的“简单爱”为例)

a.用fopen打开歌词文件 file *fp  = fopen(“简单爱.lrc”,"r");(r->只读)

b.使用fseek将文件流指针,要定位到文件尾部,ftell或得文件总大小;

c.使用rewind 复位文件流指针;

d.根据文件总大小从堆区申请合适的空间;

e.使用fread读取文件数据到内存中;

 

2.将arr指向的内存数据,按行“\r\n”切割,并存入字符指针数组 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],"\r\n"));

已将歌词的每一行 存放 在 指针数组中 注意 记得保存 切割到的行数

3.逐行分析buf[0]代表第0行,buf[n]代表第n行

a.先单独分析前四行

原数据

[ti:简单爱]
[ar:周杰伦]
[al:范特西]
[by:大脸猫]

要得到的结果:

Ubuntu下实现歌词解析

 

 

 

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],"\r\n"));
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],"\r\n")));
 45     i= 0;
 46     while(arr[i] != null)
 47         printf("%s\n", 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\n", tmp);
150             }
151             else if(i==1)
152             {
153                 cusor_moveto(17,2);
154                 printf("%s\n", tmp);
155             }
156             else if(i==2)
157             {
158                 cusor_moveto(17,3);
159                 printf("%s\n", tmp);
160             }
161             else if(i==3)
162             {
163                 cusor_moveto(17,4);
164                 printf("%s\n", 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\n");
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

----------------------好的,我的第一阶段项目总结完了,写的不好,还请见谅----------------------