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

项目介绍

1、创建一个qmainwindow项目

image

2、导入素材包

image image image image

3、实现ui界面

image image image 设置按钮的宽高

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

image

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

5.1添加设计师类继承qwidget

image image

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

阶段效果 image image

6、实现歌词展示

6.1读取歌词

添加一个c++类处理歌词文件解析,返回对象 image

6.2解析歌曲头信息

image

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; // 其他情况显示当前歌词的前两行 } }

双击歌曲进行播放 image 歌词部分初步完成。

播放音乐部分

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标准异常文件描述符

美化程度请自行设置 image

设计阶段

项目源码

点赞
收藏

评论区

加载中...

相关推荐

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

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

AssemblyScript 入门指南[每日前端夜话0xEB]

每日前端夜话0xEB每日前端夜话,陪你聊前端。每天晚上18:00准时推送。正文共:2459 字预计阅读时间:10分钟作者:DannyGuo翻译:疯狂的技术宅来源:logrocket!(https://oscimg.oschina.net/oscnet/b880277c594152a503

FLV文件格式

1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  

mysql设置时区

mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0