QT多媒体开发(二):播放音频

embedded/2024/12/23 20:04:49/

简介

QMediaPlayer 可以用于播放经过压缩的音频文件,如 MP3 文件和 WMA 文件。QSoundEffect 可以 用于播放低延迟音效文件,例如无压缩的 WAV 文件。这两个类都可以用于播放本地文件和网络文件。

QMediaPlayer 与播放音频相关的接口函数如下:

void setAudioOutput(QAudioOutput *output) //设置一个音频输出设备
QAudioOutput *audioOutput() //返回播放器关联的音频输出设备信息
void setSource(const QUrl &source) //设置播放媒介来源,本地文件或网络文件
QUrl source() //当前播放的媒介来源
void setActiveAudioTrack(int index) //设置当前的音频轨道
void setPlaybackRate(qreal rate) //设置播放速度,1.0 表示正常速度
void setLoops(int loops) //设置播放的循环次数
QMediaPlayer::PlaybackState playbackState() //返回当前播放器状态
QMediaMetaData metaData() //返回当前媒介的元数据
QMediaPlayer::MediaStatus mediaStatus() //媒介状态(正在缓冲、已下载等),对于网络媒介比较有用
bool hasAudio() //当前媒介是否有音频
bool hasVideo() //当前媒介是否有视频
qint64 duration() //媒介的持续时间,单位为 ms 
void setPosition(qint64 position) //设置当前的播放位置,单位为 ms 
qint64 position() //返回当前的播放位置,单位为 ms 
void play() //开始播放
void pause() //暂停播放
void stop() //停止播放

一般使用步骤

1、创建QMediaPlayer 对象,使用函数setAudioOutput()设置一个音频输出设备,

2、使用函数setSource()设置播放媒介来源(可以是本地文件或网络文件)

3、使用函数数 play() 开始播放了。使用 pause()和 stop()函数可以暂停和停止播放。

QMediaPlayer常用的一些信号如下:

void durationChanged(qint64 duration) //媒介的持续时间发生变化
void mediaStatusChanged(QMediaPlayer::MediaStatus status) //媒介状态发生变化
void metaDataChanged() //媒介的元数据发生变化
void playbackStateChanged(QMediaPlayer::PlaybackState newState) //播放器状态发生变化
void positionChanged(qint64 position) //播放位置发生变化
void sourceChanged(const QUrl &media) //媒介来源发生变化

QMediaPlayer 在开始、暂停或停止播放时,播放器状态发生变化,会发playbackStateChanged()

信号,函数 playbackState()会返回当前播放器状态。

媒介有元数据,函数 metaData()可以返回当前媒介的元数据,重新设置媒介时会发射 metaDataChanged()信号。媒介的元数据是 QMediaMetaData 类型数据,元数据用“key-value”形式 的键值对表示,QMediaMetaData 主要有以下几个函数:

QList<QMediaMetaData::Key> keys() //返回键名称列表
QString stringValue(QMediaMetaData::Key key) //以字符串形式返回一个键的数据
QVariant value(QMediaMetaData::Key key) //以 QVariant 类型返回一个键的数据

媒介元数据的键用枚举类型 QMediaMetaData::Key 的常量表示,常见枚举常量表示的元数据的类型和意义如下:

示例程序

该播放器可以打开多个文件后连续播放,可以显示播 放进度、歌曲对应的图片,还可以设置静音、调节音 量。文件列表里的项可以被拖动,从而改变其在列表 里的位置。

主窗口头文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include    <QMainWindow>
#include    <QtMultimedia>
#include    <QListWidgetItem>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTprivate: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();            //移除private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H

这里为主窗口定义了一个事件过滤器eventFilter(),后续listWidget的事件委托给窗口来监视并处理。被监视对象(这里是listWidget)使用函数 installEventFilter()将自己注册给监视对象(Mainwindow),监视对象就是事件过滤器。监视对象重新实现函数 eventFilter(),对监视到的事件进行处理。

