QT 快速傅里叶绘制QMediaPlayer频谱完整代码
时间: 2023-10-14 10:24:23 浏览: 246
Qt绘制频谱
4星 · 用户满意度95%
以下是一个完整的示例代码,演示如何使用Qt和快速傅里叶变换来绘制QMediaPlayer的频谱。
```cpp
#include <QApplication>
#include <QMediaPlayer>
#include <QAudioProbe>
#include <QAudioBuffer>
#include <QAudioFormat>
#include <QMainWindow>
#include <QVBoxLayout>
#include <QChart>
#include <QLineSeries>
#include <QValueAxis>
#include <QChartView>
#include <QTimer>
#include <fftw3.h>
QT_CHARTS_USE_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr)
: QMainWindow(parent)
{
// 创建垂直布局
QVBoxLayout *layout = new QVBoxLayout();
// 创建图表和序列
m_chart = new QChart();
m_series = new QLineSeries();
m_chart->addSeries(m_series);
// 创建X轴和Y轴
QValueAxis *axisX = new QValueAxis();
axisX->setRange(0, 20000);
axisX->setTickCount(5);
axisX->setLabelFormat("%g Hz");
m_chart->addAxis(axisX, Qt::AlignBottom);
m_series->attachAxis(axisX);
QValueAxis *axisY = new QValueAxis();
axisY->setRange(0, 100);
m_chart->addAxis(axisY, Qt::AlignLeft);
m_series->attachAxis(axisY);
// 创建图表视图并添加到布局中
QChartView *chartView = new QChartView(m_chart);
chartView->setRenderHint(QPainter::Antialiasing);
layout->addWidget(chartView);
// 设置布局为主窗口的中心部分
QWidget *widget = new QWidget(this);
widget->setLayout(layout);
setCentralWidget(widget);
// 创建媒体播放器和音频探测器
m_player = new QMediaPlayer();
m_probe = new QAudioProbe();
m_probe->setSource(m_player);
// 连接音频探测器的数据可用信号与处理槽
connect(m_probe, &QAudioProbe::audioBufferProbed, this, &MainWindow::processBuffer);
// 打开媒体文件并开始播放
m_player->setMedia(QUrl::fromLocalFile("test.mp3"));
m_player->play();
// 创建定时器,每100毫秒刷新一次图表
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &MainWindow::updateChart);
timer->start(100);
}
private slots:
void processBuffer(const QAudioBuffer &buffer)
{
// 获取音频格式和数据
const QAudioFormat format = buffer.format();
const qint64 duration = buffer.duration();
const qint64 sampleCount = duration / 1000 * format.sampleRate() * format.channelCount();
const quint16 *data = buffer.constData<quint16>();
// 分配内存
fftw_complex *in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * sampleCount);
fftw_complex *out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * sampleCount);
fftw_plan plan = fftw_plan_dft_1d(sampleCount, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
// 复制数据并进行窗口函数处理
for (int i = 0; i < sampleCount; i++) {
double window = 0.54 - 0.46 * qCos(2 * M_PI * i / (sampleCount - 1));
in[i][0] = data[i] * window;
in[i][1] = 0;
}
// 执行快速傅里叶变换,得到频谱数据
fftw_execute(plan);
QVector<QPointF> points(sampleCount / 2);
for (int i = 0; i < sampleCount / 2; i++) {
double freq = i * format.sampleRate() / sampleCount;
double magnitude = 20 * qLn(qSqrt(qPow(out[i][0], 2) + qPow(out[i][1], 2)));
points[i] = QPointF(freq, magnitude);
}
// 更新序列的数据
m_series->replace(points);
// 释放内存
fftw_destroy_plan(plan);
fftw_free(in);
fftw_free(out);
}
void updateChart()
{
// 更新图表的坐标轴范围
const qreal maxX = m_series->points().last().x();
m_chart->axisX()->setRange(maxX - 20000, maxX);
}
private:
QMediaPlayer *m_player;
QAudioProbe *m_probe;
QChart *m_chart;
QLineSeries *m_series;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
```
在这个示例代码中,我们使用了FFTW库来进行快速傅里叶变换。在处理每个音频缓冲区时,我们首先计算出采样数,然后分配内存,并将数据复制到输入数组中。接着,我们对每个采样点应用了一个汉宁窗口函数,并使用FFTW执行了快速傅里叶变换。最后,我们计算了每个频率对应的幅度,并将其作为点添加到QLineSeries中。在定时器的槽函数中,我们更新了图表的X轴范围,以保持最新的频谱数据可见。
阅读全文