做了个音乐播放器的项目,要求能实现分析歌词,歌词滚屏,唱到的那一句显示红色。
可以通过数字键1,2来选择要播放的歌曲,但是要按三遍。
附上源码:
main.c:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"start_mplayer.h"
#include"console.h"
int main(int argc,charargv[])
{ int b =0;
printf(“敲3次1:简单爱\n”);
printf(“敲3次2:山水之间\n”);
scanf("%d\n",&b);
/ while(b1||b2)
{*/
if (b1)
{mplayer_play(“简单爱.mp3”);}
else if(b2)
{mplayer_play(“山水之间.mp3”);}
//mplayer_play(“简单爱.mp3”);
char *arr=NULL;
arr = geci(arr);
char*buf[128]={NULL};
int a = 0;
a = cut_geci(buf,arr);
printf("歌词一共%d行\n",a);
char *last_time = buf[a-1];
int min = 0,sec = 0;
sscanf(last_time,"[%d:%d.64]",&min,&sec);
int end_time = min*60+sec+5;
cusor_hide();
int i=0;
for(i=0;i<4;i++)
{
set_fg_color(COLOR_MAGENTA);
char tmp[128]="";
sscanf(buf[i],"%*[:]:%[]]",tmp);
switch (i)
{
case 0:
printf(“歌名:%s\n”,tmp);
break;
case 1:
printf(“歌手名:%s\n”,tmp);
break;
case 2:
printf(“作词:%s\n”,tmp);
break;
case 3:
printf(“作曲:%s\n\n”,tmp);
break;
default:
break;
}
}
i=4;
LRC *head=NULL;
for(i=4;i<a;i++)
{
char *str_lrc = buf[i];
//[03:34.64][02:34.71][01:05.83]我想就这样牵着你的手不放开
//1、寻找歌词的位置
while(*str_lrc == ‘[’)
str_lrc +=10;
//str_lrc指向了歌词的位置
//逐个时间分析
char *str_time = buf[i];
while(str_time == ‘[’)
{
int m = 0,s = 0;
sscanf(str_time,"[%d:%d.64]", &m,&s);
int time = m60+s;//以秒为单位
//将时间 和 歌词 一一对应 放入 结构体
LRC tmp;
tmp.time = time;
strcpy(tmp.lrc, str_lrc);
//调用链表的有序插入函数
head = insert_link(head,tmp);
//分析下一个时间
str_time += 10;
}
}
// print_link(head);
i=0;
int j=0;
char buf1[128]="";
char buf2[128]="";
char buf3[128]="";
char buf4[128]="";
while(i<260)
{
cusor_moveto(40,6);
set_fg_color(COLOR_RED);
printf("%02d:%02d",i/60,i%60);
fflush(stdout);
set_fg_color(COLOR_WHITE);
//到链表查询
LRC *ret = search_lrc(head,i);
if(ret != NULL)
{
my_strcpy(buf1,buf2);
my_strcpy(buf2,buf3);
my_strcpy(buf3,buf4);
my_strcpy(buf4, ret->lrc);
cusor_moveto(30,7);
printf("%s ", buf1);
cusor_moveto(30,8);
printf("%s ", buf2);
cusor_moveto(30,9);
printf("%s ", buf3);
cusor_moveto(30,10);
set_fg_color(COLOR_RED);
printf("%s ", buf4);//当前歌词
set_fg_color(COLOR_WHITE);
fflush(stdout);
}
sleep(1);//休眠1s
cusor_moveto(0,12);
printf("进度:%ds\n",i);
cusor_moveto(80,12);
printf("总时长:%ds",end_time);
i++;
if(i%3!=0)
{ cusor_moveto((i/3)+6,12);
printf(">");}
}
/*
cusor_moveto(30,11);
char abb[128]="";
if(i==end_time)
printf(“你想继续吗?yes or no\n”);
scanf("%s",abb);
if(strcmp(abb,“no”)==0)
{
break;
}
else if(strcmp(abb,“yes”)==0)
{
continue;
}
else
{
printf(“你输得啥呀,不对!”);
}*/
return 0;}
fun.c
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct lrc
{
int time;
char lrc[128];
struct lrc *next;
}LRC;
char* geci (char*arr)
{
long file_len = 0;
FILE *fp = NULL;
int b=0;
scanf("%d\n",&b);
if (b1)
{
fp = fopen(“简单爱.lrc”,“r”);
}
else if(b2)
{
fp = fopen(“山水之间.lrc”,“r”);
}
if(fp == NULL)
{
perror("fopen");
return;
}
//打开文件
fseek(fp, 0, 2);
file_len = ftell(fp);
rewind(fp);
arr = (char *)calloc(1,file_len+1);
if(arr == NULL)
{
fclose(fp);
return ;
}
fread(arr, file_len, 1, fp);
//printf("file_len=%ld\n", file_len);
//printf("%s\n", buf);
fclose(fp);
return arr;
}
int cut_geci(charbuf[],chararr)
{
int i=0;
buf[i] = strtok(arr,"\r\n");
while(buf[i]!=NULL)
{
i++;
buf[i] = strtok(NULL,"\r\n");
}
return i;
}
//双向链表
/*
LRCinsert_link(LRChead,LRC tmp)
{
LRC *pi = (LRC *)calloc(1,sizeof(LRC));
if(pi == NULL)
{
perror(“calloc”);
return head;
}
*pi = tmp;
pi->next = NULL;
if(head == NULL)
{
head = pi;
return head;
}
else
{
LRC*pb =head,*pf = head;
while(pb->time<pi->time&&pb->next!= NULL)
{
pf = pb;
pb =pb->next;
}
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;
}
void print_link(LRC *head)
{
//判断链表是否存在
if(head == NULL)
{
printf(“link not found\n”);
return;
}
else//链表存在
{
LRC pb = head;
do
{
//访问节点内容
printf(“time=%d, geci=%s\n”, pb->time,pb->lrc);
//pb指向下一个节点
pb = pb->next;
}while(pb != head);
}
return;
}/
LRC* insert_link(LRC *head, LRC tmp)
{
//1、给待插入的节点pi 申请 堆区空间
LRC *pi = (LRC *)calloc(1,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;
}
/*void print_link(LRC *head)
{
if(head == NULL)//链表不存在
{
printf(“link not find\n”);
return;
}
else
{
LRC *pb = head;
while(pb != NULL)
{
printf(“time=%d geci:%s\n”, pb->time, pb->lrc);
//pb指向下一个节点
pb = pb->next;
}
}
return;
}*/
LRC* search_lrc(LRC *head, int i)
{
//1、判断链表是否存在
if(head == NULL)//不存在
{
printf(“link not found\n”);
return NULL;
}
else//链表存在
{
LRC *pb = head;
//逐个将节点中的time 和 i比较 如果不相等 pb=pb->next
while(pb->time!=i && pb->next != NULL)
pb = pb->next;
//判断是否找到
if(pb->time == i)//找到
return pb;
else//没找到
return NULL;
}
return NULL;
}
char *my_strcpy(char *dst,const char *src)
{
#if 0
do
{
*dst = *src;
dst++;
src++;
}while(*src != ‘\0’);
*dst=’\0’;
#endif
while(*dst++ = *src++);
}
(注释掉的部分是存在问题的双链表插入和遍历)
start_mplyer.h
#ifndef START_MPLAYER_H
#define START_MPLAYER_H
//启动mplayer播放器
//参数song_path 为歌曲的路径
typedef struct lrc
{
int time;
char lrc[128];
struct lrc *next;
}LRC;
extern void mplayer_play(char * song_path);
extern char *geci(char *arr);
extern int cut_geci(char buf[],char arr);
extern LRCinsert_link(LRChead,LRC tmp);
//extern void print_link(LRC head);
extern LRCsearch_lrc(LRC *head,int i);
extern char *my_strcpy(char *dst,const char *src);
#endif
start_mplayer.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
//启动mplayer播放器
//参数song_path 为歌曲的路径
void mplayer_play(char * song_path)
{
pid_t pid;
pid=fork();
if(pid<0)
{
perror(“fork”);
}
else if(pid==0)
{
close(1);
close(2);
execlp(“mplayer”,“mplayer”,"-slave","-quiet",song_path,NULL);
exit(0);
}
else
;
}
另外使用了光标定位和颜色变换的程序
Makefile:
exec=main
cc=gcc
obj=main.o start_mplayer.o fun.o console.o
cflags=-Wall -g
(
e
x
e
c
)
:
(exec):
(exec):(obj)
$(cc) $^ -o $@ $(cflags)
%.o:%.c
$(cc) -c $< -o $@ $(cflags)
clean:
rm $(exec) *.o
cosole.c
#include <stdio.h>
#include <stdlib.h>
#include “console.h”
void cusor_moveto(int x, int y)
{// ESC[y;xH
printf("\033[%d;%dH",y,x);
fflush(stdout);
}
//保存光标位置
void cusor_get_pos(void)
{// ESC[s
printf("\033[s");
fflush(stdout);
}
//恢复光标位置
void cusor_set_pos(void)
{// ESC[u
printf("\033[u");
fflush(stdout);
}
//隐藏光标
void cusor_hide(void)
{
printf("\033[?25l");
}
//显示光标
void cusor_show(void)
{
printf("\33[?25h");
}
//清屏
void clear_screen(void)
{// ESC[2J
printf("\033[2J");
fflush(stdout);
}
/*
COLOR_RED 红
COLOR_BLACK 黑
COLOR_GREEN 绿
COLOR_BLUE 蓝
COLOR_YELLOW 黄
COLOR_WHITE 白
COLOR_CYAN 青
COLOR_MAGENTA 洋红
*/
//设置前景颜色
void set_fg_color(int color)
{// ESC[#m
printf("\033[%dm",color);
fflush(stdout);
}
//设置背景颜色
void set_bg_color(int color)
{// ESC[#m
printf("\033[%dm",(color+10));
fflush(stdout);
}
congsole.h
#ifndef CONSOLE_H
#define CONSOLE_H
#define COLOR_RED 31
#define COLOR_BLACK 30
#define COLOR_GREEN 32
#define COLOR_BLUE 34
#define COLOR_YELLOW 33
#define COLOR_WHITE 37
#define COLOR_CYAN 36
#define COLOR_MAGENTA 35
/*
COLOR_RED 红
COLOR_BLACK 黑
COLOR_GREEN 绿
COLOR_BLUE 蓝
COLOR_YELLOW 黄
COLOR_WHITE 白
COLOR_CYAN 青
COLOR_MAGENTA 洋红
*/
extern void cusor_moveto(int x, int y);//光标跳转到 y行 x列
extern void cusor_get_pos(void);//保存光标位置
extern void cusor_hide(void);//隐藏光标
extern void cusor_show(void);//显示光标
extern void cusor_set_pos(void);//恢复光标位置
extern void clear_screen(void);//清屏
extern void set_fg_color(int color);//设置字体前景色
extern void set_bg_color(int color);//设置字体背景色
#endif //CONSOLE_H