在主窗口构造函数中,listWidget将自己的事件通过installEventFilter()委托给主窗口的eventFilter,接下来创建了QMediaPlayer对象用于音频播放。创建的QAudioOutput指向默认音频输出设备,然后用 setAudioOutput() 函数设置播放器player的音频输出设备。最后为QMediaPlayer对象发射的一些信号设置了相关的槽函数用于界面响应和控制。

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);
}//为listWidget安装事件过滤器,用于delete按键移除曲目
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{if (event->type() != QEvent::KeyPress)      //不是KeyPress事件,退出return QWidget::eventFilter(watched,event);QKeyEvent *keyEvent=static_cast<QKeyEvent *>(event);if (keyEvent->key() != Qt::Key_Delete)      //按下的不是Delete键,退出return QWidget::eventFilter(watched,event);if (watched==ui->listWidget)    //判断被监视的对象是否是listWidget{QListWidgetItem *item= ui->listWidget->takeItem(ui->listWidget->currentRow());delete  item;}return true;    //表示事件已经被处理
}

QAudioOutput 是指向音频输出设备的类,它有如下几个函数:

void setDevice(const QAudioDevice &device) //设置一个 QAudioDevice 设备
QAudioDevice device() //返回当前的 QAudioDevice 设备
void setMuted(bool muted) //设置是否静音
bool isMuted() //是否静音了
void setVolume(float volume) //设置音量
float volume() //返回当前音量

一般创建QAudioOutput时就已经将其指向了默认的音频输出设备,如果要设置其他输出设备使用setDevice()函数,device()函数返回当前的输出设备,类型是QMediaDevices。

QMediaDevices 类提供系统内 的多媒体设备信息,它有以下几个静态函数,用于返回系统中的默认多媒体设备:

QAudioDevice QMediaDevices::defaultAudioInput() //返回默认的音频输入设备(如麦克风)信息
QAudioDevice QMediaDevices::defaultAudioOutput() //返回默认的音频输出设备(如音箱)信息
QCameraDevice QMediaDevices::defaultVideoInput() //返回默认的视频输入设备(如摄像头)信息

添加文件和移除文件

添加文件按钮的槽函数为on_btnAdd_clicked(),可以一次打开多个文件,文件被添加到界面上的列表组件 listWidget 里。

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; i<fileList.size();i++)  //依次将选择的文件添加到listWidget,并将文件路径保存到用户数据中{QString  aFile=fileList.at(i);QFileInfo  fileInfo(aFile);QListWidgetItem *aItem =new QListWidgetItem(fileInfo.fileName());aItem->setIcon(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();  //播放文件
}QUrl MainWindow::getUrlFromItem(QListWidgetItem *item)
{QVariant itemData= item->data(Qt::UserRole);    //获取用户数据QUrl source =itemData.value<QUrl>();    //QVariant转换为QUrl类型return source;
}

根据选择的音频文件将其文件名添加到listWidget中,并设置其用户数据为QUrl类型的本地文件路径,后续播放listWidget中的曲目时,通过自定义函数getUrlFromItem从listWidget条目中获取到保存的本地文件路径,就可以使用setSource()函数设置播放媒介。

移除按钮对应的槽函数如下:

void MainWindow::on_btnRemove_clicked()
{//"移除"按钮,移除列表中的当前项int index =ui->listWidget->currentRow();if (index>=0){QListWidgetItem *item= ui->listWidget->takeItem(index);   //new出来的对象移除时要使用deletedelete item;}
}

在这个函数中,选择当前的listWidget进行删除,前面创建条目时使用的是new,那就对应使用delete删除

清空按钮对应的槽函数如下:

void MainWindow::on_btnClear_clicked()
{//"清空"按钮,清空播放列表loopPlay=false;     //防止do_stateChanged()里切换曲目ui->listWidget->clear();player->stop();
}

清空可以直接调用listWidget的clear()函数删除全部条目。

上一曲下一曲

这实际上还是对于listWidget中条目的处理,获取到当前的前一个/下一个条目后,取出条目中保存的用户数据(QUrl类型的本地文件路径)获得对应文件的路径,然后设置播放媒介即可。

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

这里切换曲目时要注意循环播放的问题。如果界面上的“循环”按钮是被选中的,那么 loopPlay 值为 true。如果直接重新设置播放源,播放器的状态会变为停止状态,那么 do_stateChanged()函数就会自动切换曲目,导致混乱。因此,程序里先把变量 loopPlay 设置为 false,避免do_stateChanged()函数切换曲目,重新设置曲目并开始播放后,再重新设置变量 loopPlay 的值。

QMediaPlayer 各信号的处理

