QT-LINUX简易版mp3播放器(QT实现)

隔壁老王
• 阅读 407

项目介绍

1、创建一个qmainwindow项目

QT-LINUX简易版mp3播放器(QT实现)

2、导入素材包

QT-LINUX简易版mp3播放器(QT实现) QT-LINUX简易版mp3播放器(QT实现) QT-LINUX简易版mp3播放器(QT实现) QT-LINUX简易版mp3播放器(QT实现)

3、实现ui界面

QT-LINUX简易版mp3播放器(QT实现) QT-LINUX简易版mp3播放器(QT实现) QT-LINUX简易版mp3播放器(QT实现) 设置按钮的宽高

4、实现打开文件

void MainWindow::readSongFlies(bool)
{
    files.clear(); // 先清空原有链表
    songList->clear(); // 先清空原有链表
    files = QFileDialog::getOpenFileNames(
                            this,
                            "选择文件",
                            "/home",
                            "Audio Files (*.wav *.mp3 *.ogg *.flac)");

    // 添加新数据
    for(int i=0;i<files.size();i++)
    {
        QString songfile = files.at(i); // 处理文件路径
        QStringList songfileSplite = songfile.split("/");
        QString name = songfileSplite.at(songfileSplite.size()-1);
        songList->appendRow(new QStandardItem(name));
    }
    ui->songList->setModel(songList);
}

QT-LINUX简易版mp3播放器(QT实现)

5、双击歌曲名获取歌词并播放

5.1添加设计师类继承qwidget

QT-LINUX简易版mp3播放器(QT实现) QT-LINUX简易版mp3播放器(QT实现)

5.2监听双击鼠标事件

#include "mylistview.h"
#include "ui_mylistview.h"
#include<QDebug>
MyListView::MyListView(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MyListView)
{
    ui->setupUi(this);
    // 设置不可编译
    ui->listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    // 连接QListView的双击信号到槽函数
    connect(ui->listView, &QListView::doubleClicked, this, &MyListView::getIndexData);
}

MyListView::~MyListView()
{
    delete ui;
}

void MyListView::setSongList(QStandardItemModel *&songList)
{
    ui->listView->setModel(songList);
}

void MyListView::getIndexData(const QModelIndex &index)
{
    // 获取当前双击的项目数据
    QString songName = index.data().toString();
    // 处理获取到的当前内容
    emit selectSongName(songName);
}

阶段效果 QT-LINUX简易版mp3播放器(QT实现) QT-LINUX简易版mp3播放器(QT实现)

6、实现歌词展示

6.1读取歌词

添加一个c++类处理歌词文件解析,返回对象 QT-LINUX简易版mp3播放器(QT实现)

6.2解析歌曲头信息

QT-LINUX简易版mp3播放器(QT实现)

int MyLrcHandle::getLrcHead(QString data)
{
    // 切割歌词
    QStringList lrcData = data.split("\n");

    int i=0;
    for(;i<lrcData.size();i++) // 歌曲头部信息
    {
        char key[10] = "";
        char value[128] = "";
        sscanf(lrcData.at(i).toStdString().c_str(), "[%[^:]:%[^]]",key, value);
        if (strcmp(key, "ti") == 0) // 歌名
        {
            lrcdata->ti = value;
        }
        else if (strcmp(key, "ar") == 0) // 歌手
        {
            lrcdata->ar = value;
        }
        else if (strcmp(key, "al") == 0) // 专辑
        {
            lrcdata->al = value;
        }
        else if (strcmp(key, "by") == 0) // 制作
        {
            lrcdata->by = value;
        }
        else if (strcmp(key, "offset") == 0) // 延时
        {
            continue;
        }
        else if (isdigit(key[0])) // 识别到数字
        {
            break;
        }
        else
        {
            continue;
        }
    } 
    // 歌词信息
    return 0;
}

6.3展示歌词

