音乐播放器关键代码分析
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
QMediaPlayer *player; //播放器
bool loopPlay=true; //是否循环播放
QString durationTime; //文件总长度,mm:ss字符串
QString positionTime; //当前播放到位置,mm:ss字符串
QUrl getUrlFromItem(QListWidgetItem *item); //获取item的用户数据
bool eventFilter(QObject *watched, QEvent *event); //事件过滤处理
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
//自定义槽函数
void do_stateChanged(QMediaPlayer::PlaybackState state); //播放器状态发生变化
void do_sourceChanged(const QUrl &media); //文件发生变化
void do_durationChanged(qint64 duration); //文件长度发生变化
void do_positionChanged(qint64 position); //播放位置发生变化
void do_metaDataChanged(); //元数据发生变化
//
void on_btnAdd_clicked();
void on_btnPlay_clicked();
void on_btnPause_clicked();
void on_btnStop_clicked();
void on_listWidget_doubleClicked(const QModelIndex &index);
void on_btnClear_clicked();
void on_sliderVolumn_valueChanged(int value);
void on_btnSound_clicked();
void on_sliderPosition_valueChanged(int value);
void on_btnPrevious_clicked();
void on_btnNext_clicked();
void on_btnLoop_clicked(bool checked);
void on_doubleSpinBox_valueChanged(double arg1);
void on_btnRemove_clicked();
void on_btnClose_clicked();
void on_doubleSpinBox_textChanged(const QString &arg1);
void on_btnLoop_clicked();
void on_sliderVolumn_actionTriggered(int action);
void on_sliderPosition_actionTriggered(int action);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
这是一个名为"MainWindow"的类,继承自QMainWindow。它是一个主窗口类,用于创建一个具有音频播放功能的应用程序界面。
在私有成员部分,包含了以下成员变量:
player
:QMediaPlayer类型的指针,用于控制音频的播放。loopPlay
:bool类型,表示是否循环播放音频。durationTime
:QString类型的变量,表示音频文件的总时长(以mm:ss格式的字符串表示)。positionTime
:QString类型的变量,表示当前音频播放的位置(以mm:ss格式的字符串表示)。还有两个私有函数:
getUrlFromItem(QListWidgetItem *item)
:从QListWidgetItem中获取用户数据(QUrl类型),用于获取音频文件的URL。eventFilter(QObject *watched, QEvent *event)
:事件过滤处理函数,用于处理特定的事件。公有部分包含了构造函数和析构函数。
私有槽函数部分定义了一些槽函数,用于响应相关信号的变化,包括:
do_stateChanged(QMediaPlayer::PlaybackState state)
:播放器状态发生变化的槽函数。do_sourceChanged(const QUrl &media)
:音频文件发生变化的槽函数。do_durationChanged(qint64 duration)
:音频文件总时长发生变化的槽函数。do_positionChanged(qint64 position)
:音频播放位置发生变化的槽函数。do_metaDataChanged()
:音频文件元数据发生变化的槽函数。还包括一些其他槽函数,用于响应界面上的按钮点击事件和数值变化等。
最后,私有成员ui
是一个指向Ui::MainWindow类的指针,用于访问用户界面的元素和操作。
总体上,该类定义了一个主窗口,具有音频播放器的功能,通过界面上的按钮和列表项来控制音频的播放、暂停、停止、添加、删除等操作。同时也显示了音频文件的时长、当前播放位置等信息。
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
QUrl MainWindow::getUrlFromItem(QListWidgetItem *item)
{
QVariant itemData= item->data(Qt::UserRole); //获取用户数据
QUrl source =itemData.value(); //QVariant转换为QUrl类型
return source;
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() != QEvent::KeyPress) //不是KeyPress事件,退出
return QWidget::eventFilter(watched,event);
QKeyEvent *keyEvent=static_cast(event);
if (keyEvent->key() != Qt::Key_Delete) //按下的不是Delete键,退出
return QWidget::eventFilter(watched,event);
if (watched==ui->listWidget)
{
QListWidgetItem *item= ui->listWidget->takeItem(ui->listWidget->currentRow());
delete item;
}
return true; //表示事件已经被处理
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->listWidget->installEventFilter(this); //安装事件过滤器
ui->listWidget->setDragEnabled(true); //允许拖放操作
ui->listWidget->setDragDropMode(QAbstractItemView::InternalMove); //列表项可移动
player = new QMediaPlayer(this);
QAudioOutput *audioOutput = new QAudioOutput(this); //音频输出,指向默认的音频输出设备
player->setAudioOutput(audioOutput); //设置音频输出
connect(player,&QMediaPlayer::positionChanged, //播放位置发生变化
this, &MainWindow::do_positionChanged);
connect(player,&QMediaPlayer::durationChanged, //播放源长度发生变化
this, &MainWindow::do_durationChanged);
connect(player, &QMediaPlayer::sourceChanged, //播放源发生变化
this, &MainWindow::do_sourceChanged);
connect(player, &QMediaPlayer::playbackStateChanged, //播放器状态发生变化
this, &MainWindow::do_stateChanged);
connect(player, &QMediaPlayer::metaDataChanged, //元数据发生变化
this, &MainWindow::do_metaDataChanged);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::do_stateChanged(QMediaPlayer::PlaybackState state)
{//播放器状态变化时执行,更新按钮状态,或播放下一曲
ui->btnPlay->setEnabled(state!=QMediaPlayer::PlayingState);
ui->btnPause->setEnabled(state==QMediaPlayer::PlayingState);
ui->btnStop->setEnabled(state==QMediaPlayer::PlayingState);
//播放完一曲后停止了,如果loopPlay为true,自动播放下一曲
if (loopPlay && (state ==QMediaPlayer::StoppedState))
{
int count=ui->listWidget->count();
int curRow=ui->listWidget->currentRow();
curRow++;
curRow= curRow>=count? 0:curRow;
ui->listWidget->setCurrentRow(curRow);
player->setSource(getUrlFromItem(ui->listWidget->currentItem()));
player->play();
}
}
void MainWindow::do_sourceChanged(const QUrl &media)
{//播放的文件发生变化时的响应
ui->labCurMedia->setText(media.fileName());
}
void MainWindow::do_durationChanged(qint64 duration)
{//播放源时长变化时执行,更新进度显示
ui->sliderPosition->setMaximum(duration);
int secs=duration/1000; //秒
int mins=secs/60; //分钟
secs=secs % 60; //余数秒
durationTime=QString::asprintf("%d:%d",mins,secs);
ui->labRatio->setText(positionTime+"/"+durationTime);
}
void MainWindow::do_positionChanged(qint64 position)
{//播放位置变化时执行,更新进度显示
if (ui->sliderPosition->isSliderDown()) //滑条正被鼠标拖动
return;
ui->sliderPosition->setSliderPosition(position);
int secs=position/1000; //秒
int mins=secs/60; //分钟
secs=secs % 60; //余数秒
positionTime=QString::asprintf("%d:%d",mins,secs);
ui->labRatio->setText(positionTime+"/"+durationTime);
}
void MainWindow::do_metaDataChanged()
{//元数据变化时执行,显示歌曲图片
QMediaMetaData metaData=player->metaData(); //元数据对象
QVariant metaImg= metaData.value(QMediaMetaData::ThumbnailImage); //获取ThumbnailImage元数据
if (metaImg.isValid())
{
QImage img= metaImg.value(); //QVariant转换为QImage
QPixmap musicPixmp= QPixmap::fromImage(img);
if (ui->scrollArea->width() labPic->setPixmap(musicPixmp.scaledToWidth(ui->scrollArea->width()-30));
else
ui->labPic->setPixmap(musicPixmp);
}
else
ui->labPic->clear();
}
void MainWindow::on_btnAdd_clicked()
{//"添加"按钮,添加文件
QString curPath=QDir::homePath(); //获取系统当前目录
QString dlgTitle="选择音频文件";
QString filter="音频文件(*.mp3 *.wav *.wma);;所有文件(*.*)"; //文件过滤器
QStringList fileList=QFileDialog::getOpenFileNames(this,dlgTitle,curPath,filter);
if (fileList.count()<1)
return;
for (int i=0; isetIcon(QIcon(":/images/images/musicFile.png"));
aItem->setData(Qt::UserRole, QUrl::fromLocalFile(aFile)); //设置用户数据,QUrl对象
ui->listWidget->addItem(aItem);
}
if (player->playbackState() != QMediaPlayer::PlayingState)
{ //当前没有在播放,就播放第1个文件
ui->listWidget->setCurrentRow(0);
QUrl source= getUrlFromItem(ui->listWidget->currentItem());
player->setSource(source);
}
player->play();
}
void MainWindow::on_btnPlay_clicked()
{//开始播放
if (ui->listWidget->currentRow()<0) //没有选择文件,就播放第1个
ui->listWidget->setCurrentRow(0);
player->setSource(getUrlFromItem(ui->listWidget->currentItem()));
player->play();
loopPlay=ui->btnLoop->isChecked(); //是否循环播放
}
void MainWindow::on_btnPause_clicked()
{//暂停播放
player->pause();
}
void MainWindow::on_btnStop_clicked()
{//停止播放
loopPlay=false;
player->stop();
}
void MainWindow::on_listWidget_doubleClicked(const QModelIndex &index)
{//双击listWidget时切换播放文件
Q_UNUSED(index);
loopPlay=false; //暂时设置为false,防止do_stateChanged()里切换曲目
player->setSource(getUrlFromItem(ui->listWidget->currentItem()));
player->play();
loopPlay=ui->btnLoop->isChecked();
}
void MainWindow::on_btnClear_clicked()
{//"清空"按钮,清空播放列表
loopPlay=false; //防止do_stateChanged()里切换曲目
ui->listWidget->clear();
player->stop();
}
void MainWindow::on_sliderVolumn_valueChanged(int value)
{//调整音量
player->audioOutput()->setVolume(value/100.0); //0~ 1之间
}
void MainWindow::on_btnSound_clicked()
{//静音控制
bool mute=player->audioOutput()->isMuted();
player->audioOutput()->setMuted(!mute);
if (mute)
ui->btnSound->setIcon(QIcon(":/images/images/volumn.bmp"));
else
ui->btnSound->setIcon(QIcon(":/images/images/mute.bmp"));
}
void MainWindow::on_sliderPosition_valueChanged(int value)
{//播放进度调控
player->setPosition(value);
}
void MainWindow::on_btnPrevious_clicked()
{//前一曲
int curRow=ui->listWidget->currentRow();
curRow--;
curRow= curRow<0? 0:curRow;
ui->listWidget->setCurrentRow(curRow); //设置当前行
loopPlay=false; //暂时设置为false,防止do_stateChanged()里切换曲目
player->setSource(getUrlFromItem(ui->listWidget->currentItem()));
player->play();
loopPlay=ui->btnLoop->isChecked();
// if(ui->btnLoop->isChecked())
// {
// loopPlay=false; //暂时设置为false,防止do_stateChanged()里切换曲目
// player->setSource(getUrlFromItem(ui->listWidget->currentItem()));
// player->play();
// loopPlay=true;
// }
}
void MainWindow::on_btnNext_clicked()
{//下一曲
int count=ui->listWidget->count();
int curRow=ui->listWidget->currentRow();
curRow++;
curRow= curRow>=count? count-1:curRow;
ui->listWidget->setCurrentRow(curRow);
loopPlay=false; //暂时设置为false,防止do_stateChanged()里切换曲目
player->setSource(getUrlFromItem(ui->listWidget->currentItem()));
player->play();
loopPlay=ui->btnLoop->isChecked();
// if(ui->btnLoop->isChecked())
// {
// loopPlay=false; //暂时设置为false,防止do_stateChanged()里切换曲目
// player->setSource(getUrlFromItem(ui->listWidget->currentItem()));
// player->play();
// loopPlay=true;
// }
}
void MainWindow::on_btnLoop_clicked(bool checked)
{//"循环" 按钮
loopPlay=checked;
}
void MainWindow::on_doubleSpinBox_valueChanged(double arg1)
{//"倍速" DoubleSpinbox
player->setPlaybackRate(arg1);
}
void MainWindow::on_btnRemove_clicked()
{//"移除"按钮,移除列表中的当前项
int index =ui->listWidget->currentRow();
if (index>=0)
{
QListWidgetItem *item= ui->listWidget->takeItem(index);
delete item;
}
}
这段代码是一个音乐播放器的主窗口类MainWindow的实现代码。主要功能包括添加音频文件、播放、暂停、停止、切换曲目、调整音量、静音控制、播放进度调控等。
具体分析如下:
getUrlFromItem
函数用于从QListWidgetItem中获取保存的QUrl对象。eventFilter
函数是一个事件过滤器,用于捕获并处理QKeyEvent事件(键盘按下事件),当捕获到Delete键按下事件时,删除当前选中的QListWidgetItem。do_stateChanged
函数根据播放器状态的变化,更新按钮的状态,并在循环播放模式下自动播放下一曲。do_sourceChanged
函数在播放的文件发生变化时更新显示的文件名。do_durationChanged
函数在播放源时长变化时更新进度条的最大值,并转换为分钟:秒的格式显示。do_positionChanged
函数在播放位置变化时更新进度条的位置,并转换为分钟:秒的格式显示。do_metaDataChanged
函数在元数据发生变化时,根据元数据中的缩略图显示歌曲图片。on_btnAdd_clicked
函数是"添加"按钮的点击事件处理函数,通过文件对话框选择音频文件,并将文件名添加到列表中,如果当前没有播放,则自动播放第一个文件。on_btnPlay_clicked
函数是"开始播放"按钮的点击事件处理函数,根据当前选中的列表项设置播放源,并开始播放。on_btnPause_clicked
函数是"暂停播放"按钮的点击事件处理函数,暂停当前播放。on_btnStop_clicked
函数是"停止播放"按钮的点击事件处理函数,停止当前播放。on_listWidget_doubleClicked
函数是当双击列表项时切换播放文件的事件处理函数。on_btnClear_clicked
函数是"清空"按钮的点击事件处理函数,清空播放列表并停止播放。on_sliderVolumn_valueChanged
函数是调整音量的滑动条的值变化事件处理函数,根据滑动条的值设置音量。on_btnSound_clicked
函数是"静音"按钮的点击事件处理函数,切换静音状态。on_sliderPosition_valueChanged
函数是播放进度调节的滑动条的值变化事件处理函数,根据滑动条的值设置播放位置。on_btnPrevious_clicked
函数是"上一曲"按钮的点击事件处理函数,切换到上一曲并播放。on_btnNext_clicked
函数是"下一曲"按钮的点击事件处理函数,切换到下一曲并播放。on_btnLoop_clicked
函数是"循环播放"按钮的点击事件处理函数,设置循环播放的状态。on_doubleSpinBox_valueChanged
函数是"倍速"双精度浮点数输入框的值变化事件处理函数,根据输入的值设置播放速率。on_btnRemove_clicked
函数是"移除"按钮的点击事件处理函数,移除当前选中的列表项。以上就是代码的详细分析。这段代码实现了一个简单的音乐播放器界面,并提供了基本的播放控制功能。
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() != QEvent::KeyPress) //不是KeyPress事件,退出
return QWidget::eventFilter(watched,event);
QKeyEvent *keyEvent=static_cast(event);
if (keyEvent->key() != Qt::Key_Delete) //按下的不是Delete键,退出
return QWidget::eventFilter(watched,event);
if (watched==ui->listWidget)
{
QListWidgetItem *item= ui->listWidget->takeItem(ui->listWidget->currentRow());
delete item;
}
return true; //表示事件已经被处理
}
这段代码是MainWindow类中的一个事件过滤器函数eventFilter
,用于捕获并处理特定的事件。
在这段代码中,首先通过判断事件的类型来确定是否为按键事件(KeyPress)。如果不是按键事件,则直接调用基类的事件过滤器函数进行默认处理。
如果是按键事件,进一步判断按下的键盘键是否为Delete键。如果不是Delete键,则同样调用基类的事件过滤器函数进行默认处理。
如果按下的是Delete键,且被监视的对象是ui->listWidget
(列表控件),则获取当前选中的列表项(QListWidgetItem),并从列表中移除该列表项。最后,通过delete操作释放内存。
最后,返回true
表示事件已经被处理。
总的来说,这段代码的作用是在用户按下Delete键时,如果当前焦点位于列表控件上(ui->listWidget
),则删除选中的列表项。
ps:
低延迟音效文件是指在进行音效处理时,尽可能地减少音效的延迟时间,以保证音频效果的同步和响应速度。在数字音频处理中,无论是采样率、位深度还是传输带宽都会对音效处理的延迟时间产生影响,如果音效延迟时间过长,就会导致音频和视频不同步或者影响用户体验。
为了降低音效处理的延迟时间,一些专业的音效处理器会采用各种优化算法,包括质量损失较小的预测算法、快速近似算法、滤波器设计等方法,以达到尽可能地减少音效延迟时间的目的。同时,低延迟音效也可以通过采用特殊的音频编码算法来实现,如Opus等音频编码格式就具有较低的编码延迟,适合于实时音频应用。
低延迟音效文件通常用于需要高质量音频响应和实时交互的场景,例如电子游戏、虚拟现实、语音通话等。通过使用低延迟音效文件,可以提高用户体验和音频响应速度,增加应用的稳定性和可靠性。