在Linux下的基于myplayer实现的歌曲播放器

一、基础原理

1、多进程系统编程
通过execlp(“mplayer”,“mplayer”,“-slave”,“-quiet”,“-idle”,“-input”,“file=./myfifo”,“-playlist”,“./list.txt”,NULL);
将造作可以通过有名管道./myfifo传给mplayer。
2、C语言对于文本的操作
对歌词文本进行解析。

二、myplayer的工作模式

1)键盘模式:
按下一个按键,程序开始工作
启动方法:
mplayer 歌曲路径名
启动mplayer后可以通过键盘按键来控制mplayer播放
基本控制键:
left or right 向后/向前搜索10秒
up or down 向后/向前搜索1分钟
pageup or pagedown 向后/向前搜索10分钟
p or SPACE 暂停播放(按任意键继续)
q or ESC 停止播放并退出
0 or 9 音量控制(音量循环模式)
2)slave模式:(-------用于项目)
启动方法:
./mplayer -idle -slave -quiet 歌曲路径名
-ac mad 这两个参数的意思是指定用mad解码器
-idle 播放文件至文件末尾后mplayer不退出
-slave 指定mplayer运行在slave模式下
-quiet 指定mplayer不向屏幕上,打印乱码信息
slave模式下的控制命令:
loadfile string //播放string指定的歌曲。
loadlist listname //播放列表文件
volume x 1 //设置音量,x为音量的大小。
mute 1/0 //静音开关。1:静音;0:取消静音。
pause //暂停/取消暂停。
seek value //快进或快退参数value指定的秒数
当value为正时,快进;当value为负时,快退。
get_percent_pos //获得文件的播放进度(百分比:0–100)。
get_time_pos //获得文件的当前位置,以秒为单位,精确到小数位1位。
get_file_name //获得文件的文件名。
get_time_length //获得文件的长度,以秒为单位。
get_meta_album //获得文件的 ‘专辑’ 的元数据。
get_meta_artist //获得文件的 ‘艺术家’ 的元数据。
get_meta_comment //获得文件的 ‘评论’ 的元数据。
get_meta_genre //获得文件的 ‘流派’ 的元数据。
get_meta_title //获得文件的 ‘标题’ 的元数据。
get_meta_year //获得文件的 ‘年份’ 的元数据。

三、对歌词的解析操作

在Qt中我们可以针对歌词创建一个类

lyc.h

#ifndef LYC_H
#define LYC_H
#include <iostream>
# include <vector>
#include <string.h>
#include <stdlib.h>
#include <QObject>
class LrcContent{
public:
    int lrc_time;
    char lrc_content[256];
};
class Lyc
{
public:
    Lyc(char * filename);
    ~Lyc();
    void getSongMsg();
    void getSongLrc();

public:
    //歌词文件名
    char lyc_name[256];
    //歌曲名
    char song_name[256];
    //歌曲作者
    char song_atuther[256];
    //专辑名
    char song_album[256];
    //所有的歌词内容
    std::vector <LrcContent *> lrcVector;
    //单句歌词的操作句柄
    LrcContent * lrc;
    //歌词文件指针
    FILE * fd;
    int lrc_time;
};
#endif // LYC_H

lyc.c

#include "lyc.h"
#include <QDebug>

char tempbuff[256]={};
Lyc::Lyc(char * filename)
{
    //根据歌曲名找到歌词名
    char * temp = strtok(filename,".");//因为在解析歌曲的同时就顺便将歌词的也解析了,所以传来的的是.mp3结尾的字符串
    sprintf(lyc_name,"%s.lrc",temp);//字符串的拼接
    
    //打开歌词文件
    fd = fopen(lyc_name,"r+");
    //未发现歌词文件
    if(fd==NULL)
    {
        perror("fopen:");
        
        //歌曲名
        //char song_name[256];
        memset(song_name,0,sizeof(song_name));
        strcpy(song_name,"无");

        //歌曲作者
        //har song_atuther[256];
        memset(song_atuther,0,sizeof(song_atuther));
        strcpy(song_atuther,"无");

        //专辑名
        //char song_album[256];
        memset(song_album,0,sizeof(song_album));
        strcpy(song_album,"无");
    }
    else
    {
       //获取歌曲信息
        getSongMsg();

        //获取歌曲信息
        getSongLrc();
    }
}
Lyc::~Lyc()
{
    fclose(fd);
}

