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

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

 strtok函数切割
//arr指向内存存储的歌词
char *buf[]={arr,NULL};
int i=;
//切割
while(buf[i++] = strtok(buf[i],"\r\n"));

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

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

a.先单独分析前四行

原数据

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

要得到的结果:

 int i=;
for(i=;i<;i++)
{
char tmp[]="";
//[ti:简单爱] -->sscanf(buf[0],"%*[^:]:%[^]]", tmp);//tmp--简单
buf[i];//分析
}

b、逐行分析剩下的行 将时间+歌词 一一对应 插入链表

链表节点的设计:

 typedef struct lrc
{
//数据域
int time;
char lrc[]; //指针域
struct lrc *next;
}LRC;

4.模拟计时器 i++

计时器每走一秒,都会对链表中成员域(time)进行比较,时间相等,则输出成员域歌词(lrc_sentence)

5、滚屏(4行)

//光标定位:(注意)

6、反显 当前歌词为 红色 其他歌词为黑色

7、启动mplayer

6和7步骤都可以直接调用别人的API接口,现在我贴出代码,只可意会不可言传~~~细品

main.c

 #include "lrc.h"
#include "console.h"
#include "start_mplayer.h"
#include <unistd.h> int main(int argc, char *argv[])
{
char *lrc_condent = NULL;
LRC *head = NULL;
char *arr[]={lrc_condent,NULL};
int i = ; lrc_condent = read_song_lrc("./lrc/简单爱.lrc");
//printf("%s",lrc_condent);
arr[] = lrc_condent;
//切割每一行
while(arr[i++] = strtok(arr[i],"\r\n")); head = lrc_handle(arr, head); mplayer_play("./song/love.mp3");
lrc_print(head); return ;
}

lrc.c

 #include<stdlib.h>
