From 01812e6bf97f39d996fe748b8ad68413ac8c7fb3 Mon Sep 17 00:00:00 2001 From: Gary Wang Date: Sun, 13 Oct 2024 21:07:45 +0800 Subject: [PATCH] yyc12345 --- .editorconfig | 7 ++++ CMakeLists.txt | 14 ++++++-- fftspectrum.cpp | 89 +++++++++++++++++++++++++++++++++++++++++++++++++ fftspectrum.h | 31 +++++++++++++++++ mainwindow.cpp | 7 +++- mainwindow.h | 2 ++ 6 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 .editorconfig create mode 100644 fftspectrum.cpp create mode 100644 fftspectrum.h diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d02e348 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,7 @@ +[*] +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 4 \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e1bcd9..4d86b79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,12 @@ find_package(Qt6 6.6 COMPONENTS Widgets Multimedia Network LinguistTools REQUIRE find_package(KF6Codecs 6.1.0) find_package(PkgConfig) +option(KISSFFT_PKGCONFIG OFF) +option(KISSFFT_STATIC ON) +option(KISSFFT_TEST OFF) +option(KISSFFT_TOOLS OFF) +add_subdirectory(kissfft EXCLUDE_FROM_ALL) + if (USE_QTEXTCODEC) find_package(Qt6 6.6 COMPONENTS Core5Compat REQUIRED) endif() @@ -35,7 +41,8 @@ set (PMUSIC_CPP_FILES playlistmanager.cpp singleapplicationmanager.cpp lrcbar.cpp - lyricsmanager.cpp + lyricsmanager.cpp + fftspectrum.cpp ) set (PMUSIC_HEADER_FILES @@ -44,7 +51,8 @@ set (PMUSIC_HEADER_FILES playlistmanager.h singleapplicationmanager.h lrcbar.h - lyricsmanager.h + lyricsmanager.h + fftspectrum.h ) set (PMUSIC_UI_FILES @@ -84,7 +92,7 @@ if (TARGET KF6::Codecs) target_link_libraries (${EXE_NAME} PRIVATE KF6::Codecs) endif () -target_link_libraries(${EXE_NAME} PRIVATE Qt::Widgets Qt::Multimedia Qt::Network) +target_link_libraries(${EXE_NAME} PRIVATE Qt::Widgets Qt::Multimedia Qt::Network kissfft::kissfft) if (USE_QTEXTCODEC) target_compile_definitions(${EXE_NAME} PRIVATE USE_QTEXTCODEC=1) diff --git a/fftspectrum.cpp b/fftspectrum.cpp new file mode 100644 index 0000000..7f57902 --- /dev/null +++ b/fftspectrum.cpp @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: 2024 Gary Wang +// +// SPDX-License-Identifier: MIT + +#include "fftspectrum.h" + +#include +#include +#include + +#include + +FFTSpectrum::FFTSpectrum(QWidget* parent) + : QWidget(parent) + , m_audioBufferOutput(new QAudioBufferOutput(this)) +{ + connect(this, &FFTSpectrum::mediaPlayerChanged, this, [=]() { + if (m_mediaPlayer) { + m_mediaPlayer->setAudioBufferOutput(m_audioBufferOutput); + } + }); + + connect(m_audioBufferOutput, &QAudioBufferOutput::audioBufferReceived, this, [=](const QAudioBuffer& buffer) { + const QAudioFormat&& fmt = buffer.format(); + const QAudioFormat::SampleFormat sampleFormat = fmt.sampleFormat(); + int channelCount = fmt.channelCount(); + const int frameCount = buffer.frameCount(); + kissfft fft(frameCount, false); + std::vector::cpx_t> samples(frameCount); + std::vector::cpx_t> mass(frameCount); + if (sampleFormat == QAudioFormat::Int16 && channelCount == 1) { + const QAudioBuffer::S16M* data = buffer.constData(); + for (int i = 0; i < frameCount; ++i) { + samples[i].real(data[i].value(QAudioFormat::FrontCenter) / float(32768)); + samples[i].imag(0); + } + } else if (sampleFormat == QAudioFormat::Float && channelCount == 2) { + const QAudioBuffer::F32S* data = buffer.constData(); + for (int i = 0; i < frameCount; ++i) { + samples[i].real(data[i].value(QAudioFormat::FrontLeft)); + samples[i].imag(0); + } + } + fft.transform(samples.data(), mass.data()); + m_freq.resize(frameCount); + for (int i = 0; i < frameCount; i++) { + m_freq[i] = sqrt(mass[i].real() * mass[i].real() + mass[i].imag() * mass[i].imag()); + } + for (auto& val : m_freq) { + val = log10(val + 1); + } + qDebug() << m_freq.size() << "updated"; + update(); + qDebug() << sampleFormat << channelCount; + }); + + resize(490, 420); +} + +FFTSpectrum::~FFTSpectrum() +{ + +} + +void FFTSpectrum::setMediaPlayer(QMediaPlayer* player) +{ + m_mediaPlayer = player; + emit mediaPlayerChanged(); +} + +void FFTSpectrum::paintEvent(QPaintEvent* e) +{ + QPainter painter(this); + painter.fillRect(rect(), Qt::black); + + if (!m_freq.empty()) { + int width = this->width(); + int height = this->height(); + int barWidth = std::max(1ULL, width / m_freq.size()); + qDebug() << m_freq.size() << barWidth << m_freq << "freq"; + + for (int i = 0; i < m_freq.size(); i++) { + int barHeight = static_cast(m_freq[i] * height); + painter.fillRect(i * barWidth, height - barHeight, barWidth, barHeight, Qt::green); + } + } +} + + diff --git a/fftspectrum.h b/fftspectrum.h new file mode 100644 index 0000000..e9c3342 --- /dev/null +++ b/fftspectrum.h @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2024 Gary Wang +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +class QAudioBufferOutput; +class FFTSpectrum : public QWidget +{ + Q_OBJECT + Q_PROPERTY(QMediaPlayer * mediaPlayer MEMBER m_mediaPlayer WRITE setMediaPlayer NOTIFY mediaPlayerChanged) +public: + explicit FFTSpectrum(QWidget* parent); + ~FFTSpectrum(); + + void setMediaPlayer(QMediaPlayer* player); + +signals: + void mediaPlayerChanged(); + +protected: + void paintEvent(QPaintEvent* e) override; + +private: + QMediaPlayer* m_mediaPlayer = nullptr; + QAudioBufferOutput* m_audioBufferOutput = nullptr; + std::vector m_freq; +}; diff --git a/mainwindow.cpp b/mainwindow.cpp index 6d1b7ae..b00950d 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -6,6 +6,7 @@ #include "./ui_mainwindow.h" #include "playlistmanager.h" +#include "fftspectrum.h" #include "lrcbar.h" // taglib @@ -17,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -41,13 +43,15 @@ MainWindow::MainWindow(QWidget *parent) , m_mediaDevices(new QMediaDevices(this)) , m_mediaPlayer(new QMediaPlayer(this)) , m_audioOutput(new QAudioOutput(this)) + , m_fftSpectrum(new FFTSpectrum(this)) , m_lrcbar(new LrcBar(nullptr)) , m_playlistManager(new PlaylistManager(this)) { ui->setupUi(this); m_playlistManager->setAutoLoadFilterSuffixes({ - "*.mp3", "*.wav", "*.aiff", "*.ape", "*.flac", "*.ogg", "*.oga", "*.mpga", "*.aac" + "*.mp3", "*.wav", "*.aiff", "*.ape", "*.flac", "*.ogg", "*.oga", "*.mpga", "*.aac", "*.tta" }); + m_fftSpectrum->setMediaPlayer(m_mediaPlayer); m_mediaPlayer->setAudioOutput(m_audioOutput); m_mediaPlayer->setLoops(QMediaPlayer::Infinite); ui->playlistView->setModel(m_playlistManager->model()); @@ -438,6 +442,7 @@ void MainWindow::initConnections() setAudioMetadataForDisplay(metadata.stringValue(QMediaMetaData::Title), metadata.stringValue(QMediaMetaData::Author), metadata.stringValue(QMediaMetaData::AlbumTitle)); + setAudioPropertyInfoForDisplay(-1, metadata.value(QMediaMetaData::AudioBitRate).toInt() / 1000, -1, metadata.stringValue(QMediaMetaData::FileFormat)); #endif // NO_TAGLIB QVariant coverArt(metadata.value(QMediaMetaData::ThumbnailImage)); if (!coverArt.isNull()) { diff --git a/mainwindow.h b/mainwindow.h index a6a770b..86e68fe 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -17,6 +17,7 @@ class QAudioOutput; class QPropertyAnimation; QT_END_NAMESPACE +class FFTSpectrum; class LrcBar; class PlaylistManager; class MainWindow : public QMainWindow @@ -92,6 +93,7 @@ private: QMediaDevices *m_mediaDevices; QMediaPlayer *m_mediaPlayer; QAudioOutput *m_audioOutput; + FFTSpectrum* m_fftSpectrum; LrcBar *m_lrcbar; QPropertyAnimation *m_fadeOutAnimation; PlaylistManager *m_playlistManager;