void MyLrcHandle::analyzeLrc(QString data)
{
    // 切割歌词
    QStringList lrcData = data.split("\n");
    int i=0;
    for(;i<lrcData.size();i++)
    {
        char key[10] = "";
        char value[128] = "";
        sscanf(lrcData.at(i).toStdString().c_str(), "[%[^:]:%[^]]",key, value);
        if (strcmp(key, "ti") == 0) // 歌名
        {
            lrcdata->ti = value;
        }
        else if (strcmp(key, "ar") == 0) // 歌手
        {
            lrcdata->ar = value;
        }
        else if (strcmp(key, "al") == 0) // 专辑
        {
            lrcdata->al = value;
        }
        else if (strcmp(key, "by") == 0) // 制作
        {
            lrcdata->by = value;
        }
        else if (strcmp(key, "offset") == 0) // 延时
        {
            continue;
        }
        else if (isdigit(key[0])) // 识别到数字
        {
            break;
        }
        else
        {
            continue;
        }
    }
    // 歌词信息
    for(;i<lrcData.size();i++)
    {
        QString str = lrcData.at(i);
        if(str.isEmpty() || str.size()< 10) // 处理空行
        {
            continue;
        }
        // [03:34.64][02:34.71][01:05.83]我想就这样牵着你的手不放开(使用splite更方便)
        char *tmp = const_cast<char*>(str.toUtf8().constData());
        char *lrc = tmp;
        while(*lrc == '[') // 如果第一个字符是 [ 跳过固定长度的字符
            lrc += 10;
        while(*tmp == '[') // 获取时间
        {
            int min=0,sec=0;
            sscanf(tmp, "[%d:%d", &min, &sec);
            // 存入qmap中qmap以秒数为key,歌词为value
            lrcdata->lrc->push_back(MyLrc(min * 60 + sec, lrc));
            tmp+=10;
        }
    }
    // 对歌词排序
    lrcdata->lrc->sort(CompareLrc());
}

处理歌词最开始和结束的情况

std::list<MyLrc>::iterator MainWindow::findPointFirst()
{
    std::list<MyLrc>::iterator tmpBegin = mLrc->getLrc()->begin();
    std::list<MyLrc>::iterator tmpBegin2 = std::next(tmpBegin);
    std::list<MyLrc>::iterator tmpEnd = mLrc->getLrc()->end();
    std::list<MyLrc>::iterator tmpEnd2 = std::prev(tmpEnd); // 最后一行
    std::list<MyLrc>::iterator tmpEnd3 = std::prev(tmpEnd2); // 倒数第二行

    std::list<MyLrc>::iterator currentLrcPrev2 = std::prev(currentLrc);
    std::list<MyLrc>::iterator currentLrcPrev3 = std::prev(currentLrcPrev2);

    if(currentLrc == tmpBegin) // 如果是一行歌词
        return tmpBegin;
    else if(currentLrc == tmpBegin2) // 当前是第二行歌词
        return tmpBegin;
    else if(currentLrc == tmpEnd2) // 最后一行
    {
        tmpEnd2--;
        tmpEnd2--;
        tmpEnd2--;
        tmpEnd2--;
        return tmpEnd2;
    }else if(currentLrc == tmpEnd3) // 倒数第二行
    {
        tmpEnd3--;
        tmpEnd3--;
        tmpEnd3--;
        return tmpEnd3;
    }
    else
    {
        return currentLrcPrev3; // 其他情况显示当前歌词的前两行
    }
}

双击歌曲进行播放 QT-LINUX简易版mp3播放器(QT实现) 歌词部分初步完成。

播放音乐部分

1、使用有名管道对mplayer进行操作 定时对mplayer进行歌曲时间获取 (此处使用pthread处理)

void *send_cmd(void *arg) // 定时发送获取时间操作
{
    DATA *data = (DATA *)arg;
    MainWindow *w = data->w;
    int fi_fd = w->fi_fd;
    usleep(500000); // 等待0.5秒
    while(1)
    {
        usleep(500000);
        if(w->flag)
        {
            if(write(fi_fd,"get_time_pos\n", strlen("get_time_pos\n"))==-1)
            {
                perror("write");
            }
        }
    }
}

