Part of a larger restructure, added MusicPlayer which is the main controller and a structure for the song queue

This commit is contained in:
Crylia
2024-03-26 12:03:41 +01:00
parent a2872f6479
commit 9023766c51
67 changed files with 1218 additions and 262 deletions

View File

@@ -28,9 +28,9 @@ pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET
) )
PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2) PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2)
file(GLOB_RECURSE PROJECT_SOURCES ../src/*.cpp) file(GLOB_RECURSE PROJECT_SOURCES src/*.cpp)
file(GLOB_RECURSE PROJECT_HEADERS ../src/*.h) file(GLOB_RECURSE PROJECT_HEADERS src/*.h)
file(GLOB_RECURSE PROJECT_RESOURCES ../assets/resources.qrc) file(GLOB_RECURSE PROJECT_RESOURCES assets/resources.qrc)
add_executable(CryliaPlayer add_executable(CryliaPlayer
${PROJECT_SOURCES} ${PROJECT_SOURCES}
@@ -61,4 +61,4 @@ set(DESKTOP_FILE ${CMAKE_CURRENT_BINARY_DIR}/CryliaPlayer.desktop)
configure_file(${DESKTOP_FILE_IN} ${DESKTOP_FILE} @ONLY) configure_file(${DESKTOP_FILE_IN} ${DESKTOP_FILE} @ONLY)
install(FILES ${DESKTOP_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications) install(FILES ${DESKTOP_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
install(FILES ../assets/aqua.jpg DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons) install(FILES assets/aqua.jpg DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons)

View File

Before

Width:  |  Height:  |  Size: 193 B

After

Width:  |  Height:  |  Size: 193 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20,18H4V8H20M20,6H12L10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6Z" /></svg>

After

Width:  |  Height:  |  Size: 185 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 5.69L17 10.19V18H15V12H9V18H7V10.19L12 5.69M12 3L2 12H5V20H11V14H13V20H19V12H22" /></svg>

After

Width:  |  Height:  |  Size: 162 B

View File

Before

Width:  |  Height:  |  Size: 336 B

After

Width:  |  Height:  |  Size: 336 B

View File

Before

Width:  |  Height:  |  Size: 339 B

After

Width:  |  Height:  |  Size: 339 B

View File

Before

Width:  |  Height:  |  Size: 109 B

After

Width:  |  Height:  |  Size: 109 B

View File

Before

Width:  |  Height:  |  Size: 109 B

After

Width:  |  Height:  |  Size: 109 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6V8H14V6H3M3 10V12H14V10H3M20 10.1C19.9 10.1 19.7 10.2 19.6 10.3L18.6 11.3L20.7 13.4L21.7 12.4C21.9 12.2 21.9 11.8 21.7 11.6L20.4 10.3C20.3 10.2 20.2 10.1 20 10.1M18.1 11.9L12 17.9V20H14.1L20.2 13.9L18.1 11.9M3 14V16H10V14H3Z" /></svg>

After

Width:  |  Height:  |  Size: 307 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15,6V8H3V6H15M15,10V12H3V10H15M3,16V14H11V16H3M17,6H22V8H19V17A3,3 0 0,1 16,20A3,3 0 0,1 13,17A3,3 0 0,1 16,14C16.35,14 16.69,14.07 17,14.18V6M16,16A1,1 0 0,0 15,17A1,1 0 0,0 16,18A1,1 0 0,0 17,17A1,1 0 0,0 16,16Z" /></svg>

After

Width:  |  Height:  |  Size: 293 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 16H10V14H3M18 14V10H16V14H12V16H16V20H18V16H22V14M14 6H3V8H14M14 10H3V12H14V10Z" /></svg>

After

Width:  |  Height:  |  Size: 161 B

View File

Before

Width:  |  Height:  |  Size: 332 B

After

Width:  |  Height:  |  Size: 332 B

View File

Before

Width:  |  Height:  |  Size: 388 B

After

Width:  |  Height:  |  Size: 388 B

View File

Before

Width:  |  Height:  |  Size: 460 B

After

Width:  |  Height:  |  Size: 460 B

View File

Before

Width:  |  Height:  |  Size: 360 B

After

Width:  |  Height:  |  Size: 360 B

View File

Before

Width:  |  Height:  |  Size: 535 B

After

Width:  |  Height:  |  Size: 535 B

View File

Before

Width:  |  Height:  |  Size: 346 B

After

Width:  |  Height:  |  Size: 346 B

View File

Before

Width:  |  Height:  |  Size: 412 B

After

Width:  |  Height:  |  Size: 412 B

View File

Before

Width:  |  Height:  |  Size: 457 B

After

Width:  |  Height:  |  Size: 457 B

View File

Before

Width:  |  Height:  |  Size: 712 B

After

Width:  |  Height:  |  Size: 712 B

View File

@@ -1,20 +1,6 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file>aqua.jpg</file> <file>aqua.jpg</file>
<file>icons/songControl/shuffle.svg</file> <file>icons/</file>
<file>icons/songControl/prevSong.svg</file>
<file>icons/songControl/nextSong.svg</file>
<file>icons/songControl/play.svg</file>
<file>icons/songControl/pause.svg</file>
<file>icons/songControl/songRepeat.svg</file>
<file>icons/songControl/repeat-once.svg</file>
<file>icons/songControl/volume-high.svg</file>
<file>icons/songControl/volume-low.svg</file>
<file>icons/songControl/volume-mute.svg</file>
<file>icons/songControl/volume-off.svg</file>
<file>icons/songControl/volume-medium.svg</file>
<file>icons/songControl/arrow-expand.svg</file>
<file>icons/home.svg</file>
<file>icons/songControl/magnify.svg</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@@ -0,0 +1,79 @@
#include "MusicPlayer.h"
MusicPlayer::~MusicPlayer( ) { }
void MusicPlayer::PlaySong(Song* song) {
songHistory->push(songQueue->Top( ));
songQueue->SetTop(song);
audio.PlaySong(songQueue->Top( )->GetPath( ));
}
void MusicPlayer::NextSong( ) {
if (songQueue->IsEmpty( )) {
audio.StopMusic( );
return;
}
songHistory->push(songQueue->Top( ));
songQueue->Next( );
audio.PlaySong(songQueue->Top( )->GetPath( ));
}
void MusicPlayer::NextSong(Song* song, bool isPrioQueue) {
if (songQueue->IsEmpty( )) {
audio.StopMusic( );
return;
}
songHistory->push(songQueue->Top( ));
songQueue->JumpToSong(song, isPrioQueue);
audio.PlaySong(songQueue->Top( )->GetPath( ));
}
void MusicPlayer::PreviousSong( ) {
if (songHistory->isEmpty( ))
return;
songQueue->SetTop(songHistory->top( ));
songHistory->pop( );
audio.PlaySong(songQueue->Top( )->GetPath( ));
}
void MusicPlayer::SkipToTimestamp(unsigned const int& skipTo) {
if (audio.IsMusicPlaying( ) == 0) return;
audio.SetMusicPos(skipTo);
}
int MusicPlayer::GetSongProgression( ) {
return audio.IsMusicPlaying( ) == 1 ? audio.GetMusicPos( ) : 0;
}
Song* MusicPlayer::GetCurrentlyPlaying( ) {
return songQueue->Top( );
}
//For the PriorityQueue
void MusicPlayer::AddSongToQueue(Song* song) {
songQueue->AddToPriorityQueue(song);
}
void MusicPlayer::RemoveSongFromQueue(Song* song) {
songQueue->RemoveSongFromPriorityQueue(song);
}
void MusicPlayer::MoveSongInQueue(Song* songToMove, Song* otherSong, bool beforeElseAfter) {
songQueue->MoveSongInPriorityQueue(songToMove, otherSong, beforeElseAfter);
}
void MusicPlayer::shuffleQueue( ) {
shuffle ? songQueue->ShufflePlaylist( ) : songQueue->RestorePlaylist( );
}
void MusicPlayer::setQueueLoop( ) {
loop == All ? songQueue->LinkQueue(true) : songQueue->LinkQueue(false);
}

View File

@@ -0,0 +1,104 @@
#pragma once
#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 {
public:
static MusicPlayer& getInstance( ) {
static MusicPlayer instance;
return instance;
}
private:
MusicPlayer( );
// 0 no shuffle, 1 shuffling
int shuffle = 0;
// None, Once, All
Loop loop = None;
// 0 stopped, 1 playing
bool playing = 0;
// Song queue, will be filled with the entire playlist by default
SongQueue* songQueue;
// Contain all played songs
SongHistory<Song*>* songHistory;
Audio& audio = Audio::getInstance( );
void shuffleQueue( );
void setQueueLoop( );
public:
~MusicPlayer( );
MusicPlayer(MusicPlayer const&) = delete;
void operator=(MusicPlayer const&) = delete;
/**
* @brief Will start playing the given song and put itself at the queue top.
*
* @param song Song that will start playing
*/
void PlaySong(Song* song);
/**
* @brief Skip the current song and play the next in queue,
* if nothing is in queue it will stop playing anything.
*
*/
void NextSong( );
/**
* @brief Jumps the queue to the given song keeping the non altered queue intact
*
* @param song
* @param isPrioQueue If the song is in the prio queue or normal queue
*/
void NextSong(Song* song, bool isPrioQueue);
/**
* @brief Rewind the currently playing song to the beginning if playtime >= 5 seconds.
* Otherwise play the top song in the history stack
*
*/
void PreviousSong( );
/**
* @brief Skip the song to the given timestamp
*
* @param skipTo time as positive integer
*/
void SkipToTimestamp(unsigned const int& skipTo);
/**
* @brief Get the current Song progression as an positive integer
*
* @return int current timestamp
*/
int GetSongProgression( );
/**
* @brief Get the Currently Playing Song
*
* @return Song& Song thats currently playing
*/
Song* GetCurrentlyPlaying( );
void SetShuffle(bool shuffle) { this->shuffle = shuffle; }
void SetLoop(Loop loop) { this->loop = loop; }
void AddSongToQueue(Song* song);
void RemoveSongFromQueue(Song* song);
void MoveSongInQueue(Song* songToMove, Song* otherSong, bool beforeElseAfter);
};