//解析歌曲信息
char * DealMsgString(char *buff)
{
    memset(tempbuff,0,sizeof(tempbuff));

    buff+=4;
    int i=0;
    while(*buff !=']')
    {
        tempbuff[i]=*buff;
        i++;
        buff++;
    }
    return tempbuff;
}


void Lyc::getSongMsg()
{
    char buff[256]={};
    for(int i=0;i<3;i++)
    {
        //如果前三行没有内容
        if(fgets(buff,256,fd)==NULL)
        {
            //歌曲名
            //char song_name[256];
            memset(song_name,0,sizeof(song_name));
            strcpy(song_name,"无");

            //歌曲作者
            //char song_atuther[256];
            memset(song_atuther,0,sizeof(song_atuther));
            strcpy(song_atuther,"无");

            //专辑名
            //char song_album[256];
            memset(song_album,0,sizeof(song_album));
            strcpy(song_album,"无");
        }

        if(strncmp(buff,"[ti:",4)==0)
        {
            char *temp= DealMsgString(buff);
            memset(song_name,0,sizeof(song_name));
            strcpy(song_name,temp);
        }
        else if(strncmp(buff,"[ar:",4)==0)
        {
            char *temp= DealMsgString(buff);
            memset(song_atuther,0,sizeof(song_atuther));
            strcpy(song_atuther,temp);
        }
        else if(strncmp(buff,"[al:",4)==0)
        {
            char *temp= DealMsgString(buff);
            memset(song_album,0,sizeof(song_album));
            strcpy(song_album,temp);
        }
        else
        {
            //歌曲名
            memset(song_name,0,sizeof(song_name));
            strcpy(song_name,"无");

            //歌曲作者
            memset(song_atuther,0,sizeof(song_atuther));
            strcpy(song_atuther,"无");

            //专辑名
            memset(song_album,0,sizeof(song_album));
            strcpy(song_album,"无");
        }
    }
}
void Lyc::getSongLrc()
{
    this->lrcVector.clear();;
    char text[256]={};
    int min=0;
    int sec=0;
    while(fgets(text,256,fd) != NULL)
    {
        char * temp = text;
        int lrctime;
        //非空行
        if(text[0] == '[')
        {
            if(text[1]>='0'||text[1]<='9')
            {
                //解析时间
                sscanf(text,"[%d:%d",&min,&sec);
                lrctime = min*60+sec;
                temp+=10;
            }
            //判断是否为停顿
            if(*temp=='\0'||*temp=='\n')
            {
                continue;
            }
            lrc = new LrcContent;
            memset(lrc->lrc_content,0,sizeof(lrc->lrc_content));
            strcpy(lrc->lrc_content,temp);
            lrc->lrc_time=lrctime;
            lrcVector.push_back(lrc);
        }
    }
}

四、对mplayer的命令操作

//创建歌单
void createPlaylist(const char* music_folder,const char* playlist_file)
{
    //read directory(get song name)
    DIR* dir;
    struct dirent* entry;
    FILE* file;
    dir=opendir(music_folder);
    if(dir == NULL)
    {
        printf("Open dir tmpdir fail\n");
        return;
    }

    file = fopen(playlist_file,"w");
    if(file==NULL)
    {
        printf("无法创建歌单文件\n");
        closedir(dir);
        return;
    }

    while ((entry = readdir(dir)) != NULL) {
           // 如果是以.mp3或.wav结尾的文件,则将其写入歌单文件
           if (strcasecmp(entry->d_name + strlen(entry->d_name) - 4, ".mp3") == 0
               || strcasecmp(entry->d_name + strlen(entry->d_name) - 4, ".wav") == 0) {
               fprintf(file, "%s/%s\n", music_folder, entry->d_name);
               strcpy(song_lry[j++],entry->d_name);
               qDebug()<<entry->d_name;
           }
       }
       fclose(file);
       closedir(dir);
       printf("歌单创建成功!\n");
       return ;
}

