實現功能:歌詞對應,歌詞滾屏顯示,歌詞總時長,多首歌曲選擇播放,進度條(附加動畫)
成果演示:代碼
主函數代碼:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include"start_mplayer/start_mplayer.h"
#include"fun/fun.h"
#include "fun/console.h"
int main(int argc, char const *argv[])
{
while (1)
{
int sim_time = 0;//模擬時鐘時間
unsigned long lrc_length = 0;//歌詞總長度
char *ret = NULL;//存放所有歌詞的地址
char *str[128]={NULL} ;//分行後的歌詞地址數組
int line = 0,rea_line = 0;//line爲切割分的歌詞行數,rea_line 爲歌詞總時長
LRC *head = NULL;//鏈表頭
char cmd[16]="";//存放指令
char song[32]="";//歌詞名
//提示並輸入歌曲
clear_screen();
cusor_show();
cusor_moveto(5,15);
printf("歌庫現存:簡單愛 只因你太美 野狼 霧裏看花 烤麪筋 Lemon 大花轎\n");//自己添加歌曲
cusor_moveto(5,16);
printf("Please choose the song you want to listen to:\n ");
cusor_moveto(5,17);
scanf("%s",song);
//獲取歌詞
ret = get_lrc(&lrc_length,ret,song);
if (NULL == ret)
{
cusor_moveto(20,19);
printf("該歌曲尚未收錄!!!\n");
cusor_moveto(20,20);
printf("拜拜了寶貝T.T\n");
sleep(2);
cusor_moveto(20,20);
printf("真的要退出了呢 \n");
sleep(2);
cusor_moveto(20,20);
printf("退出成功!!!T.T \n");
sleep(2);
clear_screen();
cusor_show();
return 0;
}
//printf("lrc_length=%lu,%p\n",lrc_length,ret);
//歌詞分行
line = cut_lrc(ret,str);
//printf("%d",line);
//歌詞存放
head = save_lrc(head,str,line);
rea_line = print_link(head);//獲取歌詞時長
//printf("%d",rea_line);
//播放歌曲
mplayer_play(song);
//啓動模擬時鐘,進行輸出
sim_clock(head,str,sim_time,rea_line);
//放完一首歌,進行人機交互
cusor_moveto(20,23);
printf("Do you want to keep listening?yes or no\n");
cusor_moveto(20,24);
scanf("%s",cmd);
if (strcmp(cmd,"no")==0)
{
break;
}
else if (strcmp(cmd,"yes")==0)
{
continue;
}
else
{
printf("I don't know,I'm going to default to yes!\n");
}
free(*str);
}
return 0;
}
功能函數:
包括獲取歌詞,將歌詞分行,每句歌詞存進鏈表節點,模擬時鐘,查找對應時間的歌詞
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include <math.h>
#include"fun.h"
#include "console.h"
因爲這裏是將歌詞放在了一個子文件夾song裏,所以獲取歌詞時候要注意文件地址
/**********************獲取歌詞******************/
char * get_lrc(unsigned long *length,char *data,char *path)
{
char buf[32]="";
sprintf(buf,"./song/%s.lrc",path);
FILE *fp = NULL;
fp = fopen(buf,"r");
if (NULL == fp)
return NULL;
sscanf(buf,"%[^lrc]",path);
/**********************獲取文件長度******************/
fseek(fp,0,2);//流指針指到末尾
*length = ftell(fp);//獲取長度
rewind(fp);//指針復位
//申請堆區空間
data = (char *)calloc(1,*length);
if (NULL == data)
{
perror("calloc");
return NULL ;
}
//一次性讀取內容
fread(data,*length,1,fp);
//關閉文件
fclose(fp);
return data;
}
strtok函數切割歌詞
/**********************歌詞分行******************/
int cut_lrc(char *buf,char **str)
{
int i = 0;
//第一次切割
str[i] = strtok(buf, "\r\n");
//第2~n切割
while(str[i] != NULL)//保證上一次切割正常 纔有進行下一次切割的必要
{
i++;
str[i] = strtok(NULL,"\r\n");
//while(str[i++] = strtok(str[i],"\r\n"));
}
return i;
}
/**********************歌詞存放******************/
/**********************前四行*******************/
void save_lrc_four(char **str)
{
int i = 0;
char tmp[32]="",name[32]="";
for(i=0;i<4;i++)
{
sscanf(str[i],"[%[^:]:%[^]]",tmp,name);
if (strcmp(tmp,"ti") == 0)
{
set_fg_color(COLOR_BLUE);
cusor_moveto(45, 2);
printf("歌名:%s\n",name);
}
else if (strcmp(tmp,"ar") == 0)
{
cusor_moveto(45, 3);
printf("歌手:%s\n",name);
}
else if (strcmp(tmp,"al") == 0)
{
cusor_moveto(45, 4);
printf("專輯:%s\n",name);
}
else if (strcmp(tmp,"by") == 0)
{
cusor_moveto(45, 5);
printf("來自:%s\n",name);
}
}
return;
}
/**********************歌詞內容存放******************/
LRC * save_lrc(LRC *head,char **str,int n)
{
LRC pb;
int i = 0;
//歌詞輸出
for ( i = 4; i < n; i++)
{
char *str_lrc = str[i];
//指向歌詞位置
while('[' == *str_lrc)
str_lrc += 10;
//時間用s爲單位
char *str_time = str[i];
while ('[' == *str_time)
{
int min = 0,sec = 0,time = 0;
sscanf(str_time,"[%d:%d:%*d]",&min,&sec);
time = min*60+sec;
//printf("%d\n",time);
//時間,歌詞一一對應插入鏈表節點
pb.time = time;
strcpy(pb.lrc,str_lrc);
//有序插入
head = insert_link(head,pb);
str_time += 10;
}
}
return head;
}
有序插入的方法將歌詞放入鏈表儲存
/**********************有序插入******************/
LRC * insert_link(LRC *head,LRC pb)
{
LRC *pi = (LRC *)calloc(1,sizeof(LRC));
if (NULL ==pi)
{
perror("calloc");
return head;
}
//pb賦值給pi
*pi = pb;
pi->next = NULL;
if (NULL == head)
{
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;
}
}
}
查找與時間對應的歌詞
/**********************查找節點******************/
LRC* search_link(LRC *head, int time)
{
//1、判斷鏈表是否存在
if(head == NULL)//不存在
{
printf("link not found\n");
return NULL;
}
else//鏈表存在
{
LRC *pb = head;
//逐個將節點中的time 和 time比較 如果不相等 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 sim_clock(LRC *head,char **str,int time,int end)
{
LRC *ret = NULL;
char buf[12][128]={""};
int n=5, x, y;
char prb[31]="******************************";//30個*
int s = 0;
clear_screen();
cusor_moveto(0,5);
save_lrc_four(str);
while(1)
{
/**********************大風車啊吱悠悠的轉******************/
if (time %2 == 0)
{
cusor_moveto(0,3);
for (y = 2 * n + 1; y >= -2 * n - 1; y--)
{
for (x = -2 * n - 1; x <= 2 * n + 1; x++)
{
if (x == 0 && y == 0)putchar(' ');
else if (abs(x) + abs(y) <= 2 * n + 1 && (x==0||y==0||(double)y/x>fabs((double)y/x)/((double)y/x)))putchar('*');
else putchar(' ');
}
putchar('\n');
}
}
else
{
cusor_moveto(0,3);
for (x = 2 * n + 1; x >= -2 * n - 1; x--)
{
for (y = -2 * n - 1; y <= 2 * n + 1; y++)
{
if (y == 0 && x == 0)putchar(' ');
else if (abs(y) + abs(x) <= 2 * n + 1 && (x==0||y==0||(double)y/x>fabs((double)y/x)/((double)y/x)))putchar('*');
else putchar(' ');
}
putchar('\n');
}
}
save_lrc_four(str);//輸出四個歌頭
cusor_hide();//隱藏光標
/**********************時間******************/
cusor_moveto(29,20);//移動到20行29列
printf("%02d:%02d",time/60,time%60);
/**********************進度條******************/
s=time*sizeof(prb)/end;//end歌曲總長度
prb[s]='>';//*變>
printf("|%s |",prb);//進度條
/**********************歌曲總時長******************/
cusor_moveto(68,20);//移動到20行66列
printf("%02d:%02d",end/60,end%60);
fflush(stdout);
/**********************查找時間對應歌詞輸出******************/
ret = search_link(head,time);//查找歌詞
if (NULL != ret)
{
int i =0;
for(i=0;i<11;i++)
{
strcpy(buf[i],buf[i+1]);
}
strcpy(buf[11],ret->lrc);
for ( i = 0; i < 11; i++)
{
cusor_moveto(36,7+i);
printf("%s ",buf[i]);
}
cusor_moveto(36,18);
set_fg_color(COLOR_RED);
printf("%s ",buf[11]);
set_fg_color(COLOR_BLUE);
fflush(stdout);
if (ret->next==NULL)
{
sleep(5);
break;
}
}
sleep(1);
time++;
}
return;
}
得到歌詞的最後一句對應的時間,看做最終時間,但是誤差較大
/**********************遍歷節點******************/
int print_link(LRC *head)
{
int i = 0;
if(head == NULL)//鏈表不存在
{
printf("link not find\n");
return 0;
}
else
{
LRC *pb = head;
while(pb != NULL)
{
i=pb->time;
//pb指向下一個節點
pb = pb->next;
}
}
return i+5;
}
功能函數庫
#ifndef __FUN_H__
#define __FUN_H__
typedef struct lrc
{
int time;
char lrc[128];
struct lrc *next;
}LRC;
extern void sim_clock(LRC *head,char **str,int time,int end);//模擬時鐘 參數time 爲模擬時鐘時間
extern char * get_lrc(unsigned long *length,char *data,char *path);//獲取歌詞 參數length 爲文件長度 data 爲文件內容 返回存文件字符串的空間地址
extern int cut_lrc(char *buf,char **str);//分割歌詞 參數buf 爲文件內容 str 爲切割後的文件
extern LRC * save_lrc(LRC *head,char **str,int n);//保存歌詞
extern void save_lrc_four(char **str);//歌頭內容
extern LRC * insert_link(LRC *head,LRC pb);//有序插入
extern LRC* search_link(LRC *head, int time);//查找鏈表
extern int print_link(LRC *head);//遍歷鏈表
#endif
光標定位及顏色改變代碼
#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);
}
對應的庫函數
#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_
歌曲播放代碼,因放在子文件夾中,所以makefi函數裏需要標註地址
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include<string.h>
//啓動mplayer播放器
//參數song_path 爲歌曲的路徑
void mplayer_play(char * song_path)
{
song_path = strcat(song_path,"mp3");
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
;
}
庫函數
#ifndef __START_MPLAYER_H__
#define __START_MPLAYER_H__
//啓動mplayer播放器
//參數song_path 爲歌曲的路徑
extern void mplayer_play(char * song_path);
#endif
makefile函數
exec=main
cc=gcc
obj=main.o ./start_mplayer/start_mplayer.o ./fun/fun.o ./fun/console.o#你要修改的地方
cflags=-Wall -g
$(exec):$(obj)
$(cc) $^ -o $@ $(cflags)
%.o:%.c
$(cc) -c $< -o $@ $(cflags)
clean:
rm $(exec) *.o
總結:麻雀雖小,五臟俱全,雖有不足,然心甚慰,道阻且長,不負年華。
附:程序鏈接
鏈接:https://pan.baidu.com/s/1l53hZ7y-PMX06vZFuyxVXA
提取碼:kbnh
複製這段內容後打開百度網盤手機App,操作更方便哦