From 10b6fc637cea22d3190e15dc07bcd123e6f4bbc7 Mon Sep 17 00:00:00 2001 From: Aditya Agrawal Date: Wed, 29 Oct 2025 10:10:35 +0530 Subject: [PATCH] feat: added music player aplication --- Src/Music_Player_Application/Makefile | 31 +++++ .../MusicPlayerApplication.hpp | 94 +++++++++++++++ .../MusicPlayerFacade.hpp | 112 +++++++++++++++++ Src/Music_Player_Application/compile.bat | 17 +++ Src/Music_Player_Application/compile.sh | 15 +++ .../core/AudioEngine.hpp | 55 +++++++++ .../device/BluetoothSpeakerAdapter.hpp | 20 ++++ .../device/HeadphonesAdapter.hpp | 21 ++++ .../device/IAudioOutputDevice.hpp | 8 ++ .../device/WiredSpeakerAdapter.hpp | 20 ++++ .../enums/DeviceType.hpp | 7 ++ .../enums/PlayStrategyType.hpp | 7 ++ .../external/BluetoothSpeakerAPI.hpp | 13 ++ .../external/HeadphonesAPI.hpp | 13 ++ .../external/WiredSpeakerAPI.hpp | 13 ++ .../factories/DeviceFactory.hpp | 22 ++++ .../folderstructure.txt | 41 +++++++ Src/Music_Player_Application/main.cpp | 60 ++++++++++ .../managers/DeviceManager.hpp | 54 +++++++++ .../managers/PlaylistManager.hpp | 43 +++++++ .../managers/StrategyManager.hpp | 40 +++++++ .../models/Playlist.hpp | 32 +++++ Src/Music_Player_Application/models/Song.hpp | 27 +++++ Src/Music_Player_Application/music_player.exe | Bin 0 -> 254608 bytes .../strategies/CustomQueueStrategy.hpp | 113 ++++++++++++++++++ .../strategies/PlayStrategy.hpp | 17 +++ .../strategies/RandomPlayStrategy.hpp | 72 +++++++++++ .../strategies/SequentialPlayStrategy.hpp | 48 ++++++++ 28 files changed, 1015 insertions(+) create mode 100644 Src/Music_Player_Application/Makefile create mode 100644 Src/Music_Player_Application/MusicPlayerApplication.hpp create mode 100644 Src/Music_Player_Application/MusicPlayerFacade.hpp create mode 100644 Src/Music_Player_Application/compile.bat create mode 100644 Src/Music_Player_Application/compile.sh create mode 100644 Src/Music_Player_Application/core/AudioEngine.hpp create mode 100644 Src/Music_Player_Application/device/BluetoothSpeakerAdapter.hpp create mode 100644 Src/Music_Player_Application/device/HeadphonesAdapter.hpp create mode 100644 Src/Music_Player_Application/device/IAudioOutputDevice.hpp create mode 100644 Src/Music_Player_Application/device/WiredSpeakerAdapter.hpp create mode 100644 Src/Music_Player_Application/enums/DeviceType.hpp create mode 100644 Src/Music_Player_Application/enums/PlayStrategyType.hpp create mode 100644 Src/Music_Player_Application/external/BluetoothSpeakerAPI.hpp create mode 100644 Src/Music_Player_Application/external/HeadphonesAPI.hpp create mode 100644 Src/Music_Player_Application/external/WiredSpeakerAPI.hpp create mode 100644 Src/Music_Player_Application/factories/DeviceFactory.hpp create mode 100644 Src/Music_Player_Application/folderstructure.txt create mode 100644 Src/Music_Player_Application/main.cpp create mode 100644 Src/Music_Player_Application/managers/DeviceManager.hpp create mode 100644 Src/Music_Player_Application/managers/PlaylistManager.hpp create mode 100644 Src/Music_Player_Application/managers/StrategyManager.hpp create mode 100644 Src/Music_Player_Application/models/Playlist.hpp create mode 100644 Src/Music_Player_Application/models/Song.hpp create mode 100644 Src/Music_Player_Application/music_player.exe create mode 100644 Src/Music_Player_Application/strategies/CustomQueueStrategy.hpp create mode 100644 Src/Music_Player_Application/strategies/PlayStrategy.hpp create mode 100644 Src/Music_Player_Application/strategies/RandomPlayStrategy.hpp create mode 100644 Src/Music_Player_Application/strategies/SequentialPlayStrategy.hpp diff --git a/Src/Music_Player_Application/Makefile b/Src/Music_Player_Application/Makefile new file mode 100644 index 0000000..787e555 --- /dev/null +++ b/Src/Music_Player_Application/Makefile @@ -0,0 +1,31 @@ +# Makefile for Lecture 18 C++ Music Player System + +CXX = g++ +CXXFLAGS = -std=c++11 -Wall -Wextra +TARGET = music_player +SOURCE = main.cpp + +# Default target +all: $(TARGET) + +# Build the executable +$(TARGET): $(SOURCE) + $(CXX) $(CXXFLAGS) -I. -o $(TARGET) $(SOURCE) + +# Run the application +run: $(TARGET) + ./$(TARGET) + +# Clean up compiled files +clean: + rm -f $(TARGET) $(TARGET).exe + +# Help target +help: + @echo "Available targets:" + @echo " all - Build the application (default)" + @echo " run - Build and run the application" + @echo " clean - Remove compiled files" + @echo " help - Show this help message" + +.PHONY: all run clean help diff --git a/Src/Music_Player_Application/MusicPlayerApplication.hpp b/Src/Music_Player_Application/MusicPlayerApplication.hpp new file mode 100644 index 0000000..56a6896 --- /dev/null +++ b/Src/Music_Player_Application/MusicPlayerApplication.hpp @@ -0,0 +1,94 @@ +#pragma once +#include "managers/PlaylistManager.hpp" +#include "MusicPlayerFacade.hpp" + +using namespace std; + +class MusicPlayerApplication { +private: + static MusicPlayerApplication* instance; + vector songLibrary; + MusicPlayerApplication() {} + +public: + static MusicPlayerApplication* getInstance() { + if (!instance) { + instance = new MusicPlayerApplication(); + } + return instance; + } + + void createSongInLibrary(const string& title, const string& artist, + const string& path) { + Song* newSong = new Song(title, artist, path); + songLibrary.push_back(newSong); + } + + Song* findSongByTitle(const string& title) { + for (Song* s : songLibrary) { + if (s->getTitle() == title) { + return s; + } + } + return nullptr; + } + void createPlaylist(const string& playlistName) { + PlaylistManager::getInstance()->createPlaylist(playlistName); + } + + void addSongToPlaylist(const string& playlistName, + const string& songTitle) { + Song* song = findSongByTitle(songTitle); + if (!song) { + throw runtime_error("Song \"" + songTitle + "\" not found in library."); + } + PlaylistManager::getInstance() + ->addSongToPlaylist(playlistName, song); + } + + void connectAudioDevice(DeviceType deviceType) { + MusicPlayerFacade::getInstance()->connectDevice(deviceType); + } + + void selectPlayStrategy(PlayStrategyType strategyType) { + MusicPlayerFacade::getInstance()->setPlayStrategy(strategyType); + } + + void loadPlaylist(const string& playlistName) { + MusicPlayerFacade::getInstance()->loadPlaylist(playlistName); + } + + void playSingleSong(const string& songTitle) { + Song* song = findSongByTitle(songTitle); + if (!song) { + throw runtime_error("Song \"" + songTitle + "\" not found."); + } + MusicPlayerFacade::getInstance()->playSong(song); + } + + void pauseCurrentSong(const string& songTitle) { + Song* song = findSongByTitle(songTitle); + if (!song) { + throw runtime_error("Song \"" + songTitle + "\" not found."); + } + MusicPlayerFacade::getInstance()->pauseSong(song); + } + + void playAllTracksInPlaylist() { + MusicPlayerFacade::getInstance()->playAllTracks(); + } + + void playPreviousTrackInPlaylist() { + MusicPlayerFacade::getInstance()->playPreviousTrack(); + } + + void queueSongNext(const string& songTitle) { + Song* song = findSongByTitle(songTitle); + if (!song) { + throw runtime_error("Song \"" + songTitle + "\" not found."); + } + MusicPlayerFacade::getInstance()->enqueueNext(song); + } +}; + +MusicPlayerApplication* MusicPlayerApplication::instance = nullptr; \ No newline at end of file diff --git a/Src/Music_Player_Application/MusicPlayerFacade.hpp b/Src/Music_Player_Application/MusicPlayerFacade.hpp new file mode 100644 index 0000000..f144da5 --- /dev/null +++ b/Src/Music_Player_Application/MusicPlayerFacade.hpp @@ -0,0 +1,112 @@ +#pragma once +#include "core/AudioEngine.hpp" +#include "models/Playlist.hpp" +#include "models/Song.hpp" +#include "strategies/PlayStrategy.hpp" +#include "enums/DeviceType.hpp" +#include "enums/PlayStrategyType.hpp" +#include "managers/DeviceManager.hpp" +#include "managers/PlaylistManager.hpp" +#include "managers/StrategyManager.hpp" + +using namespace std; + +class MusicPlayerFacade { +private: + static MusicPlayerFacade* instance; + AudioEngine* audioEngine; + Playlist* loadedPlaylist; + PlayStrategy* playStrategy; + + MusicPlayerFacade() { + loadedPlaylist = nullptr; + playStrategy = nullptr; + audioEngine = new AudioEngine(); + } + +public: + static MusicPlayerFacade* getInstance() { + if (!instance) { + instance = new MusicPlayerFacade(); + } + return instance; + } + + void connectDevice(DeviceType deviceType) { + DeviceManager::getInstance()->connect(deviceType); + } + + void setPlayStrategy(PlayStrategyType strategyType) { + playStrategy = StrategyManager::getInstance()->getStrategy(strategyType); + } + + void loadPlaylist(const string& name) { + loadedPlaylist = PlaylistManager::getInstance()->getPlaylist(name); + if (!playStrategy) { + throw runtime_error("Play strategy not set before loading."); + } + playStrategy->setPlaylist(loadedPlaylist); + } + + void playSong(Song* song) { + if (!DeviceManager::getInstance()->hasOutputDevice()) { + throw runtime_error("No audio device connected."); + } + IAudioOutputDevice* device = DeviceManager::getInstance()->getOutputDevice(); + audioEngine->play(device, song); + } + + void pauseSong(Song* song) { + if (audioEngine->getCurrentSongTitle() != song->getTitle()) { + throw runtime_error("Cannot pause \"" + song->getTitle() + "\"; not currently playing."); + } + audioEngine->pause(); + } + + void playAllTracks() { + if (!loadedPlaylist) { + throw runtime_error("No playlist loaded."); + } + while (playStrategy->hasNext()) { + Song* nextSong = playStrategy->next(); + IAudioOutputDevice* device = DeviceManager::getInstance()->getOutputDevice(); + audioEngine->play(device, nextSong); + } + cout << "Completed playlist: " << loadedPlaylist->getPlaylistName() << "\n"; + } + + void playNextTrack() { + if (!loadedPlaylist) { + throw runtime_error("No playlist loaded."); + } + if(playStrategy->hasNext()) { + Song* nextSong = playStrategy->next(); + IAudioOutputDevice* device = DeviceManager::getInstance()->getOutputDevice(); + audioEngine->play(device, nextSong); + } + else { + cout << "Completed playlist: " << loadedPlaylist->getPlaylistName() << "\n"; + } + } + + void playPreviousTrack() { + if (!loadedPlaylist) { + throw runtime_error("No playlist loaded."); + } + if(playStrategy->hasPrevious()) { + Song* prevSong = playStrategy->previous(); + IAudioOutputDevice* device = DeviceManager::getInstance()->getOutputDevice(); + audioEngine->play(device, prevSong); + } + else { + cout << "Completed playlist: " << loadedPlaylist->getPlaylistName() << "\n"; + } + } + + void enqueueNext(Song* song) { + playStrategy->addToNext(song); + } +}; + +MusicPlayerFacade* MusicPlayerFacade::instance = nullptr; + \ No newline at end of file diff --git a/Src/Music_Player_Application/compile.bat b/Src/Music_Player_Application/compile.bat new file mode 100644 index 0000000..ab91e5c --- /dev/null +++ b/Src/Music_Player_Application/compile.bat @@ -0,0 +1,17 @@ +@echo off +echo Compiling C++ Music Player System... + +REM Compile the main program +g++ -std=c++11 -I. -o music_player main.cpp + +if %errorlevel% equ 0 ( + echo Compilation successful! + echo Running the Music Player application... + echo. + music_player.exe +) else ( + echo Compilation failed! + echo Please check for any syntax errors. +) + +pause diff --git a/Src/Music_Player_Application/compile.sh b/Src/Music_Player_Application/compile.sh new file mode 100644 index 0000000..2a2aae2 --- /dev/null +++ b/Src/Music_Player_Application/compile.sh @@ -0,0 +1,15 @@ +#!/bin/bash +echo "Compiling Lecture 18 C++ Music Player System..." + +# Compile the main program +g++ -std=c++11 -I. -o music_player main.cpp + +if [ $? -eq 0 ]; then + echo "Compilation successful!" + echo "Running the Music Player application..." + echo + ./music_player +else + echo "Compilation failed!" + echo "Please check for any syntax errors." +fi diff --git a/Src/Music_Player_Application/core/AudioEngine.hpp b/Src/Music_Player_Application/core/AudioEngine.hpp new file mode 100644 index 0000000..c967633 --- /dev/null +++ b/Src/Music_Player_Application/core/AudioEngine.hpp @@ -0,0 +1,55 @@ +#pragma once +#include "../models/Song.hpp" +#include "../device/IAudioOutputDevice.hpp" +#include +#include + +using namespace std; + +class AudioEngine { +private: + Song* currentSong; + bool songIsPaused; +public: + AudioEngine() { + currentSong = nullptr; + songIsPaused = false; + } + string getCurrentSongTitle() const { + if (currentSong) { + return currentSong->getTitle(); + } + return ""; + } + bool isPaused() const { + return songIsPaused; + } + void play(IAudioOutputDevice* aod, Song* song) { + if (song == nullptr) { + throw runtime_error("Cannot play a null song."); + } + // Resume if same song was paused + if (songIsPaused && song == currentSong) { + songIsPaused = false; + cout << "Resuming song: " << song->getTitle() << "\n"; + aod->playAudio(song); + return; + } + + currentSong = song; + songIsPaused = false; + cout << "Playing song: " << song->getTitle() << "\n"; + aod->playAudio(song); + } + + void pause() { + if (currentSong == nullptr) { + throw runtime_error("No song is currently playing to pause."); + } + if (songIsPaused) { + throw runtime_error("Song is already paused."); + } + songIsPaused = true; + cout << "Pausing song: " << currentSong->getTitle() << "\n"; + } +}; \ No newline at end of file diff --git a/Src/Music_Player_Application/device/BluetoothSpeakerAdapter.hpp b/Src/Music_Player_Application/device/BluetoothSpeakerAdapter.hpp new file mode 100644 index 0000000..5879545 --- /dev/null +++ b/Src/Music_Player_Application/device/BluetoothSpeakerAdapter.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "../models/Song.hpp" +#include "IAudioOutputDevice.hpp" +#include "../external/BluetoothSpeakerAPI.hpp" + +using namespace std; + +class BluetoothSpeakerAdapter : public IAudioOutputDevice { +private: + BluetoothSpeakerAPI* bluetoothApi; +public: + BluetoothSpeakerAdapter(BluetoothSpeakerAPI* api) { + bluetoothApi = api; + } + + void playAudio(Song* song) override { + string payload = song->getTitle() + " by " + song->getArtist(); + bluetoothApi->playSoundViaBluetooth(payload); + } +}; \ No newline at end of file diff --git a/Src/Music_Player_Application/device/HeadphonesAdapter.hpp b/Src/Music_Player_Application/device/HeadphonesAdapter.hpp new file mode 100644 index 0000000..cdaaf1c --- /dev/null +++ b/Src/Music_Player_Application/device/HeadphonesAdapter.hpp @@ -0,0 +1,21 @@ +#pragma once +#include "../models/Song.hpp" +#include "IAudioOutputDevice.hpp" +#include "../external/HeadphonesAPI.hpp" + +using namespace std; + +class HeadphonesAdapter : public IAudioOutputDevice { +private: + HeadphonesAPI* headphonesApi; +public: + HeadphonesAdapter(HeadphonesAPI* api) { + headphonesApi = api; + } + + void playAudio(Song* song) override { + string payload = song->getTitle() + " by " + song->getArtist(); + headphonesApi->playSoundViaJack(payload); + } +}; + diff --git a/Src/Music_Player_Application/device/IAudioOutputDevice.hpp b/Src/Music_Player_Application/device/IAudioOutputDevice.hpp new file mode 100644 index 0000000..7b94c0d --- /dev/null +++ b/Src/Music_Player_Application/device/IAudioOutputDevice.hpp @@ -0,0 +1,8 @@ +#pragma once +#include "../models/Song.hpp" + +class IAudioOutputDevice { +public: + virtual ~IAudioOutputDevice() {} + virtual void playAudio(Song* song) = 0; +}; \ No newline at end of file diff --git a/Src/Music_Player_Application/device/WiredSpeakerAdapter.hpp b/Src/Music_Player_Application/device/WiredSpeakerAdapter.hpp new file mode 100644 index 0000000..b486488 --- /dev/null +++ b/Src/Music_Player_Application/device/WiredSpeakerAdapter.hpp @@ -0,0 +1,20 @@ +#pragma once +#include "../models/Song.hpp" +#include "IAudioOutputDevice.hpp" +#include "../external/WiredSpeakerAPI.hpp" + +using namespace std; + +class WiredSpeakerAdapter : public IAudioOutputDevice { +private: + WiredSpeakerAPI* wiredApi; +public: + WiredSpeakerAdapter(WiredSpeakerAPI* api) { + wiredApi = api; + } + + void playAudio(Song* song) override { + string payload = song->getTitle() + " by " + song->getArtist(); + wiredApi->playSoundViaCable(payload); + } +}; \ No newline at end of file diff --git a/Src/Music_Player_Application/enums/DeviceType.hpp b/Src/Music_Player_Application/enums/DeviceType.hpp new file mode 100644 index 0000000..614654a --- /dev/null +++ b/Src/Music_Player_Application/enums/DeviceType.hpp @@ -0,0 +1,7 @@ +#pragma once + +enum class DeviceType { + BLUETOOTH, + WIRED, + HEADPHONES +}; \ No newline at end of file diff --git a/Src/Music_Player_Application/enums/PlayStrategyType.hpp b/Src/Music_Player_Application/enums/PlayStrategyType.hpp new file mode 100644 index 0000000..ab2780a --- /dev/null +++ b/Src/Music_Player_Application/enums/PlayStrategyType.hpp @@ -0,0 +1,7 @@ +#pragma once + +enum class PlayStrategyType { + SEQUENTIAL, + RANDOM, + CUSTOM_QUEUE +}; \ No newline at end of file diff --git a/Src/Music_Player_Application/external/BluetoothSpeakerAPI.hpp b/Src/Music_Player_Application/external/BluetoothSpeakerAPI.hpp new file mode 100644 index 0000000..58c03d9 --- /dev/null +++ b/Src/Music_Player_Application/external/BluetoothSpeakerAPI.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include + +using namespace std; + +class BluetoothSpeakerAPI { +public: + void playSoundViaBluetooth(const string& data) { + cout << "[BluetoothSpeaker] Playing: " << data << "\n"; + // mimics playing music + } +}; \ No newline at end of file diff --git a/Src/Music_Player_Application/external/HeadphonesAPI.hpp b/Src/Music_Player_Application/external/HeadphonesAPI.hpp new file mode 100644 index 0000000..1220821 --- /dev/null +++ b/Src/Music_Player_Application/external/HeadphonesAPI.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include + +using namespace std; + +class HeadphonesAPI { +public: + void playSoundViaJack(const string& data) { + cout << "[Headphones] Playing: " << data << "\n"; + // mimics playing music + } +}; \ No newline at end of file diff --git a/Src/Music_Player_Application/external/WiredSpeakerAPI.hpp b/Src/Music_Player_Application/external/WiredSpeakerAPI.hpp new file mode 100644 index 0000000..c7b4efe --- /dev/null +++ b/Src/Music_Player_Application/external/WiredSpeakerAPI.hpp @@ -0,0 +1,13 @@ +#pragma once +#include +#include + +using namespace std; + +class WiredSpeakerAPI { +public: + void playSoundViaCable(const string& data) { + cout << "[WiredSpeaker] Playing: " << data << "\n"; + // mimics playing music + } +}; \ No newline at end of file diff --git a/Src/Music_Player_Application/factories/DeviceFactory.hpp b/Src/Music_Player_Application/factories/DeviceFactory.hpp new file mode 100644 index 0000000..6d4d01a --- /dev/null +++ b/Src/Music_Player_Application/factories/DeviceFactory.hpp @@ -0,0 +1,22 @@ +#pragma once +#include +#include "../device/IAudioOutputDevice.hpp" +#include "../device/BluetoothSpeakerAdapter.hpp" +#include "../device/WiredSpeakerAdapter.hpp" +#include "../device/HeadphonesAdapter.hpp" +#include "../enums/DeviceType.hpp" + +using namespace std; + +class DeviceFactory { +public: + static IAudioOutputDevice* createDevice(DeviceType deviceType) { + if (deviceType == DeviceType::BLUETOOTH) { + return new BluetoothSpeakerAdapter(new BluetoothSpeakerAPI()); + } else if (deviceType == DeviceType::WIRED) { + return new WiredSpeakerAdapter(new WiredSpeakerAPI()); + } else { // HEADPHONES + return new HeadphonesAdapter(new HeadphonesAPI()); + } + } +}; \ No newline at end of file diff --git a/Src/Music_Player_Application/folderstructure.txt b/Src/Music_Player_Application/folderstructure.txt new file mode 100644 index 0000000..eaa9dc6 --- /dev/null +++ b/Src/Music_Player_Application/folderstructure.txt @@ -0,0 +1,41 @@ +MusicPlayerApp/ +│ +├── main.cpp # Composition root and entry point +├── MusicPlayerFacade.hpp # Facade class (orchestrator) +├── MusicPlayerApplication.hpp # High-level application/demo runner +│ +├── core/ +│ └── AudioEngine.hpp # Playback engine +│ +├── enums/ # All shared enum types +│ ├── DeviceType.hpp # enum class DeviceType { BLUETOOTH, WIRED, HEADPHONES } +│ └── PlayStrategyType.hpp # enum class PlayStrategyType { SEQUENTIAL, RANDOM, CUSTOM_QUEUE } +│ +├── models/ +│ ├── Song.hpp +│ └── Playlist.hpp +│ +├── managers/ +│ ├── PlaylistManager.hpp +│ ├── DeviceManager.hpp +| └── StrategyManager.hpp +│ +├── strategies/ +│ ├── PlayStrategy.hpp +│ ├── SequentialPlayStrategy.hpp +│ ├── RandomPlayStrategy.hpp +│ └── CustomQueueStrategy.hpp +│ +├── device/ # Audio device interfaces & adapters +│ ├── IAudioOutputDevice.hpp +│ ├── BluetoothSpeakerAdapter.hpp +│ ├── WiredSpeakerAdapter.hpp +│ └── HeadphonesAdapter.hpp +| +├── external/ # External devices +│ ├── BluetoothSpeakerAPI.hpp +│ ├── HeadphonesAPI.hpp +│ └── WiredSpeakerAPI.hpp +│ +└── factories/ + └── DeviceFactory.hpp # Creates IAudioOutputDevice instances diff --git a/Src/Music_Player_Application/main.cpp b/Src/Music_Player_Application/main.cpp new file mode 100644 index 0000000..2580613 --- /dev/null +++ b/Src/Music_Player_Application/main.cpp @@ -0,0 +1,60 @@ +#include "MusicPlayerApplication.hpp" + +using namespace std; + +int main() { + try { + auto application = MusicPlayerApplication::getInstance(); + + // Populate library + application->createSongInLibrary("Kesariya", "Arijit Singh", "/music/kesariya.mp3"); + application->createSongInLibrary("Chaiyya Chaiyya", "Sukhwinder Singh", "/music/chaiyya_chaiyya.mp3"); + application->createSongInLibrary("Tum Hi Ho", "Arijit Singh", "/music/tum_hi_ho.mp3"); + application->createSongInLibrary("Jai Ho", "A. R. Rahman", "/music/jai_ho.mp3"); + application->createSongInLibrary("Zinda", "Siddharth Mahadevan", "/music/zinda.mp3"); + + // Create playlist and add songs + application->createPlaylist("Bollywood Vibes"); + application->addSongToPlaylist("Bollywood Vibes", "Kesariya"); + application->addSongToPlaylist("Bollywood Vibes", "Chaiyya Chaiyya"); + application->addSongToPlaylist("Bollywood Vibes", "Tum Hi Ho"); + application->addSongToPlaylist("Bollywood Vibes", "Jai Ho"); + + // Connect device + application->connectAudioDevice(DeviceType::BLUETOOTH); + + //Play/pause a single song + application->playSingleSong("Zinda"); + application->pauseCurrentSong("Zinda"); + application->playSingleSong("Zinda"); // resume + + cout << "\n-- Sequential Playback --\n"; + application->selectPlayStrategy(PlayStrategyType::SEQUENTIAL); + application->loadPlaylist("Bollywood Vibes"); + application->playAllTracksInPlaylist(); + + cout << "\n-- Random Playback --\n"; + application->selectPlayStrategy(PlayStrategyType::RANDOM); + application->loadPlaylist("Bollywood Vibes"); + application->playAllTracksInPlaylist(); + + cout << "\n-- Custom Queue Playback --\n"; + application->selectPlayStrategy(PlayStrategyType::CUSTOM_QUEUE); + application->loadPlaylist("Bollywood Vibes"); + application->queueSongNext("Kesariya"); + application->queueSongNext("Tum Hi Ho"); + application->playAllTracksInPlaylist(); + + cout << "\n-- Play Previous in Sequential --\n"; + application->selectPlayStrategy(PlayStrategyType::SEQUENTIAL); + application->loadPlaylist("Bollywood Vibes"); + application->playAllTracksInPlaylist(); + + application->playPreviousTrackInPlaylist(); + application->playPreviousTrackInPlaylist(); + + } catch (const exception& error) { + cerr << "Error: " << error.what() << endl; + } + return 0; +} \ No newline at end of file diff --git a/Src/Music_Player_Application/managers/DeviceManager.hpp b/Src/Music_Player_Application/managers/DeviceManager.hpp new file mode 100644 index 0000000..fa94699 --- /dev/null +++ b/Src/Music_Player_Application/managers/DeviceManager.hpp @@ -0,0 +1,54 @@ +#pragma once +#include +#include "../device/IAudioOutputDevice.hpp" +#include "../enums/DeviceType.hpp" +#include "../factories/DeviceFactory.hpp" + +using namespace std; + +class DeviceManager { +private: + static DeviceManager* instance; + IAudioOutputDevice* currentOutputDevice; + DeviceManager() { + currentOutputDevice = nullptr; + } +public: + static DeviceManager* getInstance() { + if (instance == nullptr) { + instance = new DeviceManager(); + } + return instance; + } + void connect(DeviceType deviceType) { + if (currentOutputDevice) { + delete currentOutputDevice; + } + + currentOutputDevice = DeviceFactory::createDevice(deviceType); + + switch(deviceType) { + case DeviceType::BLUETOOTH: + cout<< "Bluetooth device connected \n"; + break; + case DeviceType::WIRED: + cout<< "Wired device connected \n"; + break; + case DeviceType::HEADPHONES: + cout<< "Headphones connected \n"; + } + } + + IAudioOutputDevice* getOutputDevice() { + if (!currentOutputDevice) { + throw runtime_error("No output device is connected."); + } + return currentOutputDevice; + } + + bool hasOutputDevice() { + return currentOutputDevice != nullptr; + } +}; + +DeviceManager* DeviceManager::instance = nullptr; \ No newline at end of file diff --git a/Src/Music_Player_Application/managers/PlaylistManager.hpp b/Src/Music_Player_Application/managers/PlaylistManager.hpp new file mode 100644 index 0000000..1f25df7 --- /dev/null +++ b/Src/Music_Player_Application/managers/PlaylistManager.hpp @@ -0,0 +1,43 @@ +#pragma once +#include "../models/Playlist.hpp" +#include +#include +#include + +using namespace std; + +class PlaylistManager { +private: + static PlaylistManager* instance; + map playlists; + PlaylistManager() {} +public: + static PlaylistManager* getInstance() { + if (!instance) { + instance = new PlaylistManager(); + } + return instance; + } + + void createPlaylist(const string& name) { + if (playlists.count(name)) { + throw runtime_error("Playlist \"" + name + "\" already exists."); + } + playlists[name] = new Playlist(name); + } + + void addSongToPlaylist(const string& playlistName, Song* song) { + if (!playlists.count(playlistName)) { + throw runtime_error("Playlist \"" + playlistName + "\" not found."); + } + playlists[playlistName]->addSongToPlaylist(song); + } + + Playlist* getPlaylist(const string& name) { + if (!playlists.count(name)) { + throw runtime_error("Playlist \"" + name + "\" not found."); + } + return playlists[name]; + } +}; +PlaylistManager* PlaylistManager::instance = nullptr; \ No newline at end of file diff --git a/Src/Music_Player_Application/managers/StrategyManager.hpp b/Src/Music_Player_Application/managers/StrategyManager.hpp new file mode 100644 index 0000000..c972ad0 --- /dev/null +++ b/Src/Music_Player_Application/managers/StrategyManager.hpp @@ -0,0 +1,40 @@ +#pragma once +#include +#include "../strategies/SequentialPlayStrategy.hpp" +#include "../strategies/CustomQueueStrategy.hpp" +#include "../strategies/RandomPlayStrategy.hpp" +#include "../enums/PlayStrategyType.hpp" + +using namespace std; + +class StrategyManager { +private: + static StrategyManager* instance; + SequentialPlayStrategy* sequentialStrategy; + RandomPlayStrategy* randomStrategy; + CustomQueueStrategy* customQueueStrategy; + + StrategyManager() { + sequentialStrategy = new SequentialPlayStrategy(); + randomStrategy = new RandomPlayStrategy(); + customQueueStrategy = new CustomQueueStrategy(); + } +public: + static StrategyManager* getInstance() { + if (!instance) { + instance = new StrategyManager(); + } + return instance; + } + PlayStrategy* getStrategy(PlayStrategyType type) { + if (type == PlayStrategyType::SEQUENTIAL) { + return sequentialStrategy; + } else if (type == PlayStrategyType::RANDOM) { + return randomStrategy; + } else { + return customQueueStrategy; + } + } +}; + +StrategyManager* StrategyManager::instance = nullptr; \ No newline at end of file diff --git a/Src/Music_Player_Application/models/Playlist.hpp b/Src/Music_Player_Application/models/Playlist.hpp new file mode 100644 index 0000000..b1e1225 --- /dev/null +++ b/Src/Music_Player_Application/models/Playlist.hpp @@ -0,0 +1,32 @@ +#pragma once +#include +#include +#include +#include "Song.hpp" + +using namespace std; + +class Playlist { +private: + string playlistName; + vector songList; +public: + Playlist(string name) { + playlistName = name; + } + string getPlaylistName() { + return playlistName; + } + const vector getSongs() { + return songList; + } + int getSize() { + return (int)songList.size(); + } + void addSongToPlaylist(Song* song) { + if (song == nullptr) { + throw runtime_error("Cannot add null song to playlist."); + } + songList.push_back(song); + } +}; \ No newline at end of file diff --git a/Src/Music_Player_Application/models/Song.hpp b/Src/Music_Player_Application/models/Song.hpp new file mode 100644 index 0000000..6b546ef --- /dev/null +++ b/Src/Music_Player_Application/models/Song.hpp @@ -0,0 +1,27 @@ +#pragma once +#include +#include + +using namespace std; + +class Song { +private: + string title; + string artist; + string filePath; +public: + Song(string t, string a, string f) { + title = t; + artist = a; + filePath = f; + } + string getTitle() { + return title; + } + string getArtist() { + return artist; + } + string getFilePath() { + return filePath; + } +}; \ No newline at end of file diff --git a/Src/Music_Player_Application/music_player.exe b/Src/Music_Player_Application/music_player.exe new file mode 100644 index 0000000000000000000000000000000000000000..29347a79b87318f366f0079085447907c502e9b6 GIT binary patch literal 254608 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 +#include +#include +#include +#include +#include "../models/Playlist.hpp" +#include "PlayStrategy.hpp" + +class CustomQueueStrategy : public PlayStrategy { +private: + Playlist* currentPlaylist; + int currentIndex; + queue nextQueue; + stack prevStack; + + Song* nextSequential() { + if (currentPlaylist->getSize() == 0) { + throw runtime_error("Playlist is empty."); + } + currentIndex = currentIndex + 1; + return currentPlaylist->getSongs()[currentIndex]; + } + + Song* previousSequential() { + if (currentPlaylist->getSize() == 0) { + throw runtime_error("Playlist is empty."); + } + currentIndex = currentIndex - 1; + return currentPlaylist->getSongs()[currentIndex]; + } + +public: + CustomQueueStrategy() { + currentPlaylist = nullptr; + currentIndex = -1; + } + + void setPlaylist(Playlist* playlist) override { + currentPlaylist = playlist; + currentIndex = -1; + while (!nextQueue.empty()) { + nextQueue.pop(); + } + while(!prevStack.empty()) { + prevStack.pop(); + } + } + + bool hasNext() override { + return ((currentIndex + 1) < currentPlaylist->getSize()); + } + + Song* next() override { + if (!currentPlaylist || currentPlaylist->getSize() == 0) { + throw runtime_error("No playlist loaded or playlist is empty."); + } + + if (!nextQueue.empty()) { + Song* s = nextQueue.front(); + nextQueue.pop(); + prevStack.push(s); + + // update index to match queued song + auto& list = currentPlaylist->getSongs(); + for (int i = 0; i < (int)list.size(); ++i) { + if (list[i] == s) { + currentIndex = i; + break; + } + } + return s; + } + + // Otherwise sequential + return nextSequential(); + } + + bool hasPrevious() override { + return (currentIndex - 1 > 0); + } + + Song* previous() override { + if (!currentPlaylist || currentPlaylist->getSize() == 0) { + throw runtime_error("No playlist loaded or playlist is empty."); + } + + if (!prevStack.empty()) { + Song* s = prevStack.top(); + prevStack.pop(); + + // update index to match stacked song + auto& list = currentPlaylist->getSongs(); + for (int i = 0; i < (int)list.size(); ++i) { + if (list[i] == s) { + currentIndex = i; + break; + } + } + return s; + } + + // Otherwise sequential + return previousSequential(); + } + + void addToNext(Song* song) override { + if (!song) { + throw runtime_error("Cannot enqueue null song."); + } + nextQueue.push(song); + } +}; \ No newline at end of file diff --git a/Src/Music_Player_Application/strategies/PlayStrategy.hpp b/Src/Music_Player_Application/strategies/PlayStrategy.hpp new file mode 100644 index 0000000..3d09455 --- /dev/null +++ b/Src/Music_Player_Application/strategies/PlayStrategy.hpp @@ -0,0 +1,17 @@ +#pragma once +#include +#include "../models/Song.hpp" +#include "../models/Playlist.hpp" + +using namespace std; + +class PlayStrategy { +public: + virtual ~PlayStrategy() {} + virtual void setPlaylist(Playlist* playlist) = 0; + virtual Song* next() = 0; + virtual bool hasNext() = 0; + virtual Song* previous() = 0; + virtual bool hasPrevious() = 0; + virtual void addToNext(Song* song) {} +}; \ No newline at end of file diff --git a/Src/Music_Player_Application/strategies/RandomPlayStrategy.hpp b/Src/Music_Player_Application/strategies/RandomPlayStrategy.hpp new file mode 100644 index 0000000..b3d5314 --- /dev/null +++ b/Src/Music_Player_Application/strategies/RandomPlayStrategy.hpp @@ -0,0 +1,72 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include "../models/Playlist.hpp" +#include "PlayStrategy.hpp" + +using namespace std; + +class RandomPlayStrategy : public PlayStrategy { +private: + Playlist* currentPlaylist; + vector remainingSongs; + stack history; + +public: + RandomPlayStrategy() { + currentPlaylist = nullptr; + srand((unsigned)time(nullptr)); + } + + void setPlaylist(Playlist* playlist) override { + currentPlaylist = playlist; + if (!currentPlaylist || currentPlaylist->getSize() == 0) return; + + remainingSongs = currentPlaylist->getSongs(); + history = stack(); + } + + bool hasNext() override { + return currentPlaylist && !remainingSongs.empty(); + } + + // Next in Loop + Song* next() override { + if (!currentPlaylist || currentPlaylist->getSize() == 0) { + throw runtime_error("No playlist loaded or playlist is empty."); + } + if (remainingSongs.empty()) { + throw runtime_error("No songs left to play"); + } + + int idx = rand() % remainingSongs.size(); + Song* selectedSong = remainingSongs[idx]; + + // Remove the selectedSong from the list. (Swap and pop to remove in O(1)) + swap(remainingSongs[idx], remainingSongs.back()); + remainingSongs.pop_back(); + + history.push(selectedSong); + return selectedSong; + } + + bool hasPrevious() override { + return history.size() > 0; + } + + Song* previous() override { + if (history.empty()) { + throw std::runtime_error("No previous song available."); + } + + Song* song = history.top(); + history.pop(); + return song; + } +}; + \ No newline at end of file diff --git a/Src/Music_Player_Application/strategies/SequentialPlayStrategy.hpp b/Src/Music_Player_Application/strategies/SequentialPlayStrategy.hpp new file mode 100644 index 0000000..e221af8 --- /dev/null +++ b/Src/Music_Player_Application/strategies/SequentialPlayStrategy.hpp @@ -0,0 +1,48 @@ +#pragma once +#include +#include "../models/Playlist.hpp" +#include "PlayStrategy.hpp" + +using namespace std; + +class SequentialPlayStrategy : public PlayStrategy { +private: + Playlist* currentPlaylist; + int currentIndex; +public: + SequentialPlayStrategy() { + currentPlaylist = nullptr; + currentIndex = -1; + } + + void setPlaylist(Playlist* playlist) override { + currentPlaylist = playlist; + currentIndex = -1; + } + + bool hasNext() override { + return ((currentIndex + 1) < currentPlaylist->getSize()); + } + + // Next in Loop + Song* next() override { + if (!currentPlaylist || currentPlaylist->getSize() == 0) { + throw runtime_error("No playlist loaded or playlist is empty."); + } + currentIndex = currentIndex + 1; + return currentPlaylist->getSongs()[currentIndex]; + } + + bool hasPrevious() override { + return (currentIndex - 1 > 0); + } + + // previous in Loop + Song* previous() override { + if (!currentPlaylist || currentPlaylist->getSize() == 0) { + throw runtime_error("No playlist loaded or playlist is empty."); + } + currentIndex = currentIndex - 1; + return currentPlaylist->getSongs()[currentIndex]; + } +}; \ No newline at end of file