View File

View File

@@ -1,46 +0,0 @@
#include "MainWindow.h"
void MainWindow::setupMainWindow( ) {
this->setWindowTitle("Crylia Player");
this->setWindowIcon(QIcon(":aqua.jpg"));
QWidget* mw = new QWidget(this);
mw->setContentsMargins(10, 10, 10, 10);
QOverlayout* ol = new QOverlayout(mw);
mw->setLayout(ol);
Pages* p = new Pages(mw);
PlaylistPage* pp = new PlaylistPage(mw);
PlaylistWidget* pw = new PlaylistWidget(mw);
FloatingControls* fc = new FloatingControls(mw, this->path);
QVBoxLayout* vbox = new QVBoxLayout( );
vbox->addWidget(fc, 0, Qt::AlignBottom);
QHBoxLayout* hbox = new QHBoxLayout( );
QVBoxLayout* vbox2 = new QVBoxLayout( );
vbox2->addWidget(p);
vbox2->addWidget(pw);
hbox->addLayout(vbox2);
hbox->addWidget(pp);
hbox->setSpacing(10);
vbox2->setSpacing(10);
ol->addItem(vbox);
ol->addItem(hbox);
this->setCentralWidget(mw);
}
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent) {
setupMainWindow( );
}
MainWindow::MainWindow(std::filesystem::path path, QWidget* parent)
: QMainWindow(parent), path(path) {
setupMainWindow( );
}
MainWindow::~MainWindow( ) { }

View File

@@ -1,27 +0,0 @@
#include "pages.h"
#include <QWidget>
#include <QFrame>
Pages::Pages(QWidget* parent) :QFrame(parent) {
this->setStyleSheet(R"(
background-color: #282828;
border-radius: 12px;
)");
this->setFixedSize(300, 180);
QVBoxLayout* layout = new QVBoxLayout(this);
PageNavigator* home = new PageNavigator("Home", ":icons/home.svg");
PageNavigator* localFiles = new PageNavigator("Local Files", ":icons/home.svg");
PageNavigator* playlist = new PageNavigator("Playlist", ":icons/songControl/magnify.svg");
layout->addWidget(home);
layout->addWidget(localFiles);
layout->addWidget(playlist);
}
Pages::~Pages( ) { }

View File

@@ -1,17 +0,0 @@
#pragma once
#include <QWidget>
#include <QFrame>
#include "../../Widgets/PageNavigator/PageNavigator.h"
class Pages : public QFrame {
Q_OBJECT
private:
//Page[3] pages;
public:
Pages(QWidget* parent = nullptr);
~Pages( );
};

View File

