From 55eb496cd5cc601068c89e4f9a0b5745cec89211 Mon Sep 17 00:00:00 2001 From: Crylia Date: Wed, 27 Mar 2024 18:20:03 +0100 Subject: [PATCH] Did more work on the bindings between the audio and view --- src/Controller/MusicPlayer/MusicPlayer.cpp | 31 +++- src/Controller/MusicPlayer/MusicPlayer.h | 31 +++- .../FloatingControls/FloatingControls.cpp | 147 ++++++++++++++++-- .../FloatingControls/FloatingControls.h | 9 +- src/core/SongHistory/SongHistory.hpp | 4 +- src/core/audio/audio.cpp | 16 +- src/core/audio/audio.h | 10 +- src/core/song/song.h | 4 + 8 files changed, 224 insertions(+), 28 deletions(-) diff --git a/src/Controller/MusicPlayer/MusicPlayer.cpp b/src/Controller/MusicPlayer/MusicPlayer.cpp index ba142bf..f6ec244 100644 --- a/src/Controller/MusicPlayer/MusicPlayer.cpp +++ b/src/Controller/MusicPlayer/MusicPlayer.cpp @@ -3,10 +3,12 @@ MusicPlayer::~MusicPlayer( ) { } void MusicPlayer::PlaySong(Song* song) { - songHistory->push(songQueue->Top( )); songQueue->SetTop(song); + songHistory->push(songQueue->Top( )); audio.PlaySong(songQueue->Top( )->GetPath( )); + + emit SongChanged( ); } void MusicPlayer::NextSong( ) { @@ -19,6 +21,7 @@ void MusicPlayer::NextSong( ) { songQueue->Next( ); audio.PlaySong(songQueue->Top( )->GetPath( )); + emit SongChanged( ); } void MusicPlayer::NextSong(Song* song, bool isPrioQueue) { @@ -31,6 +34,7 @@ void MusicPlayer::NextSong(Song* song, bool isPrioQueue) { songQueue->JumpToSong(song, isPrioQueue); audio.PlaySong(songQueue->Top( )->GetPath( )); + emit SongChanged( ); } void MusicPlayer::PreviousSong( ) { @@ -41,6 +45,7 @@ void MusicPlayer::PreviousSong( ) { songHistory->pop( ); audio.PlaySong(songQueue->Top( )->GetPath( )); + emit SongChanged( ); } void MusicPlayer::SkipToTimestamp(unsigned const int& skipTo) { @@ -77,3 +82,27 @@ void MusicPlayer::shuffleHandler( ) { void MusicPlayer::setQueueLoop( ) { loop == All ? songQueue->LinkQueue(true) : songQueue->LinkQueue(false); } + +bool MusicPlayer::IsPlaying( ) { + return audio.IsMusicPaused( ); +} + +QPixmap MusicPlayer::GetAlbumArt( ) { + return audio.GetAlbumCover( ); +} + +/** + * @brief Resumes or Plays the music depending on the current state, if no music is playing + * it returns false + * + * @return true Music is Playing + * @return false Music is Paused or nothing is playing + */ +bool MusicPlayer::PlayPause( ) { + if (!audio.IsMusicPlaying( )) return false; + + audio.TogglePlayPause( ); + + emit SongChanged( ); + return !audio.IsMusicPaused( ); +} diff --git a/src/Controller/MusicPlayer/MusicPlayer.h b/src/Controller/MusicPlayer/MusicPlayer.h index 1a89c2f..5ac910d 100644 --- a/src/Controller/MusicPlayer/MusicPlayer.h +++ b/src/Controller/MusicPlayer/MusicPlayer.h @@ -1,17 +1,15 @@ #pragma once +#include +#include + #include "../../core/audio/audio.h" #include "../../core/SongHistory/SongHistory.hpp" #include "../../core/SongQueue/SongQueue.h" #include "../../core/song/song.h" -enum Loop { - None, - Once, - All -}; - -class MusicPlayer { +class MusicPlayer : public QObject { + Q_OBJECT public: static MusicPlayer& getInstance( ) { static MusicPlayer instance; @@ -19,7 +17,7 @@ public: } private: - MusicPlayer( ) : songQueue(new SongQueue( )) { } + MusicPlayer( ) : songQueue(new SongQueue( )), songHistory(new SongHistory( )) { } // 0 no shuffle, 1 shuffling int shuffle = 0; @@ -95,6 +93,18 @@ public: */ Song* GetCurrentlyPlaying( ); + /** + * @brief Will either play or pause a current song, if not song is active it returns false. + * + * @return true if currently playing + * @return false if paused or nothing playing + */ + bool PlayPause( ); + + bool IsPlaying( ); + + QPixmap GetAlbumArt( ); + void SetShuffle(bool shuffle) { this->shuffle = shuffle; shuffleHandler( ); @@ -102,8 +112,13 @@ public: bool GetShuffle( ) { return shuffle; } void SetLoop(Loop loop) { this->loop = loop; } Loop GetLoop( ) { return loop; } + u_short GetVolume( ) { return audio.GetVolume( ); } + void SetVolume(u_short volume) { audio.SetVolume(volume); } void AddSongToQueue(Song* song); void RemoveSongFromQueue(Song* song); void MoveSongInQueue(Song* songToMove, Song* otherSong, bool beforeElseAfter); + +signals: + void SongChanged( ); }; diff --git a/src/View/Modules/FloatingControls/FloatingControls.cpp b/src/View/Modules/FloatingControls/FloatingControls.cpp index f49bb26..42e790a 100755 --- a/src/View/Modules/FloatingControls/FloatingControls.cpp +++ b/src/View/Modules/FloatingControls/FloatingControls.cpp @@ -2,13 +2,6 @@ #include "FloatingControls.h" - -enum Repeat : short { - ALL, - CURRENT, - NONE -}; - static QPushButton* makeSongControlButton(QString name, QSize size = QSize(36, 36), QString color = "#D7D7D7") { QPushButton* button = new QPushButton( ); button->setObjectName(name); @@ -31,8 +24,7 @@ static QPushButton* makeSongControlButton(QString name, QSize size = QSize(36, 3 FloatingControls::FloatingControls(QWidget* parent) : QFrame(parent), - fullscreen(false), - songRepeat(NONE) { + fullscreen(false) { #pragma region Frame setup this->setFixedHeight(100); @@ -102,6 +94,7 @@ FloatingControls::FloatingControls(QWidget* parent) : color: #D7D7D7; } )"); + connect(&musicPlayer, &MusicPlayer::SongChanged, this, &FloatingControls::setTitle); #pragma endregion artistSongLayout->addWidget(m_artist); @@ -126,10 +119,24 @@ FloatingControls::FloatingControls(QWidget* parent) : m_skipPrev = makeSongControlButton("prevSong", QSize(36, 36), "#D7D7D7"); songControlsLayout->addWidget(m_skipPrev); m_playPause = makeSongControlButton("play", QSize(36, 36), "#D7D7D7"); + connect(m_playPause, &QPushButton::clicked, this, &FloatingControls::playPause); songControlsLayout->addWidget(m_playPause); m_skipNext = makeSongControlButton("nextSong", QSize(36, 36), "#D7D7D7"); songControlsLayout->addWidget(m_skipNext); m_loop = makeSongControlButton("songRepeat", QSize(36, 36), "#757575"); + connect(m_loop, &QPushButton::clicked, [this]( ) { + switch (musicPlayer.GetLoop( )) { + case None: + setLoop(All); + break; + case All: + setLoop(Once); + break; + case Once: + setLoop(None); + break; + } + }); songControlsLayout->addWidget(m_loop); #pragma endregion @@ -207,9 +214,9 @@ FloatingControls::FloatingControls(QWidget* parent) : m_volumeIcon = new QLabel( ); m_volumeIcon->setAlignment(Qt::AlignRight | Qt::AlignVCenter); m_volumeIcon->setObjectName("m_volumeIcon"); - m_volumeIcon->setPixmap(RenderSvg(":icons/volume-high.svg", 36, 36).scaled(QSize(24, 24), Qt::IgnoreAspectRatio)); + m_volumeIcon->setPixmap(RenderSvg(":icons/volume-medium.svg", 24, 24)); QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( ); - colorize->setColor(QColor("#78AB70")); + colorize->setColor(QColor("#FFF59D")); colorize->setStrength(1); m_volumeIcon->setGraphicsEffect(colorize); rightLayout->addWidget(m_volumeIcon); @@ -228,7 +235,7 @@ FloatingControls::FloatingControls(QWidget* parent) : background: #414141; } QSlider#m_volumeSlider::handle:horizontal{ - background: #78AB70; + background: #FFF59D; border: 4px solid #414141; width: 14px; height: 14px; @@ -237,12 +244,13 @@ FloatingControls::FloatingControls(QWidget* parent) : padding: -8px 0; } QSlider#m_volumeSlider::sub-page:horizontal{ - background: #78AB70; + background: #FFF59D; border-radius: 4px; height: 8px; } )"); m_volumeSlider->setCursor(Qt::PointingHandCursor); + connect(m_volumeSlider, &QSlider::valueChanged, this, &FloatingControls::volumeChanged); #pragma endregion rightLayout->addWidget(m_volumeSlider); @@ -304,7 +312,120 @@ void FloatingControls::setShuffle(bool shuffle) { musicPlayer.SetShuffle(shuffle); QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( ); + // Get the value to make sure it actually changed musicPlayer.GetShuffle( ) ? colorize->setColor(QColor("#CE93D8")) : colorize->setColor(QColor("#757575")); colorize->setStrength(1); m_shuffle->setGraphicsEffect(colorize); } + +void FloatingControls::volumeChanged( ) { + int value = m_volumeSlider->value( ); + musicPlayer.SetVolume(value); + + // We know MIX_MAX_VOLUME is always 0-128 so no need to calculate anything + if (value == 0) { + m_volumeIcon->setPixmap(RenderSvg(":icons/volume-off.svg", 24, 24)); + QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( ); + colorize->setColor(QColor("#FFF59D")); + colorize->setStrength(1); + m_volumeIcon->setGraphicsEffect(colorize); + } + else if (value > 0 && value < 42) { + m_volumeIcon->setPixmap(RenderSvg(":icons/volume-low.svg", 24, 24)); + QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( ); + colorize->setColor(QColor("#FFF59D")); + colorize->setStrength(1); + m_volumeIcon->setGraphicsEffect(colorize); + } + else if (value >= 42 && value < 84) { + m_volumeIcon->setPixmap(RenderSvg(":icons/volume-medium.svg", 24, 24)); + QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( ); + colorize->setColor(QColor("#FFF59D")); + colorize->setStrength(1); + m_volumeIcon->setGraphicsEffect(colorize); + } + else if (value >= 84 && value < 128) { + m_volumeIcon->setPixmap(RenderSvg(":icons/volume-high.svg", 24, 24)); + QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( ); + colorize->setColor(QColor("#FFF59D")); + colorize->setStrength(1); + m_volumeIcon->setGraphicsEffect(colorize); + } +} + +void FloatingControls::setLoop(Loop loop) { + musicPlayer.SetLoop(loop); + + QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( ); + // Get the value to make sure it actually changed + switch (musicPlayer.GetLoop( )) { + case None: + m_loop->setIcon(RenderSvg(":icons/songRepeat.svg", 36, 36)); + colorize->setColor(QColor("#757575")); + colorize->setStrength(1); + m_loop->setGraphicsEffect(colorize); + break; + case All: + m_loop->setIcon(RenderSvg(":icons/songRepeat.svg", 36, 36)); + colorize->setColor(QColor("#CE93D8")); + colorize->setStrength(1); + m_loop->setGraphicsEffect(colorize); + break; + case Once: + m_loop->setIcon(RenderSvg(":icons/repeat-once.svg", 36, 36)); + colorize->setColor(QColor("#CE93D8")); + colorize->setStrength(1); + m_loop->setGraphicsEffect(colorize); + break; + } +} + +void FloatingControls::playPause( ) { + //! TESTING ONLY + musicPlayer.PlaySong(new Song( + "Check This Out", + "", + "2Complex", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "/home/crylia/Musik/Dubstep EDM Electro/2Complex - Check This Out.mp3", + 0, + "" + )); + + bool playing = musicPlayer.IsPlaying( ); + + QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( ); + playing ? + m_playPause->setIcon(RenderSvg(":icons/play.svg", 36, 36)) : + m_playPause->setIcon(RenderSvg(":icons/pause.svg", 36, 36)); + colorize->setColor(QColor("#D7D7D7")); + colorize->setStrength(1); + m_playPause->setGraphicsEffect(colorize); +} + +void FloatingControls::setTitle( ) { + std::cout << musicPlayer.GetCurrentlyPlaying( )->GetTitle( ) << std::endl; + m_title->setText(QString::fromStdString(musicPlayer.GetCurrentlyPlaying( )->GetTitle( ))); + m_artist->setText(QString::fromStdString(musicPlayer.GetCurrentlyPlaying( )->GetArtist( ))); + + m_albumArt->setPixmap(musicPlayer.GetAlbumArt( )); + QRect targetRect; + if (m_albumArt->pixmap( ).width( ) > m_albumArt->pixmap( ).height( )) { + int sideLength = m_albumArt->pixmap( ).height( ); + targetRect = QRect((m_albumArt->pixmap( ).width( ) - sideLength) / 2, 0, sideLength, sideLength); + } + else { + int sideLength = m_albumArt->pixmap( ).width( ); + targetRect = QRect(0, (m_albumArt->pixmap( ).height( ) - sideLength) / 2, sideLength, sideLength); + } + + m_albumArt->setPixmap(m_albumArt->pixmap( ).copy(targetRect).scaled(QSize(64, 64), Qt::KeepAspectRatio)); +} diff --git a/src/View/Modules/FloatingControls/FloatingControls.h b/src/View/Modules/FloatingControls/FloatingControls.h index c702439..e82799f 100755 --- a/src/View/Modules/FloatingControls/FloatingControls.h +++ b/src/View/Modules/FloatingControls/FloatingControls.h @@ -59,8 +59,15 @@ private: QSlider* m_volumeSlider; bool fullscreen; - Repeat songRepeat; + +signals: + void SongChanged( ); private slots: void setShuffle(bool shuffle); + void setLoop(Loop loop); + void volumeChanged( ); + void playPause( ); + + void setTitle( ); }; diff --git a/src/core/SongHistory/SongHistory.hpp b/src/core/SongHistory/SongHistory.hpp index faaa459..e816cef 100644 --- a/src/core/SongHistory/SongHistory.hpp +++ b/src/core/SongHistory/SongHistory.hpp @@ -10,10 +10,10 @@ private: Node* next; }; - Node* topNode = nullptr; + Node* topNode; public: - SongHistory( ) { } + SongHistory( ) : topNode(nullptr) { } ~SongHistory( ) { while (!isEmpty( )) pop( ); diff --git a/src/core/audio/audio.cpp b/src/core/audio/audio.cpp index 55c49d4..8756de1 100644 --- a/src/core/audio/audio.cpp +++ b/src/core/audio/audio.cpp @@ -22,7 +22,7 @@ Audio::~Audio( ) { void Audio::StartMusic( ) { if (Mix_PlayingMusic( ) == 0) { //TODO: Get the loop status from the FloatingControls widget and replace the 1 - Mix_PlayMusic(music, 1); + Mix_PlayMusic(music, this->loop); } } @@ -43,6 +43,7 @@ void Audio::PlaySong(const std::string path) { SDL_Quit( ); return; } + Mix_PlayMusic(music, this->loop); } void Audio::PauseMusic( ) { @@ -57,6 +58,17 @@ void Audio::ResumeMusic( ) { } } +void Audio::TogglePlayPause( ) { + if (IsMusicPaused( )) + ResumeMusic( ); + else + PauseMusic( ); +} + +bool Audio::IsMusicPaused( ) { + return (Mix_PausedMusic( ) == 1); +} + bool Audio::IsMusicPlaying( ) { return (Mix_PlayingMusic( ) != 0); } @@ -112,7 +124,7 @@ QPixmap Audio::GetAlbumCover( ) { } int Audio::GetVolume( ) { - return Mix_GetMusicVolume(music); + return Mix_VolumeMusic(-1); } void Audio::SetVolume(int vol) { diff --git a/src/core/audio/audio.h b/src/core/audio/audio.h index d203c96..e16782a 100644 --- a/src/core/audio/audio.h +++ b/src/core/audio/audio.h @@ -12,6 +12,12 @@ extern "C" { #include +enum Loop { + None, + All, + Once +}; + class Audio { public: static Audio& getInstance( ) { @@ -24,6 +30,7 @@ private: std::string path; std::string artist; std::string album; + Loop loop; Mix_Music* music; @@ -50,7 +57,8 @@ public: void PauseMusic( ); void ResumeMusic( ); bool IsMusicPlaying( ); - + void TogglePlayPause( ); + bool IsMusicPaused( ); void SetVolume(int vol); int GetVolume( ); }; diff --git a/src/core/song/song.h b/src/core/song/song.h index f4d095e..a694269 100644 --- a/src/core/song/song.h +++ b/src/core/song/song.h @@ -51,4 +51,8 @@ public: std::string GetPath( ) { return path; }; + std::string GetTitle( ) { return title; } + std::string GetAlbum( ) { return album; } + std::string GetArtist( ) { return artist; } + };