#include <unistd.h>
#include "lrc.h"
#include"console.h"
LRC *lrc_create_head()
{
LRC *head = (LRC*)calloc(, sizeof(LRC));
head->next = NULL;
return head;
}
//取出歌词
char *read_song_lrc(char *lrc_name)
{
FILE *fp = fopen(lrc_name,"r");
char *lrc_content = NULL;
unsigned long int length;
if(fp == NULL)
{
perror("fopen");
return NULL;
} fseek(fp,,);
length = ftell(fp);
rewind(fp);
lrc_content = (char *)calloc(,length);
if (lrc_content == NULL)
{
perror("calloc");
return NULL;
} fread(lrc_content,length,,fp);
fclose(fp); return lrc_content;
}
//分割歌词
void lrc_strtok(char *lrc_condent)
{
char *arr[]={lrc_condent,NULL};
int i = ; while((arr[i++] = strtok(arr[i],"\r\n")));
i= ;
while(arr[i] != NULL)
printf("%s\n", arr[i++]);
}
//顺序插入
LRC * lrc_insert(LRC *head, LRC tmp)
{
//1、给待插入的节点pi 申请 堆区空间
LRC *pi = (LRC *)calloc(,sizeof(LRC));
if(pi == NULL)
{
perror("calloc");
return head;
} //2、将tmp的内容 赋值给 *pi
*pi = tmp;
pi->next = NULL; //3、链表节点pi的插入
if(head == NULL)//链表不存在
{
head = pi;
return head;
}
else//存在
{
//a、寻找插入点
LRC *pb = head, *pf = head;
while(pb->time < pi->time && pb->next != NULL)
{
pf = pb;
pb = pb->next;
} //b、插入点的判断
if(pb->time >= pi->time)//头部 中部插入
{
if(pb == head)//头部之前插入
{
pi->next = head;
head = pi;
return head;
}
else//中部插入
{
pf->next = pi;
pi->next = pb;
return head;
}
}
else//尾部插入
{
pb->next = pi;
return head;
}
}
return head;
}
//处理歌词
LRC * lrc_handle(char *buf[], LRC *head)
{
int i = ;
//开头的歌手,编曲等字符串
char *song_infor[] = {"ti", "ar", "al", "by"}; system("clear");
while(buf[i] != NULL)
{
char flag = ;
sscanf(buf[i],"%*c%c", &flag);
if(flag >= '' && flag <= '')//除了前四行
{
char *str_lrc = buf[i], *str_time = buf[i];
//每遇到"["判断是否这句歌词出现的次数
while(*str_lrc == '[')
str_lrc += ; while(*str_time == '[')
{
LRC temp;
int minute = , second = , ms = ;
//取出每个节点的时分秒
sscanf(str_time, "[%d:%d.%d]", &minute, &second, &ms);
//统一单位到ms
temp.time = minute * + second + ((ms > )?:);//ms用四舍五入
//把歌词内容赋值到该次链表的lrc_sentence
strcpy(temp.lrc_sentence, str_lrc);
//循环把时间插入链表节点
head = lrc_insert(head, temp);
str_time += ;
}
} else
{
//拆分前四行的,拿到歌曲名等 char tmp[]="";
sscanf(buf[i], "%*[^:]:%[^]]", tmp);
if(i==)
{
cusor_moveto(,);
printf("%s\n", tmp);
}
else if(i==)
{
cusor_moveto(,);
printf("%s\n", tmp);
}
else if(i==)
{
cusor_moveto(,);
printf("%s\n", tmp);
}
else if(i==)
{
cusor_moveto(,);
printf("%s\n", tmp);
}
}
i++;
} return head;
}
//歌词滚屏
int times = ;
int screen = ; LRC* lrc_print(LRC *head)
{
int time=;
char buf1[]="";
char buf2[]="";
char buf3[]="";
char buf4[]="";
while()
{
//光标定位
cusor_moveto(,);
printf("%02d:%02d",time/,time% );
fflush(stdout); LRC *ret = search_link(head, time);
if(ret != NULL)
{
//滚起来
strcpy(buf1,buf2);
strcpy(buf2,buf3);
strcpy(buf3,buf4);
strcpy(buf4, ret->lrc_sentence); cusor_moveto(,);
printf("%s ", buf1); cusor_moveto(,);
printf("%s ", buf2); cusor_moveto(,);
printf("%s ", buf3); cusor_moveto(,);
set_fg_color(COLOR_RED);
printf("%s ", buf4);//当前歌词
set_fg_color(COLOR_BLACK );
fflush(stdout);
}
//滚屏显示歌词
//第一行 sleep();
time++;
} } LRC* search_link(LRC *head, int time)
{
//1、判断链表是否存在
if(head == NULL)//不存在
{
printf("link not found\n");
return NULL;
}
else//链表存在
{
LRC *pb = head; //逐个将节点中的name 和 name比较 如果不相等 pb=pb->next
while(pb->time != time && pb->next != NULL)
pb = pb->next; //判断是否找到
if(pb->time == time)//找到
return pb;
else//没找到
return NULL;
} return NULL;
} void mplayer_play(char * song_path)
{
pid_t pid;
pid=fork();
if(pid<)
{
perror("fork");
}
else if(pid==)
{
close();
close();
execlp("mplayer","mplayer","-slave","-quiet",song_path,NULL);
exit();
}
else;
}

lrc.h

 #ifndef __LRC_H__
#define __LRC_H__ #include <stdio.h>
#include <stdlib.h>
#include <string.h> typedef struct lrc
{
int time;
char lrc_sentence[]; struct lrc *next;
}LRC;
//创造链表头
LRC *lrc_create_head(void);
//顺序插入
LRC * lrc_insert(LRC *head, LRC tmp);
//读取歌词
char *read_song_lrc(char *lrc_name);
//切割歌词
void lrc_strtok(char *lrc_condent);
//处理歌词
LRC * lrc_handle(char *buf[], LRC *head);
//遍历歌词
LRC* lrc_print(LRC *head);
extern LRC* search_link(LRC *head, int time);
void mplayer_play(char * song_path); #endif

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