@@ -1,18 +0,0 @@
#include "PlaylistPage.h"
#include <QWidget>
#include <QScrollArea>
#include <QPushButton>
#include <QVBoxLayout>
#include <QScrollBar>
#include <QLabel>
PlaylistPage::PlaylistPage(QWidget* parent) : QFrame(parent) {
this->setStyleSheet(R"(
background-color: #282828;
border-radius: 12px;
)");
}
PlaylistPage::~PlaylistPage( ) { }

View File

@@ -1,16 +0,0 @@
#pragma once
#include <QPixmap>
#include <QString>
#include <QSvgRenderer>
#include <QPainter>
static QPixmap RenderSvg(QString path, int w, int h) {
QSvgRenderer renderer(path);
QPixmap pixmap(w, h);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
renderer.render(&painter);
return pixmap;
}

View File

@@ -1,54 +0,0 @@
#include "PageNavigator.h"
#include "SelectHandler.hpp"
PageNavigator::PageNavigator(QString text, QString icon, QWidget* parent)
:m_text(new QLabel(text)), m_icon(new QLabel( )) {
m_icon->setPixmap(icon);
setObjectName("PageNavigator");
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setStyleSheet(R"(
#PageNavigator{
border: 4px solid #414141;
border-radius: 8px;
color: #E0E0E0;
}
)");
QFont font = m_text->font( );
font.setPointSize(16);
font.setWeight(QFont::Bold);
m_text->setFont(font);
QHBoxLayout* layout = new QHBoxLayout(this);
layout->addWidget(m_icon, 0, Qt::AlignLeft);
layout->addWidget(m_text, 1, Qt::AlignLeft);
connect(this, &QPushButton::clicked, [this]( ) {
SelectHandler* sh = SelectHandler::GetInstance( );
sh->setSelected(this);
});
}
void PageNavigator::unselect( ) {
setStyleSheet(R"(
#PageNavigator{
border: 4px solid #414141;
border-radius: 6px;
color: #E0E0E0;
}
)");
}
void PageNavigator::select( ) {
setStyleSheet(R"(
#PageNavigator{
border: 4px solid #81D4FA;
border-radius: 6px;
color: #E0E0E0;
}
)");
}

68
src/View/MainWidget.cpp Normal file
View File

@@ -0,0 +1,68 @@
#include "MainWidget.h"
void MainWidget::setupMainWidget( ) {
setContentsMargins(10, 10, 10, 10);
QOverlayout* ol = new QOverlayout(this);
setLayout(ol);
QVBoxLayout* vbox = new QVBoxLayout( );
vbox->addWidget(floatingControlls, 0, Qt::AlignBottom);
QHBoxLayout* hbox = new QHBoxLayout( );
QVBoxLayout* vbox2 = new QVBoxLayout( );
vbox2->addWidget(pageNav);
vbox2->addWidget(playlistNav);
hbox->addLayout(vbox2);
QHBoxLayout* stackedLayout = new QHBoxLayout( );
stackedLayout->addWidget(homePage);
stackedLayout->addWidget(playlistPage);
playlistPage->setVisible(false);
hbox->addLayout(stackedLayout, 0);
hbox->setSpacing(10);
vbox2->setSpacing(10);
ol->addItem(hbox);
ol->addItem(vbox);
connect(pageNav, &PageNavModule::SelectChanged, [this, stackedLayout](PageNavigator* pn) {
if (pn->GetText( ).toStdString( ) == "Home") {
//stackedLayout->setCurrentIndex(0);
stackedLayout->itemAt(0)->widget( )->setVisible(true);
stackedLayout->itemAt(1)->widget( )->setVisible(false);
}
else if (pn->GetText( ).toStdString( ) == "Playlist") {
//stackedLayout->setCurrentIndex(1);
stackedLayout->itemAt(0)->widget( )->setVisible(false);
stackedLayout->itemAt(1)->widget( )->setVisible(true);
}
});
}
void MainWidget::PageChangedAction( ) { }
MainWidget::MainWidget(QWidget* parent)
: QWidget(parent),
pageNav(new PageNavModule(this)),
playlistNav(new PlaylistNavModule(this)),
playlistPage(new PlaylistPage(this)),
homePage(new HomePage(this)),
floatingControlls(new FloatingControls(this)) {
setupMainWidget( );
}
MainWidget::MainWidget(std::filesystem::path path, QWidget* parent)
: QWidget(parent),
pageNav(new PageNavModule(this)),
playlistNav(new PlaylistNavModule(this)),
playlistPage(new PlaylistPage(this)),
homePage(new HomePage(this)),
floatingControlls(new FloatingControls(this, path)) {
setupMainWidget( );
}
MainWidget::~MainWidget( ) { }

38
src/View/MainWidget.h Normal file
View File

@@ -0,0 +1,38 @@
#pragma once
#include <QWidget>
#include <QLayout>
#include <filesystem>
#include <QStackedLayout>
#include "Layouts/QOverlayout.h"
#include "Modules/FloatingControls/FloatingControls.h"
#include "Modules/PageNavModule/PageNavModule.h"
#include "Modules/PlaylistNavModule/PlaylistNavModule.h"
#include "Pages/Playlist/PlaylistPage.h"
#include "Pages/Home/HomePage.h"
class MainWidget : public QWidget {
Q_OBJECT
private:
PageNavModule* pageNav;
PlaylistNavModule* playlistNav;
PlaylistPage* playlistPage;
HomePage* homePage;
FloatingControls* floatingControlls;
void setupMainWidget( );
public:
MainWidget(QWidget* parent = nullptr);
MainWidget(std::filesystem::path path, QWidget* parent = nullptr);
~MainWidget( );
private slots:
void PageChangedAction( );
};

27
src/View/MainWindow.cpp Executable file
View File

@@ -0,0 +1,27 @@
#include "MainWindow.h"
void MainWindow::setupMainWindow( ) {
this->setWindowTitle("Crylia Player");
this->setWindowIcon(QIcon(":aqua.jpg"));
setObjectName("MainWindow");
setStyleSheet(R"(
#MainWindow{
background-color: #121212;
}
)");
this->setCentralWidget(mainWidget);
}
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent), mainWidget(new MainWidget(this)) {
setupMainWindow( );
}
MainWindow::MainWindow(std::filesystem::path path, QWidget* parent)
: QMainWindow(parent), mainWidget(new MainWidget(path, this)) {
setupMainWindow( );
}
MainWindow::~MainWindow( ) { }

View File