createPlaylist(“歌曲所在地址”,“list.txt”);//创建歌单
1、创建父子进程,和有名管道。子进程控制mplayer,父进程维持ui界面,并通过有名管道给传命令。

 //判断有名管道是否打开
    if(fd < 0)//全局变量(已经定义好的有名管道)
    {
        perror("open:");
    }
    
    //create pipe
    pipe(pipe_fd);
    //create parent child process
    pid = vfork();
    if(pid == 0)//子进程
    {
        dup2(pipe_fd[1],1);//输出重定向,可以读到输出的内容
        execlp("mplayer","mplayer","-slave","-quiet","-idle","-input","file=./myfifo","-playlist","./list.txt",NULL);
    }
    else if(pid > 0)
    {
        sleep(1);
        char buff1[20];
        char buff[1024];//清除管道中的数据
        read(pipe_fd[0],buff,sizeof(buff));//清除管道中的数据
        ui->horizontalSlider_2->setMaximum(lyc->lrcVector.back()->lrc_time);//设置歌曲进度条的最大值
        ui->horizontalSlider_2->setMinimum(0);//设置歌曲进度条的最小值

        //歌曲进度条的时间
            int min = 0;
            int sec = 0;
            min = song_time/60;
            sec = song_time%60;
            char mytime[6]={};
            sprintf(mytime,"%02d:%02d",min,sec);
            this->ui->label_3->setText(mytime);//进度条右边的歌曲时间

            int  timelast = lyc->lrcVector.back()->lrc_time;
            min = timelast/60;
            sec = timelast%60;
            mytime[6]={};
            sprintf(mytime,"%02d:%02d",min,sec);
            this->ui->label_4->setText(mytime);//进度条左边的歌曲总时间


        //获取歌曲音量
        write(fd,"get_property volume\n",strlen("get_property volume\n"));//向有名管道写时间
        memset(buff1,0,sizeof(buff1));
        read(pipe_fd[0],buff1,sizeof(buff1));
        int  value;
        sscanf(buff1,"ANS_volume=%d",&value);
        ui->horizontalSlider->setMaximum(100);
        ui->horizontalSlider->setMinimum(0);
        ui->horizontalSlider->setValue(value);
        volume=value;


        //时间函数,让歌曲时间每秒加一
        timer = new QTimer(this);
        connect(timer,SIGNAL(timeout()),this,SLOT(on_horizontalSlider_2_add()));
        //connect(timer,SIGNAL(timeout()),this,SLOT(timeUpdate()));//连接信号槽
        sleep(3);
        timer->start(1000);

2、上一首和下一首播放

ui->listWidget->clear();//清空屏幕的歌词
    timer->stop();//歌词时间暂停
    song_time=0;//歌曲时间,为全局变量
    vecterpos=0;//全局变量
    delete lyc;
    char buff2[100];
    i--;
    if(i<0)//第一首不能再加
    {
        i=0;
    }
    sprintf(buff2,"%s%s",song_lry_location,song_lry[i]);
    
    lyc = new Lyc(buff2);
    ui->label_2->setText(lyc->song_name);//歌曲名
    ui->label_5->setText(lyc->song_atuther);//歌手
    ui->label_6->setText(lyc->song_album);//专辑名

    write(fd,"pt_step -1\n",strlen("pt_step -1\n"));
    ui->horizontalSlider_2->setMaximum(lyc->lrcVector.back()->lrc_time);//设置歌曲进度条的最大值
    ui->horizontalSlider_2->setMinimum(0);//设置歌曲进度条的最小值

    //歌曲进度条的时间
    int min = 0;
    int sec = 0;
    min = song_time/60;
    sec = song_time%60;
    char mytime[6]={};
    sprintf(mytime,"%02d:%02d",min,sec);
    this->ui->label_3->setText(mytime);

    int  timelast = lyc->lrcVector.back()->lrc_time;
    min = timelast/60;
    sec = timelast%60;
    mytime[6]={};
    sprintf(mytime,"%02d:%02d",min,sec);
    this->ui->label_4->setText(mytime);
    timer->start(1000);

下一首

ui->listWidget->clear();
    timer->stop();
    song_time=0;
    vecterpos=0;
    delete lyc;
    char buff2[100];
    i++;
    if(i>=j)
    {
        i=j-1;
    }
    sprintf(buff2,"%s%s",song_lry_location,song_lry[i]);


    lyc = new Lyc(buff2);
    ui->label_2->setText(lyc->song_name);//歌曲名
    ui->label_5->setText(lyc->song_atuther);//歌手
    ui->label_6->setText(lyc->song_album);//专辑名

    write(fd,"pt_step 1\n",strlen("pt_step 1\n"));
    ui->horizontalSlider_2->setMaximum(lyc->lrcVector.back()->lrc_time);//设置歌曲进度条的最大值
    ui->horizontalSlider_2->setMinimum(0);//设置歌曲进度条的最小值

    //歌曲进度条的时间
    int min = 0;
    int sec = 0;
    min = song_time/60;
    sec = song_time%60;
    char mytime[6]={};
    sprintf(mytime,"%02d:%02d",min,sec);
    this->ui->label_3->setText(mytime);

    int  timelast = lyc->lrcVector.back()->lrc_time;
    min = timelast/60;
    sec = timelast%60;
    mytime[6]={};
    sprintf(mytime,"%02d:%02d",min,sec);
    this->ui->label_4->setText(mytime);
    timer->start(1000);

3、计时器

    song_time++;//每秒++
    
    
    int min = 0;
    int sec = 0;
    min = song_time/60;
    sec = song_time%60;
    char mytime[6]={};
    sprintf(mytime,"%02d:%02d",min,sec);
    this->ui->label_3->setText(mytime);
    ui->horizontalSlider_2->setValue(song_time);
    //qDebug()<<song_time;
    //qDebug()<<lyc->lrcVector[vecterpos]->lrc_time;
    if(song_time>=lyc->lrcVector[vecterpos]->lrc_time)
    {
        ui->listWidget->clear();
        for(int j=vecterpos;j<vecterpos+5;j++)
        {
            this->item = new QListWidgetItem(lyc->lrcVector[j]->lrc_content);
            ui->listWidget->addItem(this->item);
            this->item->setTextColor(Qt::black);
            this->item->setFont(QFont("宋体",16));

        }
        vecterpos++;
    }

4、歌曲进度条的拖动

    timer->stop();
    int position = ui->horizontalSlider_2->value();
    ui->horizontalSlider_2->setValue(position);
    int diff=position - song_time;
    song_time=position;
    char str[20];
    char str1[20]="seek ";
    sprintf(str,"%d\n",diff);
    strcat(str1,str);
    write(fd,str1,strlen(str1));

     //歌词播放的回退或者前进
    if(diff>0)
    {
        while(song_time>lyc->lrcVector[vecterpos]->lrc_time)
        {
            vecterpos++;
        }
    }
    else if(diff<0)
    {
        while(song_time<lyc->lrcVector[vecterpos]->lrc_time)
        {
            vecterpos--;
        }
    }
    timer->start(1000);

5、音量的大小

    int position = ui->horizontalSlider->value();
    ui->horizontalSlider->setValue(position);
    volume=position;
    char str[20];
    char str1[20]="volume ";
    sprintf(str,"%d 1\n",volume);
    strcat(str1,str);
    write(fd,str1,strlen(str1));//主要是通过命令实现的
    这些就是这个音乐播放器的大的框架,现在已经把骨架搭好了,还需要自己去填充其他的内容。
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AppWizard has created this MyPlayer application for you. This application not only demonstrates the basics of using the Microsoft Foundation classes but is also a starting point for writing your application. This file contains a summary of what you will find in each of the files that make up your MyPlayer application. MyPlayer.dsp This file (the project file) contains information at the project level and is used to build a single project or subproject. Other users can share the project (.dsp) file, but they should export the makefiles locally. MyPlayer.h This is the main header file for the application. It includes other project specific headers (including Resource.h) and declares the CMyPlayerApp application class. MyPlayer.cpp This is the main application source file that contains the application class CMyPlayerApp. MyPlayer.rc This is a listing of all of the Microsoft Windows resources that the program uses. It includes the icons, bitmaps, and cursors that are stored in the RES subdirectory. This file can be directly edited in Microsoft Visual C++. MyPlayer.clw This file contains information used by ClassWizard to edit existing classes or add new classes. ClassWizard also uses this file to store information needed to create and edit message maps and dialog data maps and to create prototype member functions. resMyPlayer.ico This is an icon file, which is used as the application s icon. This icon is included by the main resource file MyPlayer.rc. resMyPlayer.rc2 This file contains resources that are not edited by Microsoft Visual C++. You should place all resources not editable by the resource editor in this file.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值