Ubuntu下实现歌词解析的更多相关文章

  1. 解决Ubuntu下Apache不解析PHP问题

    这两天笔者遇到了一个很操蛋的问题——Apache无法解析PHP代码了,之前一直用的挺好的,突然就挂了,然后在网上疯狂的找解决办法,但是大都是php5的版本,而我却是7的版本,我就先顺便把5版本的解决方 ...

  2. ubuntu下解析udt数据包

    udt是通过udp进行端到端可靠传输的一个协议,有其默认拥塞控制算法. 之前ubuntu下wireshark的版本是1.10,不能直接解析udt数据包[1],升级到最新的2.0.0即可过滤udt数据包 ...

  3. Ubuntu下安装JDK以及相关配置

    1.查看系统位数,输入以下命令即可 getconf LONG_BIT 2.下载对应的JDK文件,我这里下载的是jdk-8u60-linux-64.tar.gz 3.创建目录作为JDK的安装目录,这里选 ...

  4. ubuntu下升级R版本

    ubuntu下升级R版本   在测试<机器学习 实用案例解析>一书的邮件分类代码时,windows系统下rstudio中无法读取特殊字符,在ubuntu下可以.在ubuntu虚拟机下安装t ...

  5. Ubuntu下的PHP开发环境架设

    Ubuntu下的PHP开发环境架设   今天重新装了ubuntu那么就吧过程记录下. 打开终端,也就是命令提示符. 我们先来最小化组建安装,按照自己的需求一步一步装其他扩展.命令提示符输入如下命令: ...

  6. ubuntu 下wireshark 软件安装与使用

    在ubuntu下,使用wireshark也是很有必要的.虽然可以使用tcpdump等工具. ubuntu:11.10     1. sudo apt-get install wireshark     ...

  7. ubuntu下配置hosts

    由于Chrome浏览器访问问题,需要配置hosts. 在Ubuntu系统下,需要修改/etc/hosts文件,修改完之后要重启网络.具体过程如下:1.修改hostssudo vi /etc/hosts ...

  8. [转载]--Ubuntu下修改DNS重启也能用的方法

    安装好Ubuntu之后设置了静态IP地址,再重启后就无法解析域名.想重新设置一下DNS,打开/etc/resolv.conf cat /etc/resolv.conf# Dynamic resolv. ...

  9. Ubuntu下sqlite3的安装及使用

    Sqlite是一款轻型的数据库,实现了多数SQL-92标准,包括事务(原子性,一致性,隔离性和持久性 ACID),触发器与多数复杂查询.对于一个移动手持设备的应用开发者,Sqlite是居家旅行必备数据 ...

随机推荐

  1. python3的数据类型转换问题

    问题描述:在自我学习的过程中,写了个登陆,在input处,希望能够对数据类型进行判断,但是因为python3的输入的数据会被系统默认为字符串,也就是1,1.2,a.都会被系统默认为字符串,这个心塞啊, ...

  2. The Monster(Codeforce-C-思维题)

    C. The Monster time limit per test 1 second memory limit per test 256 megabytes   As Will is stuck i ...

  3. 阿里云服务器上搭建seafile专业版

    因为官方一键安装教程在阿里云服务器上无法安装,由于水平有限,无法解决,所以选择手动安装 参考资料: 1,.腾讯云搭建seafile服务器 2.How to Install Seafile with N ...

  4. 阿里云vpc网络SNAT实现内网实例通外网

    需求场景: 因费用和安全考虑,内网部分机器没有分配公网IP,没绑定弹性公网IP,没有购买NAT服务,但是内网机器需要访问外网部分资源,如发送邮件. 操作步骤如下: 1.查看外网上的转发功能的开启没开启 ...

  5. 【内推】平安产险大数据测试开发工程师,15-30k!

    平安产险技术岗内部推荐-大数据测试开发工程师等-欢迎中年人和2020应届生 上班地点:深圳福田平安金融中心 另有大量 上海 北京 成都 广州 岗位 交流qq群 828186629 微信pythonte ...

  6. [BZOJ 1412][ZJOI 2009] 狼和羊的故事

    题目大意 有一个 (n times m) 的网格,每一个格子上是羊.狼.空地中的一种,羊和狼可以走上空地.现要在格子边上建立围栏,求把狼羊分离的最少围栏数. (1 leqslant n, ; m le ...

  7. songCMS 3.15 cookie SQLINJ

    ./code/profile.php ... $db = new db(); $SQL = "SELECT * FROM `{$dbprefix}user` WHERE `ID` = {$_ ...

  8. 安卓权威编程指南-笔记(第27章 broadcast intent)

    本章需求:首先,让应用轮询新结果并在有所发现时及时通知用户,即使用户重启设备后还没有打开过应用.其次,保证用户在使用应用时不出现新结果通知. 1. 一般intent和broadcast intent ...

  9. Git的安装与TortoiseGit的安装和汉化

    下载Git 进入https://git-scm.com/downloads 可以看到如下界面 因为我是windows系统,选择windows即可. 有的朋友因为网络慢的一些原因不能很快下载下来,可以进 ...

  10. 01.JS块级作用域与let

    1.块级作用域   什么是:         在一个代码块(括在一对花括号中的一组语句)中定义的所需变量(与let配合使用)并在代码块的外部是不可见的.   为什么:         在ES6之前,函 ...