@@ -7,23 +7,17 @@
#include <QPixmap> #include <QPixmap>
#include <filesystem> #include <filesystem>
#include "Modules/FloatingControls/FloatingControls.h" #include "MainWidget.h"
#include "Layouts/QOverlayout.h"
#include "Modules/PageNavigator/pages.h"
#include "Pages/Playlist/PlaylistPage.h"
#include "Modules/PlaylistNavigator/PlaylistWidget.h"
class MainWindow : public QMainWindow { class MainWindow : public QMainWindow {
Q_OBJECT Q_OBJECT
public: public:
MainWindow(QWidget* parent = nullptr); MainWindow(QWidget* parent = nullptr);
MainWindow(std::filesystem::path path, QWidget* parent = nullptr); MainWindow(std::filesystem::path path, QWidget* parent = nullptr);
~MainWindow( ); ~MainWindow( );
private: private:
// In case the program gets started with a song as an argument MainWidget* mainWidget;
std::filesystem::path path;
void setupMainWindow( ); void setupMainWindow( );
}; };

View File

@@ -20,27 +20,6 @@ enum Repeat : short {
NONE NONE
}; };
template <typename T>
static void applyShadow(T obj, int blurRadius = 20, int xOffset = 10, int yOffset = 10, QString color = "#000000", int offset = 2) {
QGraphicsDropShadowEffect* dropShadow = new QGraphicsDropShadowEffect( );
dropShadow->setBlurRadius(blurRadius);
dropShadow->setXOffset(xOffset);
dropShadow->setYOffset(yOffset);
dropShadow->setColor(color);
dropShadow->setOffset(offset);
obj->setGraphicsEffect(dropShadow);
}
static QPixmap RenderSvg(QString path) {
QSvgRenderer renderer(path);
QPixmap pixmap(36, 36);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
renderer.render(&painter);
return pixmap;
}
static QPushButton* makeSongControlButton(QString name, QSize size = QSize(36, 36), QString color = "#D7D7D7") { static QPushButton* makeSongControlButton(QString name, QSize size = QSize(36, 36), QString color = "#D7D7D7") {
QPushButton* button = new QPushButton( ); QPushButton* button = new QPushButton( );
button->setObjectName(name); button->setObjectName(name);
@@ -50,7 +29,7 @@ static QPushButton* makeSongControlButton(QString name, QSize size = QSize(36, 3
border: 0; border: 0;
} }
)"); )");
button->setIcon(RenderSvg(":/icons/songControl/" + name + ".svg")); button->setIcon(RenderSvg(":/icons/" + name + ".svg", 36, 36));
button->setIconSize(size); button->setIconSize(size);
button->setCursor(Qt::PointingHandCursor); button->setCursor(Qt::PointingHandCursor);
QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( ); QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( );
@@ -70,7 +49,7 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path)
songRepeat(NONE), songRepeat(NONE),
artist("Artist"), artist("Artist"),
songName("Song"), songName("Song"),
song(Audio::getInstance(path)) { song(Audio::getInstance( )) {
this->setFixedHeight(100); this->setFixedHeight(100);
this->setObjectName("main"); this->setObjectName("main");
this->setStyleSheet(R"( this->setStyleSheet(R"(
@@ -145,7 +124,7 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path)
QHBoxLayout* songControlsLayout = new QHBoxLayout( ); QHBoxLayout* songControlsLayout = new QHBoxLayout( );
songControlsLayout->setAlignment(Qt::AlignCenter | Qt::AlignBottom); songControlsLayout->setAlignment(Qt::AlignCenter | Qt::AlignBottom);
QString buttonNames[5] = { "songRepeat", "prevSong", "play", "nextSong", "shuffle" }; QString buttonNames[5] = { "shuffle", "prevSong", "play", "nextSong", "songRepeat" };
QString col = "#D7D7D7"; QString col = "#D7D7D7";
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
if (buttonNames[i] == "shuffle" || buttonNames[i] == "songRepeat") if (buttonNames[i] == "shuffle" || buttonNames[i] == "songRepeat")
@@ -158,16 +137,16 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path)
QObject::connect(pb, &QPushButton::clicked, [pb, this]( ) { QObject::connect(pb, &QPushButton::clicked, [pb, this]( ) {
if (!song.IsMusicPlaying( )) { if (!song.IsMusicPlaying( )) {
song.StartMusic( ); song.StartMusic( );
pb->setIcon(RenderSvg(":/icons/songControl/pause.svg")); pb->setIcon(RenderSvg(":/icons/pause.svg", 36, 36));
return; return;
} }
if (GetPlayPause( )) { if (GetPlayPause( )) {
song.ResumeMusic( ); song.ResumeMusic( );
pb->setIcon(RenderSvg(":/icons/songControl/pause.svg")); pb->setIcon(RenderSvg(":/icons/pause.svg", 36, 36));
} }
else { else {
song.PauseMusic( ); song.PauseMusic( );
pb->setIcon(RenderSvg(":/icons/songControl/play.svg")); pb->setIcon(RenderSvg(":/icons/play.svg", 36, 36));
} }
togglePlayPause( ); togglePlayPause( );
}); });
@@ -279,7 +258,7 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path)
QLabel* volumeIcon = new QLabel( ); QLabel* volumeIcon = new QLabel( );
volumeIcon->setAlignment(Qt::AlignRight | Qt::AlignVCenter); volumeIcon->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
volumeIcon->setObjectName("volumeIcon"); volumeIcon->setObjectName("volumeIcon");
volumeIcon->setPixmap(RenderSvg(":icons/songControl//volume-high.svg").scaled(QSize(24, 24), Qt::IgnoreAspectRatio)); volumeIcon->setPixmap(RenderSvg(":icons/volume-high.svg", 36, 36).scaled(QSize(24, 24), Qt::IgnoreAspectRatio));
QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( ); QGraphicsColorizeEffect* colorize = new QGraphicsColorizeEffect( );
colorize->setColor(QColor("#78AB70")); colorize->setColor(QColor("#78AB70"));
colorize->setStrength(1); colorize->setStrength(1);
@@ -344,7 +323,7 @@ FloatingControls::FloatingControls(QWidget* parent, std::filesystem::path path)
QLabel* FullscreenLabel = new QLabel( ); QLabel* FullscreenLabel = new QLabel( );
FullscreenLabel->setFixedSize(36, 24); FullscreenLabel->setFixedSize(36, 24);
FullscreenLabel->setObjectName("fullscreenLabel"); FullscreenLabel->setObjectName("fullscreenLabel");
FullscreenLabel->setPixmap(QPixmap(":icons/songControl//arrow-expand.svg").scaled(QSize(24, 24), Qt::IgnoreAspectRatio)); FullscreenLabel->setPixmap(QPixmap(":icons/arrow-expand.svg").scaled(QSize(24, 24), Qt::IgnoreAspectRatio));
QVBoxLayout* FullscreenLayout = new QVBoxLayout( ); QVBoxLayout* FullscreenLayout = new QVBoxLayout( );
FullscreenLayout->setAlignment(Qt::AlignCenter); FullscreenLayout->setAlignment(Qt::AlignCenter);

View File

@@ -1,12 +1,14 @@
#pragma once #pragma once
#include "../../../core/audio/audio.h" #include "../../../core/audio/audio.h"
#include "../../Tools/SvgToPixmap.hpp"
#include <QFrame> #include <QFrame>
#include <QSlider> #include <QSlider>
#include <QPushButton> #include <QPushButton>
#include <QObject> #include <QObject>
#include <filesystem> #include <filesystem>
#include <QStackedLayout>
enum Repeat : short; enum Repeat : short;

View File

@@ -0,0 +1,32 @@
#include "PageNavModule.h"
#include <QWidget>
#include <QFrame>
PageNavModule::PageNavModule(QWidget* parent) :QFrame(parent) {
this->setStyleSheet(R"(
background-color: #282828;
border-radius: 12px;
)");
applyShadow(this);
this->setFixedSize(300, 180);
QVBoxLayout* layout = new QVBoxLayout(this);
PageNavigator* home = new PageNavigator("Home", ":icons/home-outline.svg", "#81D4FA");
PageNavigator* localFiles = new PageNavigator("Local Files", ":icons/folder-outline.svg", "#FFE082");
PageNavigator* playlist = new PageNavigator("Playlist", ":icons/magnify.svg", "#CE93D8");
layout->addWidget(home);
layout->addWidget(localFiles);
layout->addWidget(playlist);
connect(home, &PageNavigator::SelectedChanged, this, &PageNavModule::SelectChanged);
connect(localFiles, &PageNavigator::SelectedChanged, this, &PageNavModule::SelectChanged);
connect(playlist, &PageNavigator::SelectedChanged, this, &PageNavModule::SelectChanged);
}
PageNavModule::~PageNavModule( ) { }

View File

@@ -0,0 +1,20 @@
#pragma once
#include <QWidget>
#include <QVector>
#include <QFrame>
#include "../../Widgets/PageNavigator/PageNavigator.h"
#include "../../Tools/SvgToPixmap.hpp"
class PageNavModule : public QFrame {
Q_OBJECT
private:
QVector<PageNavigator> pages;
public:
PageNavModule(QWidget* parent = nullptr);
~PageNavModule( );
signals:
void SelectChanged(PageNavigator* pn);
};

View File

@@ -1,6 +1,6 @@
#include "PlaylistWidget.h" #include "PlaylistNavModule.h"
PlaylistWidget::PlaylistWidget(QWidget* parent) : QFrame(parent) { PlaylistNavModule::PlaylistNavModule(QWidget* parent) : QFrame(parent) {
this->setStyleSheet(R"( this->setStyleSheet(R"(
background-color: #282828; background-color: #282828;
@@ -14,4 +14,4 @@ PlaylistWidget::PlaylistWidget(QWidget* parent) : QFrame(parent) {
} }
PlaylistWidget::~PlaylistWidget( ) { } PlaylistNavModule::~PlaylistNavModule( ) { }

View File

@@ -4,13 +4,13 @@
#include <QFrame> #include <QFrame>
#include <QLayout> #include <QLayout>
class PlaylistWidget : public QFrame { class PlaylistNavModule : public QFrame {
Q_OBJECT Q_OBJECT
private: private:
public: public:
PlaylistWidget(QWidget* parent); PlaylistNavModule(QWidget* parent);
~PlaylistWidget( ); ~PlaylistNavModule( );
}; };

View File

@@ -0,0 +1,14 @@
#include "HomePage.h"
HomePage::HomePage(QWidget* parent)
: QFrame(parent) {
setStyleSheet(R"(
background-color: #28FF28;
border-radius: 12px;
)");
applyShadow(this);
}
HomePage::~HomePage( ) { }

View File

@@ -0,0 +1,15 @@
#pragma once
#include <QWidget>
#include <QFrame>
#include "../../Tools/SvgToPixmap.hpp"
class HomePage : public QFrame {
Q_OBJECT
private:
/* data */
public:
HomePage(QWidget* parent = nullptr);
~HomePage( );
};

View File

@@ -0,0 +1,14 @@
#include "PlaylistPage.h"
PlaylistPage::PlaylistPage(QWidget* parent)
: QFrame(parent) {
setStyleSheet(R"(
background-color: #2828ff;
border-radius: 12px;
)");
applyShadow(this);
}
PlaylistPage::~PlaylistPage( ) { }

View File

@@ -2,13 +2,12 @@
#include <QWidget> #include <QWidget>
#include <QFrame> #include <QFrame>
#include "../../Tools/SvgToPixmap.hpp"
class PlaylistPage : public QFrame { class PlaylistPage : public QFrame {
Q_OBJECT Q_OBJECT
private: private:
public: public:
PlaylistPage(QWidget* parent); PlaylistPage(QWidget* parent = nullptr);
~PlaylistPage( ); ~PlaylistPage( );
}; };

View File

@@ -0,0 +1,29 @@
#pragma once
#include <QWidget>
#include <QPixmap>
#include <QString>
#include <QSvgRenderer>
#include <QPainter>
#include <QGraphicsDropShadowEffect>
static QPixmap RenderSvg(QString path, int w, int h) {
QSvgRenderer renderer(path);
QPixmap pixmap(w, h);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
renderer.render(&painter);
return pixmap;
}
template <typename T>
static void applyShadow(T obj, int blurRadius = 20, int xOffset = 10, int yOffset = 10, QString color = "#000000", int offset = 2) {
QGraphicsDropShadowEffect* dropShadow = new QGraphicsDropShadowEffect( );
dropShadow->setBlurRadius(blurRadius);
dropShadow->setXOffset(xOffset);
dropShadow->setYOffset(yOffset);
dropShadow->setColor(color);
dropShadow->setOffset(offset);
obj->setGraphicsEffect(dropShadow);
}

View File

@@ -0,0 +1,11 @@
#include "NavigationButton.h"
NavigationButton::NavigationButton( ) { }
NavigationButton::~NavigationButton( ) { }
void setSelected(NavigationButton* newSelected);
NavigationButton getSelected( ) { }
void NavigationButton::select( ) { }
void NavigationButton::unselect( ) { }

View File

@@ -0,0 +1,31 @@
#pragma once
#include <QPushButton>
#include <QLabel>
#include <QString>
class NavigationButton : public QPushButton {
Q_OBJECT
private:
QLabel* m_icon;
QLabel* m_name;
QString* m_colorHex;
static NavigationButton* m_selected;
public:
static void setSelected(NavigationButton* newSelected);
static NavigationButton* getSelected( );
NavigationButton( );
~NavigationButton( );
signals:
void unselected( );
void selected( );
private slots:
void select( );
void unselect( );
};

View File

@@ -0,0 +1,4 @@
#include "PagesButton.h"
PagesButton::PagesButton( ) { }
PagesButton::~PagesButton( ) { }

View File

@@ -0,0 +1,11 @@
#pragma once
#include "../NavigationButton.h"
class PagesButton : NavigationButton {
private:
public:
PagesButton( );
~PagesButton( );
};

View File

@@ -0,0 +1,4 @@
#include "PlaylistButton.h"
PlaylistButton::PlaylistButton( ) { }
PlaylistButton::~PlaylistButton( ) { }

View File

@@ -0,0 +1,11 @@
#pragma once
#include "../NavigationButton.h"
class PlaylistButton : NavigationButton {
private:
public:
PlaylistButton( );
~PlaylistButton( );
};

View File

@@ -0,0 +1,88 @@
#include "PageNavigator.h"
#include "SelectHandler.hpp"
#include "../../Tools/SvgToPixmap.hpp"
class SquareIcon : public QLabel {
public:
QSize sizeHint( ) const override {
QSize hint = QLabel::sizeHint( );
int side = qMin(hint.width( ), hint.height( ));
return QSize(side, side);
}
};
PageNavigator::PageNavigator(QString text, QString icon, QString color, QWidget* parent)
:m_text(new QLabel(text)), m_icon(new SquareIcon( )), m_color(color), m_iconPath(icon) {
QSvgRenderer renderer(icon);
QPixmap pixmap(32, 32);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
renderer.render(&painter, pixmap.rect( ));
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
painter.fillRect(pixmap.rect( ), color);
painter.end( );
m_icon->setPixmap(pixmap);
m_icon->setObjectName("icon");
setObjectName("PageNavigator");
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setStyleSheet(R"(
#PageNavigator{
border: 4px solid #414141;
border-radius: 6px;
color: #E0E0E0;
}
)");
QFont font = m_text->font( );
font.setPointSize(16);
font.setWeight(QFont::Bold);
m_text->setFont(font);
QHBoxLayout* layout = new QHBoxLayout(this);
layout->addWidget(m_icon, 0, Qt::AlignLeft);
layout->addWidget(m_text, 1, Qt::AlignLeft);
connect(this, &QPushButton::clicked, [this, parent]( ) {
SelectHandler* sh = SelectHandler::GetInstance( );
sh->setSelected(this);
emit SelectedChanged(this);
});
// Little hacky but thats how home is the default
if (text == "Home") {
SelectHandler* sh = SelectHandler::GetInstance( );
sh->setSelected(this);
emit SelectedChanged(this);
}
}
void PageNavigator::unselect( ) {
setStyleSheet(R"(
#PageNavigator{
border: 4px solid #414141;
border-radius: 6px;
}
)");
}
void PageNavigator::select( ) {
setStyleSheet(R"(
#PageNavigator{
border: 4px solid )" + m_color + R"(;
border-radius: 6px;
}
)");
}
QString PageNavigator::GetText( ) {
return m_text->text( );
}

View File

@@ -5,16 +5,25 @@
#include <QLayout> #include <QLayout>
#include <QFont> #include <QFont>
#include <QPushButton> #include <QPushButton>
#include <QColor>
#include <QGraphicsColorizeEffect>
class PageNavigator :public QPushButton { class PageNavigator :public QPushButton {
Q_OBJECT Q_OBJECT
private: private:
QLabel* m_text; QLabel* m_text;
QLabel* m_icon; QLabel* m_icon;
QString m_iconPath;
QString m_color;
public: public:
PageNavigator(QString text, QString icon, QWidget* parent = nullptr); PageNavigator(QString text, QString icon, QString color, QWidget* parent = nullptr);
void unselect( ); void unselect( );
void select( ); void select( );
QString GetText( );
signals:
void SelectedChanged(PageNavigator* pn);
}; };

View File

@@ -1,6 +1,5 @@
#pragma once #pragma once
#include <QWidget>
#include "PageNavigator.h" #include "PageNavigator.h"
/* /*
@@ -40,7 +39,7 @@ void SelectHandler::setSelected(PageNavigator* newSelected) {
if (this->selected == nullptr) { if (this->selected == nullptr) {
this->selected = newSelected; this->selected = newSelected;
newSelected->select( ); selected->select( );
return; return;
} }

View File

@@ -0,0 +1,47 @@
#pragma once
#include <iostream>
template<typename T>
class SongHistory {
private:
struct Node {
T data;
Node* next;
};
Node* topNode = nullptr;
public:
SongHistory( ) { }
~SongHistory( ) {
while (!isEmpty( ))
pop( );
}
void push(const T& value) {
Node* newNode = new Node;
newNode->data = value;
newNode->next = topNode;
topNode = newNode;
}
void pop( ) {
if (!isEmpty( )) {
Node* tmp = topNode;
topNode = topNode->next;
delete tmp;
}
else
std::cerr << "Stack empty, cannot pop" << std::endl;
}
T top( ) {
if (!isEmpty( ))
return topNode->data;
else
return nullptr;
}
bool isEmpty( ) const { return topNode == nullptr; }
};

View File

@@ -0,0 +1,186 @@
#include "ConditionalCircularLinkedList.h"
ConditionalCircularLinkedList::ConditionalCircularLinkedList( ) { }
void ConditionalCircularLinkedList::Append(Song* song) {
Node* newNode = new Node(song);
if (head == nullptr) {
head = newNode;
// Only link back when its supposed to
if (isLinked)
head->next = head;
current = head;
}
else {
Node* tmp = head;
while (tmp->next != head)
tmp = tmp->next;
tmp->next = newNode;
// Again make sure to only link when supposed to
if (isLinked)
newNode->next = head;
}
}
void ConditionalCircularLinkedList::SetListMode(bool isLooping) {
if (head == nullptr) {
std::cout << "WARN: List is empty, cannot set mode" << std::endl;
return;
}
Node* tmp = head;
while (tmp->next != head)
tmp = tmp->next;
if (!isLooping)
tmp->next = nullptr;
else
tmp->next = head;
}
void ConditionalCircularLinkedList::Clear( ) {
while (head != nullptr) {
Node* tmp = head;
head = head->next;
delete tmp;
delete current;
}
}
void ConditionalCircularLinkedList::Advance( ) {
if (current != nullptr)
current = current->next;
}
Song* ConditionalCircularLinkedList::GetNext( ) {
if (current != nullptr)
return current->data;
}
void ConditionalCircularLinkedList::AddSongBefore(Song* newSong, Song* addSongBefore) {
if (head == nullptr) return;
Node* newNode = new Node(newSong);
Node* current = head;
Node* prev = nullptr;
do {
if (current->data == addSongBefore) {
if (prev == nullptr) {
newNode->next = head;
head = newNode;
Node* lastNode = head;
while (lastNode->next != head)
lastNode = lastNode->next;
if (isLinked)
lastNode->next = head;
}
else {
prev->next = newNode;
newNode->next = current;
}
return;
}
prev = current;
current = current->next;
} while (current != head);
}
void ConditionalCircularLinkedList::AddSongAfter(Song* newSong, Song* addSongAfter) {
if (head == nullptr) return;
Node* newNode = new Node(newSong);
Node* current = head;
do {
if (current->data == addSongAfter) {
newNode->next = current->next;
current->next = newNode;
return;
}
current = current->next;
} while (current != head);
}
Song* ConditionalCircularLinkedList::RemoveSong(Song* removeSong) {
if (head == nullptr) return nullptr;
Node* current = head;
Node* prev = nullptr;
do {
if (current->data == removeSong) {
if (prev == nullptr) {
head = current->next;
Node* lastNode = head;
while (lastNode->next != current)
lastNode = lastNode->next;
if (isLinked)
lastNode->next = head;
Song* deletedSong = current->data;
delete current;
return deletedSong;
}
else {
prev->next = current->next;
Song* deletedSong = current->data;
delete current;
return deletedSong;
}
}
prev = current;
current = current->next;
} while (current != head);
}
bool ConditionalCircularLinkedList::IsEmpty( ) {
return current == nullptr;
}
void ConditionalCircularLinkedList::Shuffle( ) {
int cnt = 0;
Node* tmp = head;
while (tmp != nullptr) {
cnt++;
tmp = tmp->next;
}
Node** nodes = new Node * [cnt];
tmp = head;
for (int i = 0; i < cnt; i++) {
nodes[i] = tmp;
tmp = tmp->next;
}
for (int i = cnt; i > 0; i--) {
int j = rand( ) % (i + 1);
Node* tmp = nodes[i];
nodes[i] = nodes[j];
nodes[j] = tmp;
}
head = nodes[0];
for (int i = 0; i < cnt - 1; i++)
nodes[i]->next = nodes[i + 1];
nodes[cnt - 1]->next = nullptr;
delete[] nodes;
}

View File

@@ -0,0 +1,72 @@
#pragma once
#include <iostream>
#include "../../song/song.h"
class ConditionalCircularLinkedList {
private:
struct Node {
Node* next;
Song* data;
Node(Song* song) : data(song), next(nullptr) { }
};
Node* head;
// Variable to keep the current position that we seek
Node* current;
// Variable to either link or unlink the list
bool isLinked;
public:
ConditionalCircularLinkedList( );
ConditionalCircularLinkedList(bool isLinked) : head(nullptr), isLinked(isLinked) { }
/**
* @brief Append a new song to the queue
*
* @param song
*/
void Append(Song* song);
/**
* @brief Clear the entire list so its brand spanking new.
*
*/
void Clear( );
/**
* @brief Depending on if the queue is supposed to be looping, this will link
* up the end of the list, with its beginning to its a circular list.
* If its not supposed to loop then we break the link and it will be a normal list.
* @param isLooping Will set the list to circular or normal mode
*/
void SetListMode(bool isLooping);
/**
* @brief Advance the circular list by one, this means setting the "current" pointer
* to the next element
*
*/
void Advance( );
/**
* @brief Get the "current" pointer's data
*
* @return Song*
*/
Song* GetNext( );
void AddSongBefore(Song* newSong, Song* addSongBefore);
void AddSongAfter(Song* newSong, Song* addSongAfter);
Song* RemoveSong(Song* removeSong);
bool IsEmpty( );
void Shuffle( );
};

