Changed: Improve music player UI, add repeat, shuffle options
--HG-- branch : develop
This commit is contained in:
parent
c74a56f3b9
commit
c93d8ffd50
2 changed files with 141 additions and 31 deletions
|
@ -39,6 +39,9 @@ extern UDriver *Driver;
|
||||||
#define TEMPLATE_PLAYLIST_SONG "playlist_song"
|
#define TEMPLATE_PLAYLIST_SONG "playlist_song"
|
||||||
#define TEMPLATE_PLAYLIST_SONG_TITLE "title"
|
#define TEMPLATE_PLAYLIST_SONG_TITLE "title"
|
||||||
#define TEMPLATE_PLAYLIST_SONG_DURATION "duration"
|
#define TEMPLATE_PLAYLIST_SONG_DURATION "duration"
|
||||||
|
// ui state
|
||||||
|
#define MP3_SAVE_SHUFFLE "UI:SAVE:MP3_SHUFFLE"
|
||||||
|
#define MP3_SAVE_REPEAT "UI:SAVE:MP3_REPEAT"
|
||||||
|
|
||||||
static const std::string MediaPlayerDirectory("music/");
|
static const std::string MediaPlayerDirectory("music/");
|
||||||
|
|
||||||
|
@ -48,8 +51,20 @@ CMusicPlayer MusicPlayer;
|
||||||
|
|
||||||
CMusicPlayer::CMusicPlayer ()
|
CMusicPlayer::CMusicPlayer ()
|
||||||
{
|
{
|
||||||
_CurrentSong = 0;
|
_CurrentSongIndex = 0;
|
||||||
_State = Stopped;
|
_State = Stopped;
|
||||||
|
_PlayStart = 0;
|
||||||
|
_PauseTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CMusicPlayer::isRepeatEnabled() const
|
||||||
|
{
|
||||||
|
return (NLGUI::CDBManager::getInstance()->getDbProp(MP3_SAVE_REPEAT)->getValue32() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CMusicPlayer::isShuffleEnabled() const
|
||||||
|
{
|
||||||
|
return (NLGUI::CDBManager::getInstance()->getDbProp(MP3_SAVE_SHUFFLE)->getValue32() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,16 +74,61 @@ void CMusicPlayer::playSongs (const std::vector<CSongs> &songs)
|
||||||
_Songs = songs;
|
_Songs = songs;
|
||||||
|
|
||||||
// reset song index if out of bounds
|
// reset song index if out of bounds
|
||||||
if (_CurrentSong > _Songs.size())
|
if (_CurrentSongIndex > _Songs.size())
|
||||||
_CurrentSong = 0;
|
_CurrentSongIndex = 0;
|
||||||
|
|
||||||
|
if (isShuffleEnabled())
|
||||||
|
shuffleAndRebuildPlaylist();
|
||||||
|
else
|
||||||
|
rebuildPlaylist();
|
||||||
|
|
||||||
|
// If pause, stop, else play will resume
|
||||||
|
if (_State == Paused)
|
||||||
|
_State = Stopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***************************************************************************
|
||||||
|
void CMusicPlayer::updatePlaylist(sint prevIndex)
|
||||||
|
{
|
||||||
|
CInterfaceElement *pIE;
|
||||||
|
std::string rowId;
|
||||||
|
|
||||||
|
if (prevIndex >= 0 && prevIndex < _Songs.size())
|
||||||
|
{
|
||||||
|
rowId = toString("%s:s%d:bg", MP3_PLAYER_PLAYLIST_LIST, prevIndex);
|
||||||
|
pIE = dynamic_cast<CInterfaceElement*>(CWidgetManager::getInstance()->getElementFromId(rowId));
|
||||||
|
if (pIE) pIE->setActive(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
rowId = toString("%s:s%d:bg", MP3_PLAYER_PLAYLIST_LIST, _CurrentSongIndex);
|
||||||
|
pIE = dynamic_cast<CInterfaceElement*>(CWidgetManager::getInstance()->getElementFromId(rowId));
|
||||||
|
if (pIE) pIE->setActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***************************************************************************
|
||||||
|
void CMusicPlayer::shuffleAndRebuildPlaylist()
|
||||||
|
{
|
||||||
|
std::random_shuffle(_Songs.begin(), _Songs.end());
|
||||||
|
rebuildPlaylist();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ***************************************************************************
|
||||||
|
void CMusicPlayer::rebuildPlaylist()
|
||||||
|
{
|
||||||
CGroupList *pList = dynamic_cast<CGroupList *>(CWidgetManager::getInstance()->getElementFromId(MP3_PLAYER_PLAYLIST_LIST));
|
CGroupList *pList = dynamic_cast<CGroupList *>(CWidgetManager::getInstance()->getElementFromId(MP3_PLAYER_PLAYLIST_LIST));
|
||||||
if (pList)
|
if (pList)
|
||||||
{
|
{
|
||||||
pList->clearGroups();
|
pList->clearGroups();
|
||||||
pList->setDynamicDisplaySize(true);
|
pList->setDynamicDisplaySize(true);
|
||||||
|
bool found = _CurrentSong.Filename.empty();
|
||||||
for (uint i=0; i < _Songs.size(); ++i)
|
for (uint i=0; i < _Songs.size(); ++i)
|
||||||
{
|
{
|
||||||
|
if (!found && _CurrentSong.Filename == _Songs[i].Filename)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
_CurrentSongIndex = i;
|
||||||
|
}
|
||||||
|
|
||||||
uint min = (sint32)(_Songs[i].Length / 60) % 60;
|
uint min = (sint32)(_Songs[i].Length / 60) % 60;
|
||||||
uint sec = (sint32)(_Songs[i].Length) % 60;
|
uint sec = (sint32)(_Songs[i].Length) % 60;
|
||||||
uint hour = _Songs[i].Length / 3600;
|
uint hour = _Songs[i].Length / 3600;
|
||||||
|
@ -103,9 +163,7 @@ void CMusicPlayer::playSongs (const std::vector<CSongs> &songs)
|
||||||
pList->invalidateCoords();
|
pList->invalidateCoords();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If pause, stop, else play will resume
|
updatePlaylist();
|
||||||
if (_State == Paused)
|
|
||||||
_State = Stopped;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -116,31 +174,40 @@ void CMusicPlayer::play (sint index)
|
||||||
if(!SoundMngr)
|
if(!SoundMngr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
sint prevSongIndex = _CurrentSongIndex;
|
||||||
|
|
||||||
if (index >= 0 && index < (sint)_Songs.size())
|
if (index >= 0 && index < (sint)_Songs.size())
|
||||||
{
|
{
|
||||||
if (_State == Paused)
|
if (_State == Paused)
|
||||||
|
{
|
||||||
stop();
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
_CurrentSong = index;
|
_CurrentSongIndex = index;
|
||||||
|
_PauseTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_Songs.empty())
|
if (!_Songs.empty())
|
||||||
{
|
{
|
||||||
nlassert (_CurrentSong<_Songs.size());
|
nlassert (_CurrentSongIndex<_Songs.size());
|
||||||
|
|
||||||
/* If the player is paused, resume, else, play the current song */
|
/* If the player is paused, resume, else, play the current song */
|
||||||
if (_State == Paused)
|
if (_State == Paused)
|
||||||
|
{
|
||||||
SoundMngr->resumeMusic();
|
SoundMngr->resumeMusic();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
SoundMngr->playMusic(_Songs[_CurrentSong].Filename, 0, true, false, false);
|
{
|
||||||
|
SoundMngr->playMusic(_Songs[_CurrentSongIndex].Filename, 0, true, false, false);
|
||||||
|
_PauseTime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
_State = Playing;
|
_State = Playing;
|
||||||
|
_PlayStart = CTime::getLocalTime() - _PauseTime;
|
||||||
|
|
||||||
/* Show the song title */
|
_CurrentSong = _Songs[_CurrentSongIndex];
|
||||||
CInterfaceManager *pIM = CInterfaceManager::getInstance();
|
|
||||||
CViewText *pVT = dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:mp3_player:screen:text"));
|
updatePlaylist(prevSongIndex);
|
||||||
if (pVT)
|
|
||||||
pVT->setText (ucstring::makeFromUtf8(_Songs[_CurrentSong].Title));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +222,9 @@ void CMusicPlayer::pause ()
|
||||||
{
|
{
|
||||||
SoundMngr->pauseMusic();
|
SoundMngr->pauseMusic();
|
||||||
_State = Paused;
|
_State = Paused;
|
||||||
|
|
||||||
|
if (_PlayStart > 0)
|
||||||
|
_PauseTime = CTime::getLocalTime() - _PlayStart;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +237,8 @@ void CMusicPlayer::stop ()
|
||||||
// stop the music only if we are really playing (else risk to stop a background music!)
|
// stop the music only if we are really playing (else risk to stop a background music!)
|
||||||
SoundMngr->stopMusic(0);
|
SoundMngr->stopMusic(0);
|
||||||
_State = Stopped;
|
_State = Stopped;
|
||||||
|
_PlayStart = 0;
|
||||||
|
_PauseTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ***************************************************************************
|
// ***************************************************************************
|
||||||
|
@ -176,12 +248,13 @@ void CMusicPlayer::previous ()
|
||||||
if (!_Songs.empty())
|
if (!_Songs.empty())
|
||||||
{
|
{
|
||||||
// Point the previous song
|
// Point the previous song
|
||||||
if (_CurrentSong == 0)
|
sint index;
|
||||||
_CurrentSong = (uint)_Songs.size()-1;
|
if (_CurrentSongIndex == 0)
|
||||||
|
index = (uint)_Songs.size()-1;
|
||||||
else
|
else
|
||||||
_CurrentSong--;
|
index = _CurrentSongIndex-1;
|
||||||
|
|
||||||
play ();
|
play(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,9 +264,11 @@ void CMusicPlayer::next ()
|
||||||
{
|
{
|
||||||
if (!_Songs.empty())
|
if (!_Songs.empty())
|
||||||
{
|
{
|
||||||
_CurrentSong++;
|
sint index = _CurrentSongIndex+1;
|
||||||
_CurrentSong%=_Songs.size();
|
if (index == _Songs.size())
|
||||||
play ();
|
index = 0;
|
||||||
|
|
||||||
|
play(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,17 +280,30 @@ void CMusicPlayer::update ()
|
||||||
return;
|
return;
|
||||||
if (_State == Playing)
|
if (_State == Playing)
|
||||||
{
|
{
|
||||||
|
CViewText *pVT = dynamic_cast<CViewText*>(CWidgetManager::getInstance()->getElementFromId("ui:interface:mp3_player:screen:text"));
|
||||||
|
if (pVT)
|
||||||
|
{
|
||||||
|
TTime dur = (CTime::getLocalTime() - _PlayStart) / 1000;
|
||||||
|
std::string title;
|
||||||
|
title = toString("%02d:%02d %s", dur / 60, dur % 60, _CurrentSong.Title.c_str());
|
||||||
|
pVT->setText(ucstring::makeFromUtf8(title));
|
||||||
|
}
|
||||||
|
|
||||||
if (SoundMngr->isMusicEnded ())
|
if (SoundMngr->isMusicEnded ())
|
||||||
{
|
{
|
||||||
// Point the next song
|
// select next song from playlist
|
||||||
_CurrentSong++;
|
sint index = _CurrentSongIndex + 1;
|
||||||
_CurrentSong%=_Songs.size();
|
if (isRepeatEnabled() || index < _Songs.size())
|
||||||
|
|
||||||
// End of the playlist ?
|
|
||||||
if (_CurrentSong != 0)
|
|
||||||
{
|
{
|
||||||
// No, play the next song
|
if (index == _Songs.size())
|
||||||
play ();
|
{
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
if (isShuffleEnabled())
|
||||||
|
shuffleAndRebuildPlaylist();
|
||||||
|
}
|
||||||
|
|
||||||
|
play(index);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -361,11 +449,19 @@ public:
|
||||||
CMusicPlayer::CSongs song;
|
CMusicPlayer::CSongs song;
|
||||||
song.Filename = filenames[i];
|
song.Filename = filenames[i];
|
||||||
SoundMngr->getMixer()->getSongTitle(filenames[i], song.Title, song.Length);
|
SoundMngr->getMixer()->getSongTitle(filenames[i], song.Title, song.Length);
|
||||||
|
if (song.Length > 0)
|
||||||
songs.push_back (song);
|
songs.push_back (song);
|
||||||
}
|
}
|
||||||
|
|
||||||
MusicPlayer.playSongs(songs);
|
MusicPlayer.playSongs(songs);
|
||||||
}
|
}
|
||||||
|
else if (Params == "update_playlist")
|
||||||
|
{
|
||||||
|
if (MusicPlayer.isShuffleEnabled())
|
||||||
|
MusicPlayer.shuffleAndRebuildPlaylist();
|
||||||
|
|
||||||
|
MusicPlayer.rebuildPlaylist();
|
||||||
|
}
|
||||||
else if (Params == "previous")
|
else if (Params == "previous")
|
||||||
MusicPlayer.previous();
|
MusicPlayer.previous();
|
||||||
else if (Params == "play")
|
else if (Params == "play")
|
||||||
|
|
|
@ -55,14 +55,28 @@ public:
|
||||||
|
|
||||||
void update ();
|
void update ();
|
||||||
|
|
||||||
|
bool isRepeatEnabled() const;
|
||||||
|
bool isShuffleEnabled() const;
|
||||||
|
|
||||||
|
// Build playlist UI from songs
|
||||||
|
void rebuildPlaylist();
|
||||||
|
// Randomize playlist and rebuild the ui
|
||||||
|
void shuffleAndRebuildPlaylist();
|
||||||
|
// Update playlist active row
|
||||||
|
void updatePlaylist(sint prevIndex = -1);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// The playlist
|
// The playlist
|
||||||
uint _CurrentSong; // If (!_Songs.empty()) must always be <_Songs.size()
|
CSongs _CurrentSong;
|
||||||
|
uint _CurrentSongIndex; // If (!_Songs.empty()) must always be <_Songs.size()
|
||||||
std::vector<CSongs> _Songs;
|
std::vector<CSongs> _Songs;
|
||||||
|
|
||||||
// State
|
// State
|
||||||
enum TState { Stopped, Playing, Paused } _State;
|
enum TState { Stopped, Playing, Paused } _State;
|
||||||
|
|
||||||
|
TTime _PlayStart;
|
||||||
|
TTime _PauseTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CMusicPlayer MusicPlayer;
|
extern CMusicPlayer MusicPlayer;
|
||||||
|
|
Loading…
Reference in a new issue