zoukankan      html  css  js  c++  java
  • Ubuntu下实现歌词解析

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

    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

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

  • 相关阅读:
    R绘图 第七篇:绘制条形图(ggplot2)
    R实战 第11篇:处理缺失值
    R实战 第十篇:列联表和频数表
    贝叶斯概率
    分析思维 第三篇:数据分析的三板斧
    分析思维 第二篇:数据指标体系
    分析思维 第一篇:认识数据
    R数据挖掘 第三篇:聚类的评估(簇数确定和轮廓系数)和可视化
    R数据挖掘 第二篇:基于距离评估数据的相似性和相异性
    R数据挖掘 第一篇:聚类分析(划分)
  • 原文地址:https://www.cnblogs.com/loliconinvincible/p/12459725.html
Copyright © 2011-2022 走看看