View File

@@ -0,0 +1,94 @@
#include "SongQueue.h"
SongQueue::SongQueue( ) {
queue = new ConditionalCircularLinkedList( );
// Its never going to be linked, I'm just too lazy to make a new implementation thats almost the same
priorityQueue = new ConditionalCircularLinkedList(false);
}
SongQueue::~SongQueue( ) { }
void SongQueue::PopulateQueue(const std::list<Song*>& songList) {
for (Song* song : songList) {
queue->Append(song);
}
}
void SongQueue::Next( ) {
if (priorityQueue->IsEmpty( )) {
topSong = queue->GetNext( );
queue->Advance( );
return;
}
topSong = priorityQueue->GetNext( );
priorityQueue->Advance( );
}
void SongQueue::JumpToSong(Song* song, bool fromPrioQueue) {
if (fromPrioQueue) {
if (priorityQueue->IsEmpty( ))
return;
while (priorityQueue->GetNext( ) != song) {
priorityQueue->Advance( );
topSong = song;
}
}
if (queue->IsEmpty( ))
return;
while (queue->GetNext( ) != song) {
queue->Advance( );
topSong = song;
}
}
void SongQueue::AddToPriorityQueue(Song* song) {
priorityQueue->Append(song);
}
bool SongQueue::IsEmpty( ) {
return queue->IsEmpty( ) && priorityQueue->IsEmpty( );
}
Song* SongQueue::Top( ) { return topSong; }
void SongQueue::SetTop(Song* song) { topSong = song; }
void SongQueue::RemoveSongFromPriorityQueue(Song* song) {
if (priorityQueue->IsEmpty( ))
return;
priorityQueue->RemoveSong(song);
}
void SongQueue::MoveSongInPriorityQueue(Song* songToMove, Song* otherSong, bool beforeElseAfter) {
if (priorityQueue->IsEmpty( ))
return;
if (beforeElseAfter)
priorityQueue->AddSongBefore(songToMove, otherSong);
else
priorityQueue->AddSongAfter(songToMove, otherSong);
}
void SongQueue::ShufflePlaylist( ) {
//First backup the original list state
queue_original = new ConditionalCircularLinkedList(queue);
queue->Shuffle( );
}
void SongQueue::RestorePlaylist( ) {
if (queue_original == nullptr) return;
queue = new ConditionalCircularLinkedList(queue_original);
}
void SongQueue::LinkQueue(bool link) {
queue->SetListMode(link);
}