切换播放文件时 player 会发射 sourceChanged()和 metaDataChanged()信号。

sourceChanged()信号对应的槽函数如下,主要用于更新界面label的显示

void MainWindow::do_sourceChanged(const QUrl &media)
{//播放的文件发生变化时的响应ui->labCurMedia->setText(media.fileName());
}

metaDataChanged()信号对应的槽函数如下:

void MainWindow::do_metaDataChanged()
{//元数据变化时执行,显示歌曲图片QMediaMetaData metaData=player->metaData();     //元数据对象QVariant  metaImg= metaData.value(QMediaMetaData::ThumbnailImage);  //获取ThumbnailImage元数据,无效
//    QVariant  metaImg= metaData.value(QMediaMetaData::CoverArtImage);  //获取 CoverArtImage 元数据,无效if (metaImg.isValid()){QImage img= metaImg.value<QImage>();        //QVariant转换为QImageQPixmap musicPixmp= QPixmap::fromImage(img);if (ui->scrollArea->width() <musicPixmp.width())ui->labPic->setPixmap(musicPixmp.scaledToWidth(ui->scrollArea->width()-30));elseui->labPic->setPixmap(musicPixmp);}elseui->labPic->clear();
}

当播放媒介的元数据发生变化时,就读取媒介元数据中的 QMediaMetaData::ThumbnailImage

键的数据,这是歌曲的内嵌图片,是 QImage 类型的,如果判断有效就使用QPixmap显示到Label中,这里需要判断一下显示区域是否足够,并进行相应的调整。

播放源时长和播放位置发生变化时,player 会发射 durationChanged()和 positionChanged()信号。

durationChanged()信号对应的槽函数如下:

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

一般曲目发生更改时,播放源的时长会发生变化,在这个槽函数中重新设置了进度条

positionChanged()信号对应的槽函数如下:

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

这个槽函数主要是用于更新界面进度条显示的,以实时显示播放的进度。

播放器开始播放、暂停播放和停止播放时会发射 playbackStateChanged()信号,该信号对应的槽函数如下所示:

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

MainWindow 类的私有变量 loopPlay 表示是否要循环播放,使用界面上的“循环”按钮可以 对应设置这个变量的值。QMediaPlayer 播放完当前曲目后就进入停止状态,不会自动播放下一曲。 为了实现循环播放,我们将界面组件 listWidget 的当前行下移或重设为 0,然后重新设置播放器的播放媒介并开始播放。

其他播放控制

界面下方的一些按钮和组件用于进行播放控制和设置,包括控制播放器开始播放、暂停播放和停止播放,设置播放倍速,设置是否循环播放,设置静音和音量,拖动播放进度条的滑块直接改变播放位置。对应的槽函数如下所示:

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_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"));elseui->btnSound->setIcon(QIcon(":/images/images/mute.bmp"));
}void MainWindow::on_sliderPosition_valueChanged(int value)
{//播放进度调控player->setPosition(value);
}void MainWindow::on_doubleSpinBox_valueChanged(double arg1)
{//"倍速" DoubleSpinboxplayer->setPlaybackRate(arg1);
}

QSoundEffect 播放音效文件

QSoundEffect 用于播放低延迟音效文件,例如无压缩的 WAV 文件,从而实现一些音效,例如按键音、提示音,游戏中的爆炸音、开枪音等。QSoundEffect 不仅可以播放本地文件,还可以播放网络文件。通常使用该类播放一些时长较短的音频。

示例代码如下:

