QT开发中文网

QT C++ 频谱图

以下是一个使用QT C++绘制频谱图的示例代码。该程序可以读取wav文件并显示其频谱图。

#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QFileDialog>
#include <QtMath>
#include "wavefile.h"

class SpectrumWidget : public QWidget
{
public:
    SpectrumWidget(QWidget* parent = nullptr)
        : QWidget(parent), m_spectrum(nullptr), m_spectrumLength(0)
    {
        setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        setMinimumSize(300, 200);
    }

    ~SpectrumWidget()
    {
        delete[] m_spectrum;
    }

    void setWaveFile(const QString& filename)
    {
        WaveFile wave(filename);

        int sampleRate = wave.sampleRate();
        int numChannels = wave.numChannels();
        int numSamples = wave.numSamples();

        if (numChannels != 1) {
            qDebug() << "Only mono files are supported";
            return;
        }

        const double* samples = wave.samples();

        // Compute the FFT of the signal
        const int N = 1024; // FFT size
        double window[N];
        for (int i = 0; i < N; i++) {
            window[i] = 0.5 * (1 - qCos(2*M_PI*i/(N-1))); // Hanning window
        }

        m_spectrumLength = N/2 + 1;
        m_spectrum = new double[m_spectrumLength];

        for (int i = 0; i <= numSamples-N; i += N/2) {
            std::complex<double> x[N];
            for (int j = 0; j < N; j++) {
                x[j] = samples[i+j] * window[j]; // Apply window function
            }

            std::valarray<std::complex<double>> v(x, N);
            fft(v); // Compute FFT

            for (int j = 0; j < m_spectrumLength; j++) {
                m_spectrum[j] += std::abs(v[j])/m_spectrumLength;
            }
        }

        update();
    }

protected:
    void paintEvent(QPaintEvent* event) override
    {
        QPainter painter(this);
        painter.fillRect(rect(), Qt::black);

        if (!m_spectrum) return;

        int numBins = m_spectrumLength;
        double binWidth = width()/(double)numBins;
        double maxValue = *std::max_element(m_spectrum, m_spectrum+m_spectrumLength);

        for (int i = 0; i < numBins; i++) {
            double x1 = i*binWidth;
            double y1 = height();
            double x2 = (i+1)*binWidth - 1;
            double y2 = height()*(1 - m_spectrum[i]/maxValue);

            QRectF rect(x1, y1, x2-x1, y2-y1);
            QColor color(255*m_spectrum[i]/maxValue, 255*m_spectrum[i]/maxValue, 255);
            painter.fillRect(rect, color);
        }
    }

private:
    double* m_spectrum;
    int m_spectrumLength;

    void fft(std::valarray<std::complex<double>>& x)
    {
        int n = x.size();
        if (n <= 1) return;

        // Split even and odd elements
        std::valarray<std::complex<double>> even = x[std::slice(0, n/2, 2)];
        std::valarray<std::complex<double>> odd = x[std::slice(1, n/2, 2)];

        // Recursively compute FFT of even and odd parts
        fft(even);
        fft(odd);

        // Combine results by multiplying with twiddle factors
        for (int k = 0; k < n/2; k++) {
            std::complex<double> t = std::polar(1.0, -2*M_PI*k/n) * odd[k];
            x[k] = even[k] + t;
            x[k+n/2] = even[k] - t;
        }
    }
};

class MainWindow : public QWidget
{
public:
    MainWindow(QWidget* parent = nullptr)
        : QWidget(parent)
    {
        setWindowTitle("Spectrum");
        setMinimumSize(400, 300);

        m_spectrumWidget = new SpectrumWidget(this);

        m_openButton = new QPushButton("Open", this);
        connect(m_openButton, &QPushButton::clicked,
                this, &MainWindow::onOpenClicked);

        QVBoxLayout* layout = new QVBoxLayout(this);
        layout->addWidget(m_spectrumWidget);
        layout->addWidget(m_openButton);
    }

private slots:
    void onOpenClicked()
    {
        QString filename = QFileDialog::getOpenFileName(this, "Open WAV file", "", "*.wav");

        if (!filename.isEmpty()) {
            m_spectrumWidget->setWaveFile(filename);
            updateGeometry();
            adjustSize();
        }
    }

private:
    SpectrumWidget* m_spectrumWidget;
    QPushButton* m_openButton;
};

int main(int argc, char** argv)
{
    QApplication app(argc, argv);

    MainWindow window;
    window.show();

    return app.exec();
}

请注意,此示例代码片段仅用于演示绘制频谱图的基本原理,并不涵盖所有情况。例如,它只支持单声道WAV文件,并且使用固定的FFT大小和窗函数。在实际应用中,需要根据实际情况选择合适的参数,并进行必要的优化和错误处理。

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://qt.0voice.com/?id=1484

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?