View File

@@ -0,0 +1,61 @@
#pragma once
#include <iostream>
#include <list>
#include "../song/song.h"
#include "ConditionalCircularLinkedList/ConditionalCircularLinkedList.h"
class SongQueue {
private:
// The currently playing song
Song* topSong;
//Regular song queue, can be unlinked for non looping playlists
ConditionalCircularLinkedList* queue;
//Copy of queue to faster restore when unshuffling
ConditionalCircularLinkedList* queue_original;
//The name is confusing, but its because the queue itself has priority over the normal one
ConditionalCircularLinkedList* priorityQueue;
void setQueue( );
public:
SongQueue( );
~SongQueue( );
void PopulateQueue(const std::list<Song*>& songlist);
/**
* @brief Will put the next song from the correct sublist as the topSong.
* This will also remove the song from the queue as its not needed anymore.
*
*/
void Next( );
/**
* @brief Will put the given song from the priority or normal queue as the top song and remove it
* from the list
*
* @param song
*/
void JumpToSong(Song* song, bool fromPrioQueue);
void AddToPriorityQueue(Song* song);
bool IsEmpty( );
Song* Top( );
void SetTop(Song* song);
void RemoveSongFromPriorityQueue(Song* song);
void MoveSongInPriorityQueue(Song* songToMove, Song* otherSong, bool beforeElseAfter);
void ShufflePlaylist( );
void RestorePlaylist( );
void LinkQueue(bool link);
};