#include "widget.h"
#include "ui_widget.h"#include    <QPainter>
#include    <QPaintEvent>void Widget::defense(QString weapon)
{QUrl   url=QUrl::fromLocalFile(appPath+"/sound/"+weapon);player1->setSource(url);player1->play();
}void Widget::attack(QString weapon)
{QUrl   url=QUrl::fromLocalFile(appPath+"/sound/"+weapon);player2->setSource(url);player2->play();
}void Widget::paintEvent(QPaintEvent *event)
{QPainter painter(this);painter.drawPixmap(0,0,this->width(), this->height(),pixBackground);event->accept();
}Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);appPath=QCoreApplication::applicationDirPath(); //  无“/”pixBackground.load(appPath+"/sound/background.jpg");player1=new QSoundEffect(this);player1->setLoopCount(3);player2=new QSoundEffect(this);player2->setLoopCount(3);
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{defense("Ak7.wav");
}void Widget::on_pushButton_2_clicked()
{defense("machinegun.wav");
}void Widget::on_pushButton_5_clicked()
{attack("Ak7.wav");
}void Widget::on_pushButton_6_clicked()
{attack("machinegun.wav");
}void Widget::on_pushButton_8_clicked()
{attack("blast.wav");
}void Widget::on_pushButton_12_clicked()
{attack("tank.wav");
}void Widget::on_pushButton_11_clicked()
{attack("mine.wav");
}void Widget::on_pushButton_9_clicked()
{defense("shell.wav");
}void Widget::on_pushButton_4_clicked()
{defense("blast.wav");
}void Widget::on_pushButton_10_clicked()
{defense("blast2.wav");
}void Widget::on_pushButton_3_clicked()
{defense("fire.wav");
}void Widget::on_pushButton_7_clicked()
{attack("fire2.wav");
}

参考

QT6 C++开发指南


http://www.ppmy.cn/embedded/148155.html

相关文章

如何利用Python爬虫获得1688按关键字搜索商品

在当今的数字化时代&#xff0c;数据已成为企业竞争的核心资源。对于电商行业来说&#xff0c;了解市场动态、分析竞争对手、获取商品信息是至关重要的。Python作为一种强大的编程语言&#xff0c;其丰富的库和框架使得数据爬取变得简单易行。本文将介绍如何使用Python爬虫技术…

基于Linux编写C语言基础命令

目录 一、常用的Linux命令 1、改变及显示目录命令&#xff1a;cd、pwd、ls。 1.1、cd&#xff08;Change Directory&#xff09; 1.2、pwd&#xff08;Print Working Directory&#xff09; 1.3、ls&#xff08;List&#xff09; 2、文件及目录的创建、复制、删除和移动命…

大数据技术与应用——数据可视化(山东省大数据职称考试)

大数据分析应用-初级 第一部分 基础知识 一、大数据法律法规、政策文件、相关标准 二、计算机基础知识 三、信息化基础知识 四、密码学 五、大数据安全 六、数据库系统 七、数据仓库. 第二部分 专业知识 一、大数据技术与应用 二、大数据分析模型 三、数据科学 数据可视化 大…

RAG开发中,如何用Milvus 2.5 BM25算法实现混合搜索

01. 背景 混合搜索(Hybrid Search)作为RAG应用中Retrieve重要的一环&#xff0c;通常指的是将向量搜索与基于关键词的搜索&#xff08;全文检索&#xff09;相结合&#xff0c;并使用RRF算法合并、并重排两种不同检索的结果&#xff0c;最终来提高数据的召回率。全文检索与语义…

读书笔记~管理修炼-缄默效应

缄默效应&#xff1a;学会正确批评下属 员工明明犯了错误&#xff0c;却不及时告知你&#xff0c;总是拖到最后一刻无法弥补时才不得不承认出了问题——你遇到过这样的问题吗&#xff1f; 这其实是缄默效应在发挥作用。 在职场中&#xff0c;即使再扁平化的环境&…

[Unity] 【VR】【游戏开发】在VR中使用New Input System获取按键值的完整教程

在使用Unity开发VR项目时,推荐使用 New Input System 来处理输入操作。相比于旧的Input系统,New Input System更加灵活、功能强大,尤其在处理VR控制器的按键输入时具有明显优势。本文将详细介绍如何在VR项目中使用New Input System获取按键值,并通过代码示例和图文讲解,帮…

Pr:音频剪辑混合器

Pr菜单&#xff1a;窗口/音频剪辑混合器 Window/Audio Clip Mixer 音频剪辑混合器 Audio Clip Mixer是一种针对单个音频剪辑而非整个音轨的工具&#xff0c;适用于对单个音频剪辑进行细致调整。例如在人声录音中修复咬字不清、去除呼吸声&#xff0c;或其他需要对音频进行精细编…

中阳科技的量化交易研究:前沿探索与实践成果

量化交易以其高效性和客观性&#xff0c;正在全球金融市场中崭露头角。中阳科技秉承技术引领的理念&#xff0c;通过对量化模型的深入研究&#xff0c;为投资者提供独特的交易解决方案。本文从理论基础、实践成果和未来前景三个方面&#xff0c;探讨中阳科技在量化交易领域的探…