2、使用无名管道,将标准输出重定向到无名管道的输入

void *recv_msg(void* arg)
{
    DATA* data = (DATA*)arg;
    MainWindow* w = data->w;
    int fd0 = w->fd0;
    while(1)
    {
        char buf[64]="";
        if(read(fd0, buf, sizeof(buf)) == -1)
        {
            perror("fail to read");
        }
        if(strncmp(buf,"ANS_LENGTH", strlen("ANS_LENGTH")) == 0) // 获取歌曲总时长
        {
            float stime = 0.0f;
            sscanf(buf,"ANS_LENGTH=%f", &stime);
            int totalTime =(int)stime;
            if(totalTime > 0)
            {
                w->totalTime = totalTime;
                int min = w->totalTime / 60;
                int sec = w->totalTime % 60;
                w->currentSongTime = QString("%1:%2").arg(min, 2, 10, QLatin1Char('0'))
                                           .arg(sec, 2, 10, QLatin1Char('0'));
            }
        }
        if(strncmp(buf,"ANS_TIME_POSITION", strlen("ANS_TIME_POSITION")) == 0) // 获取当前运行时间
        {
            float time = 0.0f;
            sscanf(buf,"ANS_TIME_POSITION=%f", &time);
//            qDebug() << time;
            w->runTime=(int)time;
        }
    }
}

总时长 * 拖拽到的百分比 - 当前运行时间 = 快进或快退(正数是快进,负数是快退)

void MainWindow::dragProgress(int value)
{
    qDebug() << "dragProgress " << value;
    // 重置当前歌词和时间
    int tmpTime = (int)(value * 0.01 * totalTime); // 计算获取拖拽到的时间
    QString cmd = QString("seek %1\n").arg(tmpTime - runTime); // 计算是进还是退
    qDebug() << cmd;
    if(write(fi_fd,cmd.toStdString().c_str(),strlen(cmd.toStdString().c_str())) == -1) // 控制mplayer快进秒数 如果是负数就快退
    {
        perror("write");
    }
    runTime = tmpTime;
    // 找到大于该时间的第一个歌词
    std::list<MyLrc>::iterator it = mLrc->getLrc()->begin();
    for(;it != mLrc->getLrc()->end(); it++)
    {
        if((*it).second > runTime)
            break;
    }
    currentLrc = it;
    // 重置时间
    minutes = runTime / 60;
    seconds = runTime % 60;
}

可以关闭mplayer标准异常文件描述符

美化程度请自行设置 QT-LINUX简易版mp3播放器(QT实现)

设计阶段

项目源码

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Stella981 Stella981
3年前
AssemblyScript 入门指南[每日前端夜话0xEB]
每日前端夜话0xEB每日前端夜话,陪你聊前端。每天晚上18:00准时推送。正文共:2459 字预计阅读时间:10分钟作者:DannyGuo翻译:疯狂的技术宅来源:logrocket!(https://oscimg.oschina.net/oscnet/b880277c594152a503
Wesley13 Wesley13
3年前
VBox 启动虚拟机失败
在Vbox(5.0.8版本)启动Ubuntu的虚拟机时,遇到错误信息:NtCreateFile(\\Device\\VBoxDrvStub)failed:0xc000000034STATUS\_OBJECT\_NAME\_NOT\_FOUND(0retries) (rc101)Makesurethekern
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
3年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
3年前
MBR笔记
<bochs:100000000000e\WGUI\Simclientsize(0,0)!stretchedsize(640,480)!<bochs:2b0x7c00<bochs:3c00000003740i\BIOS\$Revision:1.166$$Date:2006/08/1117
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
隔壁老王 隔壁老王
7个月前
QT-LINUX简易版mp3播放器(设计阶段)
在ubuntu下使用qt和mplayer开发的简易音乐播放器
隔壁老王
隔壁老王
Lv1
千万程序员队伍中的一员。我住隔壁我姓王,同事们亲切得称呼我隔壁老王
文章
20
粉丝
2
获赞
7