View File

@@ -1,6 +1,6 @@
#include "audio.h" #include "audio.h"
Audio::Audio(const std::string path) :path(path) { Audio::Audio( ) {
if (SDL_Init(SDL_INIT_AUDIO) < 0) { if (SDL_Init(SDL_INIT_AUDIO) < 0) {
std::cerr << "SDL initialization failed: " << SDL_GetError( ) << std::endl; std::cerr << "SDL initialization failed: " << SDL_GetError( ) << std::endl;
return; return;
@@ -11,14 +11,6 @@ Audio::Audio(const std::string path) :path(path) {
SDL_Quit( ); SDL_Quit( );
return; return;
} }
music = Mix_LoadMUS(path.c_str( ));
if (!music) {
std::cerr << "Failed to load MP3 file: " << Mix_GetError( ) << std::endl;
Mix_CloseAudio( );
SDL_Quit( );
return;
}
}; };
Audio::~Audio( ) { Audio::~Audio( ) {
@@ -34,6 +26,22 @@ void Audio::StartMusic( ) {
} }
} }
void Audio::StopMusic( ) {
Mix_HaltMusic( );
}
void Audio::PlaySong(const std::string path) {
this->path = path;
music = Mix_LoadMUS(path.c_str( ));
if (!music) {
std::cerr << "Failed to load MP3 file: " << Mix_GetError( ) << std::endl;
Mix_CloseAudio( );
SDL_Quit( );
return;
}
}
void Audio::PauseMusic( ) { void Audio::PauseMusic( ) {
if (Mix_PlayingMusic( ) == 1) { if (Mix_PlayingMusic( ) == 1) {
Mix_PauseMusic( ); Mix_PauseMusic( );

View File

@@ -14,16 +14,16 @@ extern "C" {
class Audio { class Audio {
public: public:
static Audio& getInstance(const std::string path) { static Audio& getInstance( ) {
static Audio instance(path); static Audio instance;
return instance; return instance;
} }
private: private:
Audio(const std::string path); Audio( );
const std::string path; std::string path;
const std::string artist; std::string artist;
const std::string album; std::string album;
Mix_Music* music; Mix_Music* music;
@@ -43,6 +43,9 @@ public:
QPixmap GetAlbumCover( ); QPixmap GetAlbumCover( );
void PlaySong(const std::string path);
void StopMusic( );
void StartMusic( ); void StartMusic( );
void PauseMusic( ); void PauseMusic( );
void ResumeMusic( ); void ResumeMusic( );

36
src/core/song/song.cpp Normal file
View File

@@ -0,0 +1,36 @@
#include "song.h"
Song::Song(
std::string title,
std::string album,
std::string artist,
std::string codec,
std::string comment,
std::string copyright,
std::string publisher,
std::string genre,
std::string encoded_by,
std::string date,
std::string language,
std::string albumCoverPath,
std::string path,
int length,
std::string discoveredPath
) : title(title),
album(album),
artist(artist),
codec(codec),
comment(comment),
copyright(copyright),
publisher(publisher),
genre(genre),
encoded_by(encoded_by),
date(date),
language(language),
albumCoverPath(albumCoverPath),
path(path),
length(length) {
}
Song::~Song( ) { }

54
src/core/song/song.h Normal file
View File

@@ -0,0 +1,54 @@
#pragma once
#include <string>
class Song {
private:
// Song information
const std::string& title;
const std::string& album;
const std::string& artist;
const std::string& codec;
const std::string& comment;
const std::string& copyright;
const std::string& publisher;
const std::string& genre;
const std::string& encoded_by;
const std::string& date;
const std::string& language;
const std::string& albumCoverPath;
const std::string& path;
const int& length;
// Our own Metadata
bool favorite = false;
int playCount = 0;
std::string discovered;
public:
Song(
std::string title,
std::string album,
std::string artist,
std::string codec,
std::string comment,
std::string copyright,
std::string publisher,
std::string genre,
std::string encoded_by,
std::string date,
std::string language,
std::string albumCoverPath,
std::string path,
int length,
std::string discoveredPath
);
~Song( );
void SetFavorite(bool fav) { favorite = fav; }
void IncrementPlayCount( ) { playCount++; }
std::string GetPath( ) { return path; };
};

View File

@@ -1,4 +1,4 @@
#include "Public/MainWindow.h" #include "View/MainWindow.h"
#include <filesystem> #include <filesystem>
#include <QApplication> #include <QApplication>