diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | src/DatabaseQueue.cxx | 3 | ||||
-rw-r--r-- | src/Partition.hxx | 122 | ||||
-rw-r--r-- | src/PlayerCommands.cxx | 61 | ||||
-rw-r--r-- | src/Playlist.cxx | 264 | ||||
-rw-r--r-- | src/Playlist.hxx | 267 | ||||
-rw-r--r-- | src/PlaylistControl.cxx | 193 | ||||
-rw-r--r-- | src/PlaylistEdit.cxx | 326 | ||||
-rw-r--r-- | src/PlaylistGlobal.cxx | 5 | ||||
-rw-r--r-- | src/PlaylistInternal.hxx | 56 | ||||
-rw-r--r-- | src/PlaylistPrint.cxx | 3 | ||||
-rw-r--r-- | src/PlaylistQueue.cxx | 2 | ||||
-rw-r--r-- | src/PlaylistSave.cxx | 8 | ||||
-rw-r--r-- | src/PlaylistState.cxx | 32 | ||||
-rw-r--r-- | src/QueueCommands.cxx | 74 | ||||
-rw-r--r-- | src/UpdateRemove.cxx | 4 |
16 files changed, 651 insertions, 770 deletions
diff --git a/Makefile.am b/Makefile.am index 1d478c887..2971a7f14 100644 --- a/Makefile.am +++ b/Makefile.am @@ -113,7 +113,6 @@ mpd_headers = \ src/page.h \ src/Playlist.hxx \ src/playlist_error.h \ - src/PlaylistInternal.hxx \ src/playlist_plugin.h \ src/playlist_list.h \ src/playlist/extm3u_playlist_plugin.h \ diff --git a/src/DatabaseQueue.cxx b/src/DatabaseQueue.cxx index dd93cf662..e22144c07 100644 --- a/src/DatabaseQueue.cxx +++ b/src/DatabaseQueue.cxx @@ -30,8 +30,7 @@ static bool AddToQueue(Partition &partition, song &song, GError **error_r) { enum playlist_result result = - playlist_append_song(&partition.playlist, &partition.pc, - &song, NULL); + partition.playlist.AppendSong(partition.pc, &song, NULL); if (result != PLAYLIST_RESULT_SUCCESS) { g_set_error(error_r, playlist_quark(), result, "Playlist error"); diff --git a/src/Partition.hxx b/src/Partition.hxx index a3b9e4625..9efde274a 100644 --- a/src/Partition.hxx +++ b/src/Partition.hxx @@ -38,6 +38,128 @@ struct Partition { :playlist(max_length), pc(buffer_chunks, buffered_before_play) { } + + void ClearQueue() { + playlist.Clear(pc); + } + + enum playlist_result AppendFile(const char *path_fs, + unsigned *added_id=nullptr) { + return playlist.AppendFile(pc, path_fs, added_id); + } + + enum playlist_result AppendURI(const char *uri_utf8, + unsigned *added_id=nullptr) { + return playlist.AppendURI(pc, uri_utf8, added_id); + } + + enum playlist_result DeletePosition(unsigned position) { + return playlist.DeletePosition(pc, position); + } + + enum playlist_result DeleteId(unsigned id) { + return playlist.DeleteId(pc, id); + } + + /** + * Deletes a range of songs from the playlist. + * + * @param start the position of the first song to delete + * @param end the position after the last song to delete + */ + enum playlist_result DeleteRange(unsigned start, unsigned end) { + return playlist.DeleteRange(pc, start, end); + } + + void DeleteSong(const song &song) { + playlist.DeleteSong(pc, song); + } + + void Shuffle(unsigned start, unsigned end) { + playlist.Shuffle(pc, start, end); + } + + enum playlist_result MoveRange(unsigned start, unsigned end, int to) { + return playlist.MoveRange(pc, start, end, to); + } + + enum playlist_result MoveId(unsigned id, int to) { + return playlist.MoveId(pc, id, to); + } + + enum playlist_result SwapPositions(unsigned song1, unsigned song2) { + return playlist.SwapPositions(pc, song1, song2); + } + + enum playlist_result SwapIds(unsigned id1, unsigned id2) { + return playlist.SwapIds(pc, id1, id2); + } + + enum playlist_result SetPriorityRange(unsigned start_position, + unsigned end_position, + uint8_t priority) { + return playlist.SetPriorityRange(pc, + start_position, end_position, + priority); + } + + enum playlist_result SetPriorityId(unsigned song_id, + uint8_t priority) { + return playlist.SetPriorityId(pc, song_id, priority); + } + + void Stop() { + playlist.Stop(pc); + } + + enum playlist_result PlayPosition(int position) { + return playlist.PlayPosition(pc, position); + } + + enum playlist_result PlayId(int id) { + return playlist.PlayId(pc, id); + } + + void PlayNext() { + return playlist.PlayNext(pc); + } + + void PlayPrevious() { + return playlist.PlayPrevious(pc); + } + + enum playlist_result SeekSongPosition(unsigned song_position, + float seek_time) { + return playlist.SeekSongPosition(pc, song_position, seek_time); + } + + enum playlist_result SeekSongId(unsigned song_id, float seek_time) { + return playlist.SeekSongId(pc, song_id, seek_time); + } + + enum playlist_result SeekCurrent(float seek_time, bool relative) { + return playlist.SeekCurrent(pc, seek_time, relative); + } + + void SetRepeat(bool new_value) { + playlist.SetRepeat(pc, new_value); + } + + bool GetRandom() const { + return playlist.GetRandom(); + } + + void SetRandom(bool new_value) { + playlist.SetRandom(pc, new_value); + } + + void SetSingle(bool new_value) { + playlist.SetSingle(pc, new_value); + } + + void SetConsume(bool new_value) { + playlist.SetConsume(new_value); + } }; #endif diff --git a/src/PlayerCommands.cxx b/src/PlayerCommands.cxx index 536ee85b1..99ede9bd8 100644 --- a/src/PlayerCommands.cxx +++ b/src/PlayerCommands.cxx @@ -26,6 +26,7 @@ #include "ClientInternal.hxx" #include "Volume.hxx" #include "OutputAll.hxx" +#include "Partition.hxx" #include "protocol/Result.hxx" #include "protocol/ArgParser.hxx" @@ -34,7 +35,6 @@ extern "C" { } #include "replay_gain_config.h" -#include "PlayerControl.hxx" #include <errno.h> @@ -62,12 +62,10 @@ enum command_return handle_play(Client *client, int argc, char *argv[]) { int song = -1; - enum playlist_result result; if (argc == 2 && !check_int(client, &song, argv[1])) return COMMAND_RETURN_ERROR; - result = playlist_play(&client->playlist, client->player_control, - song); + enum playlist_result result = client->partition.PlayPosition(song); return print_playlist_result(client, result); } @@ -75,13 +73,11 @@ enum command_return handle_playid(Client *client, int argc, char *argv[]) { int id = -1; - enum playlist_result result; if (argc == 2 && !check_int(client, &id, argv[1])) return COMMAND_RETURN_ERROR; - result = playlist_play_id(&client->playlist, client->player_control, - id); + enum playlist_result result = client->partition.PlayId(id); return print_playlist_result(client, result); } @@ -89,7 +85,7 @@ enum command_return handle_stop(Client *client, G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) { - playlist_stop(&client->playlist, client->player_control); + client->partition.Stop(); return COMMAND_RETURN_OK; } @@ -155,23 +151,23 @@ handle_status(Client *client, COMMAND_STATUS_MIXRAMPDELAY ": %f\n" COMMAND_STATUS_STATE ": %s\n", volume_level_get(), - playlist_get_repeat(&playlist), - playlist_get_random(&playlist), - playlist_get_single(&playlist), - playlist_get_consume(&playlist), - playlist_get_version(&playlist), - playlist_get_length(&playlist), + playlist.GetRepeat(), + playlist.GetRandom(), + playlist.GetSingle(), + playlist.GetConsume(), + (unsigned long)playlist.GetVersion(), + playlist.GetLength(), (int)(pc_get_cross_fade(client->player_control) + 0.5), pc_get_mixramp_db(client->player_control), pc_get_mixramp_delay(client->player_control), state); - song = playlist_get_current_song(&playlist); + song = playlist.GetCurrentPosition(); if (song >= 0) { client_printf(client, COMMAND_STATUS_SONG ": %i\n" COMMAND_STATUS_SONGID ": %u\n", - song, playlist_get_song_id(&playlist, song)); + song, playlist.PositionToId(song)); } if (player_status.state != PLAYER_STATE_STOP) { @@ -204,12 +200,12 @@ handle_status(Client *client, g_free(error); } - song = playlist_get_next_song(&playlist); + song = playlist.GetNextPosition(); if (song >= 0) { client_printf(client, COMMAND_STATUS_NEXTSONG ": %i\n" COMMAND_STATUS_NEXTSONGID ": %u\n", - song, playlist_get_song_id(&playlist, song)); + song, playlist.PositionToId(song)); } return COMMAND_RETURN_OK; @@ -226,7 +222,7 @@ handle_next(Client *client, const bool single = playlist.queue.single; playlist.queue.single = false; - playlist_next(&playlist, client->player_control); + client->partition.PlayNext(); playlist.queue.single = single; return COMMAND_RETURN_OK; @@ -236,7 +232,7 @@ enum command_return handle_previous(Client *client, G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) { - playlist_previous(&client->playlist, client->player_control); + client->partition.PlayPrevious(); return COMMAND_RETURN_OK; } @@ -247,7 +243,7 @@ handle_repeat(Client *client, G_GNUC_UNUSED int argc, char *argv[]) if (!check_bool(client, &status, argv[1])) return COMMAND_RETURN_ERROR; - playlist_set_repeat(&client->playlist, client->player_control, status); + client->partition.SetRepeat(status); return COMMAND_RETURN_OK; } @@ -258,7 +254,7 @@ handle_single(Client *client, G_GNUC_UNUSED int argc, char *argv[]) if (!check_bool(client, &status, argv[1])) return COMMAND_RETURN_ERROR; - playlist_set_single(&client->playlist, client->player_control, status); + client->partition.SetSingle(status); return COMMAND_RETURN_OK; } @@ -269,7 +265,7 @@ handle_consume(Client *client, G_GNUC_UNUSED int argc, char *argv[]) if (!check_bool(client, &status, argv[1])) return COMMAND_RETURN_ERROR; - playlist_set_consume(&client->playlist, status); + client->partition.SetConsume(status); return COMMAND_RETURN_OK; } @@ -280,8 +276,8 @@ handle_random(Client *client, G_GNUC_UNUSED int argc, char *argv[]) if (!check_bool(client, &status, argv[1])) return COMMAND_RETURN_ERROR; - playlist_set_random(&client->playlist, client->player_control, status); - audio_output_all_set_replay_gain_mode(replay_gain_get_real_mode(client->playlist.queue.random)); + client->partition.SetRandom(status); + audio_output_all_set_replay_gain_mode(replay_gain_get_real_mode(client->partition.GetRandom())); return COMMAND_RETURN_OK; } @@ -297,15 +293,14 @@ enum command_return handle_seek(Client *client, G_GNUC_UNUSED int argc, char *argv[]) { unsigned song, seek_time; - enum playlist_result result; if (!check_unsigned(client, &song, argv[1])) return COMMAND_RETURN_ERROR; if (!check_unsigned(client, &seek_time, argv[2])) return COMMAND_RETURN_ERROR; - result = playlist_seek_song(&client->playlist, client->player_control, - song, seek_time); + enum playlist_result result = + client->partition.SeekSongPosition(song, seek_time); return print_playlist_result(client, result); } @@ -313,16 +308,14 @@ enum command_return handle_seekid(Client *client, G_GNUC_UNUSED int argc, char *argv[]) { unsigned id, seek_time; - enum playlist_result result; if (!check_unsigned(client, &id, argv[1])) return COMMAND_RETURN_ERROR; if (!check_unsigned(client, &seek_time, argv[2])) return COMMAND_RETURN_ERROR; - result = playlist_seek_song_id(&client->playlist, - client->player_control, - id, seek_time); + enum playlist_result result = + client->partition.SeekSongId(id, seek_time); return print_playlist_result(client, result); } @@ -336,9 +329,7 @@ handle_seekcur(Client *client, G_GNUC_UNUSED int argc, char *argv[]) return COMMAND_RETURN_ERROR; enum playlist_result result = - playlist_seek_current(&client->playlist, - client->player_control, - seek_time, relative); + client->partition.SeekCurrent(seek_time, relative); return print_playlist_result(client, result); } diff --git a/src/Playlist.cxx b/src/Playlist.cxx index 7f89e4ea9..4d1d4897e 100644 --- a/src/Playlist.cxx +++ b/src/Playlist.cxx @@ -18,7 +18,7 @@ */ #include "config.h" -#include "PlaylistInternal.hxx" +#include "Playlist.hxx" #include "PlayerControl.hxx" #include "song.h" @@ -41,14 +41,14 @@ playlist_increment_version_all(struct playlist *playlist) } void -playlist_tag_changed(struct playlist *playlist) +playlist::TagChanged() { - if (!playlist->playing) + if (!playing) return; - assert(playlist->current >= 0); + assert(current >= 0); - playlist->queue.ModifyAtOrder(playlist->current); + queue.ModifyAtOrder(current); idle_add(IDLE_PLAYLIST); } @@ -92,135 +92,117 @@ playlist_song_started(struct playlist *playlist, struct player_control *pc) playlist->queued = -1; if(playlist->queue.consume) - playlist_delete(playlist, pc, - playlist->queue.OrderToPosition(current)); + playlist->DeleteOrder(*pc, current); idle_add(IDLE_PLAYER); } const struct song * -playlist_get_queued_song(struct playlist *playlist) +playlist::GetQueuedSong() const { - if (!playlist->playing || playlist->queued < 0) - return NULL; - - return playlist->queue.GetOrder(playlist->queued); + return playing && queued >= 0 + ? queue.GetOrder(queued) + : nullptr; } void -playlist_update_queued_song(struct playlist *playlist, - struct player_control *pc, - const struct song *prev) +playlist::UpdateQueuedSong(player_control &pc, const song *prev) { - int next_order; - const struct song *next_song; - - if (!playlist->playing) + if (!playing) return; - assert(!playlist->queue.IsEmpty()); - assert((playlist->queued < 0) == (prev == NULL)); + assert(!queue.IsEmpty()); + assert((queued < 0) == (prev == NULL)); - next_order = playlist->current >= 0 - ? playlist->queue.GetNextOrder(playlist->current) + const int next_order = current >= 0 + ? queue.GetNextOrder(current) : 0; - if (next_order == 0 && playlist->queue.random && - !playlist->queue.single) { + if (next_order == 0 && queue.random && !queue.single) { /* shuffle the song order again, so we get a different order each time the playlist is played completely */ - unsigned current_position = - playlist->queue.OrderToPosition(playlist->current); + const unsigned current_position = + queue.OrderToPosition(current); - playlist->queue.ShuffleOrder(); + queue.ShuffleOrder(); - /* make sure that the playlist->current still points to + /* make sure that the current still points to the current song, after the song order has been shuffled */ - playlist->current = - playlist->queue.PositionToOrder(current_position); + current = queue.PositionToOrder(current_position); } - if (next_order >= 0) - next_song = playlist->queue.GetOrder(next_order); - else - next_song = NULL; + const struct song *const next_song = next_order >= 0 + ? queue.GetOrder(next_order) + : nullptr; if (prev != NULL && next_song != prev) { /* clear the currently queued song */ - pc_cancel(pc); - playlist->queued = -1; + pc_cancel(&pc); + queued = -1; } if (next_order >= 0) { if (next_song != prev) - playlist_queue_song_order(playlist, pc, next_order); + playlist_queue_song_order(this, &pc, next_order); else - playlist->queued = next_order; + queued = next_order; } } void -playlist_play_order(struct playlist *playlist, struct player_control *pc, - int orderNum) +playlist::PlayOrder(player_control &pc, int order) { - char *uri; + playing = true; + queued = -1; - playlist->playing = true; - playlist->queued = -1; + struct song *song = song_dup_detached(queue.GetOrder(order)); - struct song *song = - song_dup_detached(playlist->queue.GetOrder(orderNum)); - - uri = song_get_uri(song); - g_debug("play %i:\"%s\"", orderNum, uri); + char *uri = song_get_uri(song); + g_debug("play %i:\"%s\"", order, uri); g_free(uri); - pc_play(pc, song); - playlist->current = orderNum; + pc_play(&pc, song); + current = order; } static void playlist_resume_playback(struct playlist *playlist, struct player_control *pc); -/** - * This is the "PLAYLIST" event handler. It is invoked by the player - * thread whenever it requests a new queued song, or when it exits. - */ void -playlist_sync(struct playlist *playlist, struct player_control *pc) +playlist::SyncWithPlayer(player_control &pc) { - if (!playlist->playing) + if (!playing) /* this event has reached us out of sync: we aren't playing anymore; ignore the event */ return; - player_lock(pc); - enum player_state pc_state = pc_get_state(pc); - const struct song *pc_next_song = pc->next_song; - player_unlock(pc); + player_lock(&pc); + const enum player_state pc_state = pc_get_state(&pc); + const song *pc_next_song = pc.next_song; + player_unlock(&pc); if (pc_state == PLAYER_STATE_STOP) /* the player thread has stopped: check if playback should be restarted with the next song. That can happen if the playlist isn't filling the queue fast enough */ - playlist_resume_playback(playlist, pc); + playlist_resume_playback(this, &pc); else { /* check if the player thread has already started playing the queued song */ - if (pc_next_song == NULL && playlist->queued != -1) - playlist_song_started(playlist, pc); + if (pc_next_song == nullptr && queued != -1) + playlist_song_started(this, &pc); - player_lock(pc); - pc_next_song = pc->next_song; - player_unlock(pc); + player_lock(&pc); + pc_next_song = pc.next_song; + player_unlock(&pc); /* make sure the queued song is always set (if possible) */ - if (pc_next_song == NULL && playlist->queued < 0) - playlist_update_queued_song(playlist, pc, NULL); + if (pc_next_song == nullptr && queued < 0) + UpdateQueuedSong(pc, nullptr); } } @@ -247,53 +229,25 @@ playlist_resume_playback(struct playlist *playlist, struct player_control *pc) playlist->error_count >= playlist->queue.GetLength()) /* too many errors, or critical error: stop playback */ - playlist_stop(playlist, pc); + playlist->Stop(*pc); else /* continue playback at the next song */ - playlist_next(playlist, pc); -} - -bool -playlist_get_repeat(const struct playlist *playlist) -{ - return playlist->queue.repeat; -} - -bool -playlist_get_random(const struct playlist *playlist) -{ - return playlist->queue.random; -} - -bool -playlist_get_single(const struct playlist *playlist) -{ - return playlist->queue.single; -} - -bool -playlist_get_consume(const struct playlist *playlist) -{ - return playlist->queue.consume; + playlist->PlayNext(*pc); } void -playlist_set_repeat(struct playlist *playlist, struct player_control *pc, - bool status) +playlist::SetRepeat(player_control &pc, bool status) { - if (status == playlist->queue.repeat) + if (status == queue.repeat) return; - struct queue *queue = &playlist->queue; - - queue->repeat = status; + queue.repeat = status; - pc_set_border_pause(pc, queue->single && !queue->repeat); + pc_set_border_pause(&pc, queue.single && !queue.repeat); /* if the last song is currently being played, the "next song" might change when repeat mode is toggled */ - playlist_update_queued_song(playlist, pc, - playlist_get_queued_song(playlist)); + UpdateQueuedSong(pc, GetQueuedSong()); idle_add(IDLE_OPTIONS); } @@ -309,117 +263,87 @@ playlist_order(struct playlist *playlist) } void -playlist_set_single(struct playlist *playlist, struct player_control *pc, - bool status) +playlist::SetSingle(player_control &pc, bool status) { - if (status == playlist->queue.single) + if (status == queue.single) return; - struct queue *queue = &playlist->queue; - - queue->single = status; + queue.single = status; - pc_set_border_pause(pc, queue->single && !queue->repeat); + pc_set_border_pause(&pc, queue.single && !queue.repeat); /* if the last song is currently being played, the "next song" might change when single mode is toggled */ - playlist_update_queued_song(playlist, pc, - playlist_get_queued_song(playlist)); + UpdateQueuedSong(pc, GetQueuedSong()); idle_add(IDLE_OPTIONS); } void -playlist_set_consume(struct playlist *playlist, bool status) +playlist::SetConsume(bool status) { - if (status == playlist->queue.consume) + if (status == queue.consume) return; - playlist->queue.consume = status; + queue.consume = status; idle_add(IDLE_OPTIONS); } void -playlist_set_random(struct playlist *playlist, struct player_control *pc, - bool status) +playlist::SetRandom(player_control &pc, bool status) { - const struct song *queued; - - if (status == playlist->queue.random) + if (status == queue.random) return; - queued = playlist_get_queued_song(playlist); + const struct song *const queued_song = GetQueuedSong(); - playlist->queue.random = status; + queue.random = status; - if (playlist->queue.random) { - /* shuffle the queue order, but preserve - playlist->current */ + if (queue.random) { + /* shuffle the queue order, but preserve current */ - int current_position = - playlist->playing && playlist->current >= 0 - ? (int)playlist->queue.OrderToPosition(playlist->current) - : -1; + const int current_position = GetCurrentPosition(); - playlist->queue.ShuffleOrder(); + queue.ShuffleOrder(); if (current_position >= 0) { /* make sure the current song is the first in the order list, so the whole rest of the playlist is played after that */ unsigned current_order = - playlist->queue.PositionToOrder(current_position); - playlist->queue.SwapOrders(0, current_order); - playlist->current = 0; + queue.PositionToOrder(current_position); + queue.SwapOrders(0, current_order); + current = 0; } else - playlist->current = -1; + current = -1; } else - playlist_order(playlist); + playlist_order(this); - playlist_update_queued_song(playlist, pc, queued); + UpdateQueuedSong(pc, queued_song); idle_add(IDLE_OPTIONS); } int -playlist_get_current_song(const struct playlist *playlist) +playlist::GetCurrentPosition() const { - if (playlist->current >= 0) - return playlist->queue.OrderToPosition(playlist->current); - - return -1; + return current >= 0 + ? queue.OrderToPosition(current) + : -1; } int -playlist_get_next_song(const struct playlist *playlist) -{ - if (playlist->current >= 0) - { - if (playlist->queue.single == 1 && playlist->queue.repeat == 1) - return playlist->queue.OrderToPosition(playlist->current); - else if (playlist->current + 1 < (int)playlist->queue.GetLength()) - return playlist->queue.OrderToPosition(playlist->current + 1); - else if (playlist->queue.repeat == 1) - return playlist->queue.OrderToPosition(0); - } - - return -1; -} - -unsigned long -playlist_get_version(const struct playlist *playlist) +playlist::GetNextPosition() const { - return playlist->queue.version; -} + if (current < 0) + return -1; -int -playlist_get_length(const struct playlist *playlist) -{ - return playlist->queue.GetLength(); -} + if (queue.single && queue.repeat) + return queue.OrderToPosition(current); + else if (queue.IsValidOrder(current + 1)) + return queue.OrderToPosition(current + 1); + else if (queue.repeat) + return queue.OrderToPosition(0); -unsigned -playlist_get_song_id(const struct playlist *playlist, unsigned song) -{ - return playlist->queue.PositionToId(song); + return -1; } diff --git a/src/Playlist.hxx b/src/Playlist.hxx index a93c88f05..eb048eb9a 100644 --- a/src/Playlist.hxx +++ b/src/Playlist.hxx @@ -75,175 +75,184 @@ struct playlist { ~playlist() { } -}; -void -playlist_global_init(); + uint32_t GetVersion() const { + return queue.version; + } -void -playlist_tag_changed(struct playlist *playlist); + unsigned GetLength() const { + return queue.GetLength(); + } -/** - * Returns the "queue" object of the global playlist instance. - */ -static inline const struct queue * -playlist_get_queue(const struct playlist *playlist) -{ - return &playlist->queue; -} + unsigned PositionToId(unsigned position) const { + return queue.PositionToId(position); + } -void -playlist_clear(struct playlist *playlist, struct player_control *pc); + gcc_pure + int GetCurrentPosition() const; -/** - * Appends a local file (outside the music database) to the playlist. - * - * Note: the caller is responsible for checking permissions. - */ -enum playlist_result -playlist_append_file(struct playlist *playlist, struct player_control *pc, - const char *path_fs, unsigned *added_id); + gcc_pure + int GetNextPosition() const; -enum playlist_result -playlist_append_uri(struct playlist *playlist, struct player_control *pc, - const char *file, unsigned *added_id); + /** + * Returns the song object which is currently queued. Returns + * none if there is none (yet?) or if MPD isn't playing. + */ + gcc_pure + const struct song *GetQueuedSong() const; -enum playlist_result -playlist_append_song(struct playlist *playlist, struct player_control *pc, - struct song *song, unsigned *added_id); + /** + * This is the "PLAYLIST" event handler. It is invoked by the + * player thread whenever it requests a new queued song, or + * when it exits. + */ + void SyncWithPlayer(player_control &pc); -enum playlist_result -playlist_delete(struct playlist *playlist, struct player_control *pc, - unsigned song); +protected: + /** + * Called by all editing methods after a modification. + * Updates the queue version and emits #IDLE_PLAYLIST. + */ + void OnModified(); -/** - * Deletes a range of songs from the playlist. - * - * @param start the position of the first song to delete - * @param end the position after the last song to delete - */ -enum playlist_result -playlist_delete_range(struct playlist *playlist, struct player_control *pc, - unsigned start, unsigned end); + /** + * Updates the "queued song". Calculates the next song + * according to the current one (if MPD isn't playing, it + * takes the first song), and queues this song. Clears the + * old queued song if there was one. + * + * @param prev the song which was previously queued, as + * determined by playlist_get_queued_song() + */ + void UpdateQueuedSong(player_control &pc, const song *prev); -enum playlist_result -playlist_delete_id(struct playlist *playlist, struct player_control *pc, - unsigned song); +public: + void Clear(player_control &pc); -void -playlist_stop(struct playlist *playlist, struct player_control *pc); + void TagChanged(); -enum playlist_result -playlist_play(struct playlist *playlist, struct player_control *pc, - int song); + enum playlist_result AppendSong(player_control &pc, + struct song *song, + unsigned *added_id=nullptr); -enum playlist_result -playlist_play_id(struct playlist *playlist, struct player_control *pc, - int song); + /** + * Appends a local file (outside the music database) to the + * playlist. + * + * Note: the caller is responsible for checking permissions. + */ + enum playlist_result AppendFile(player_control &pc, + const char *path_fs, + unsigned *added_id=nullptr); -void -playlist_next(struct playlist *playlist, struct player_control *pc); + enum playlist_result AppendURI(player_control &pc, + const char *uri_utf8, + unsigned *added_id=nullptr); -void -playlist_sync(struct playlist *playlist, struct player_control *pc); +protected: + void DeleteInternal(player_control &pc, + unsigned song, const struct song **queued_p); -void -playlist_previous(struct playlist *playlist, struct player_control *pc); +public: + enum playlist_result DeletePosition(player_control &pc, + unsigned position); -void -playlist_shuffle(struct playlist *playlist, struct player_control *pc, - unsigned start, unsigned end); + enum playlist_result DeleteOrder(player_control &pc, + unsigned order) { + return DeletePosition(pc, queue.OrderToPosition(order)); + } -void -playlist_delete_song(struct playlist *playlist, struct player_control *pc, - const struct song *song); + enum playlist_result DeleteId(player_control &pc, unsigned id); + + /** + * Deletes a range of songs from the playlist. + * + * @param start the position of the first song to delete + * @param end the position after the last song to delete + */ + enum playlist_result DeleteRange(player_control &pc, + unsigned start, unsigned end); -enum playlist_result -playlist_move_range(struct playlist *playlist, struct player_control *pc, - unsigned start, unsigned end, int to); + void DeleteSong(player_control &pc, const song &song); -enum playlist_result -playlist_move_id(struct playlist *playlist, struct player_control *pc, - unsigned id, int to); + void Shuffle(player_control &pc, unsigned start, unsigned end); -enum playlist_result -playlist_swap_songs(struct playlist *playlist, struct player_control *pc, - unsigned song1, unsigned song2); + enum playlist_result MoveRange(player_control &pc, + unsigned start, unsigned end, int to); -enum playlist_result -playlist_swap_songs_id(struct playlist *playlist, struct player_control *pc, - unsigned id1, unsigned id2); + enum playlist_result MoveId(player_control &pc, unsigned id, int to); -enum playlist_result -playlist_set_priority(struct playlist *playlist, struct player_control *pc, - unsigned start_position, unsigned end_position, - uint8_t priority); + enum playlist_result SwapPositions(player_control &pc, + unsigned song1, unsigned song2); -enum playlist_result -playlist_set_priority_id(struct playlist *playlist, struct player_control *pc, - unsigned song_id, uint8_t priority); + enum playlist_result SwapIds(player_control &pc, + unsigned id1, unsigned id2); -bool -playlist_get_repeat(const struct playlist *playlist); + enum playlist_result SetPriorityRange(player_control &pc, + unsigned start_position, + unsigned end_position, + uint8_t priority); -void -playlist_set_repeat(struct playlist *playlist, struct player_control *pc, - bool status); + enum playlist_result SetPriorityId(player_control &pc, + unsigned song_id, uint8_t priority); -bool -playlist_get_random(const struct playlist *playlist); + void Stop(player_control &pc); -void -playlist_set_random(struct playlist *playlist, struct player_control *pc, - bool status); + enum playlist_result PlayPosition(player_control &pc, int position); -bool -playlist_get_single(const struct playlist *playlist); + void PlayOrder(player_control &pc, int order); -void -playlist_set_single(struct playlist *playlist, struct player_control *pc, - bool status); + enum playlist_result PlayId(player_control &pc, int id); -bool -playlist_get_consume(const struct playlist *playlist); + void PlayNext(player_control &pc); -void -playlist_set_consume(struct playlist *playlist, bool status); + void PlayPrevious(player_control &pc); + + enum playlist_result SeekSongPosition(player_control &pc, + unsigned song_position, + float seek_time); + + enum playlist_result SeekSongId(player_control &pc, + unsigned song_id, float seek_time); -int -playlist_get_current_song(const struct playlist *playlist); + /** + * Seek within the current song. Fails if MPD is not currently + * playing. + * + * @param time the time in seconds + * @param relative if true, then the specified time is relative to the + * current position + */ + enum playlist_result SeekCurrent(player_control &pc, + float seek_time, bool relative); -int -playlist_get_next_song(const struct playlist *playlist); + bool GetRepeat() const { + return queue.repeat; + } -unsigned -playlist_get_song_id(const struct playlist *playlist, unsigned song); + void SetRepeat(player_control &pc, bool new_value); -int -playlist_get_length(const struct playlist *playlist); + bool GetRandom() const { + return queue.random; + } -unsigned long -playlist_get_version(const struct playlist *playlist); + void SetRandom(player_control &pc, bool new_value); -enum playlist_result -playlist_seek_song(struct playlist *playlist, struct player_control *pc, - unsigned song, float seek_time); + bool GetSingle() const { + return queue.single; + } -enum playlist_result -playlist_seek_song_id(struct playlist *playlist, struct player_control *pc, - unsigned id, float seek_time); + void SetSingle(player_control &pc, bool new_value); -/** - * Seek within the current song. Fails if MPD is not currently - * playing. - * - * @param time the time in seconds - * @param relative if true, then the specified time is relative to the - * current position - */ -enum playlist_result -playlist_seek_current(struct playlist *playlist, struct player_control *pc, - float seek_time, bool relative); + bool GetConsume() const { + return queue.consume; + } + + void SetConsume(bool new_value); +}; + +void +playlist_global_init(); void playlist_increment_version_all(struct playlist *playlist); diff --git a/src/PlaylistControl.cxx b/src/PlaylistControl.cxx index e4c3298fe..323192242 100644 --- a/src/PlaylistControl.cxx +++ b/src/PlaylistControl.cxx @@ -23,7 +23,7 @@ */ #include "config.h" -#include "PlaylistInternal.hxx" +#include "Playlist.hxx" #include "PlayerControl.hxx" #include "song.h" @@ -33,244 +33,223 @@ #define G_LOG_DOMAIN "playlist" void -playlist_stop(struct playlist *playlist, struct player_control *pc) +playlist::Stop(player_control &pc) { - if (!playlist->playing) + if (!playing) return; - assert(playlist->current >= 0); + assert(current >= 0); g_debug("stop"); - pc_stop(pc); - playlist->queued = -1; - playlist->playing = false; + pc_stop(&pc); + queued = -1; + playing = false; - if (playlist->queue.random) { + if (queue.random) { /* shuffle the playlist, so the next playback will result in a new random order */ - unsigned current_position = - playlist->queue.OrderToPosition(playlist->current); + unsigned current_position = queue.OrderToPosition(current); - playlist->queue.ShuffleOrder(); + queue.ShuffleOrder(); /* make sure that "current" stays valid, and the next "play" command plays the same song again */ - playlist->current = - playlist->queue.PositionToOrder(current_position); + current = queue.PositionToOrder(current_position); } } enum playlist_result -playlist_play(struct playlist *playlist, struct player_control *pc, - int song) +playlist::PlayPosition(player_control &pc, int song) { - unsigned i = song; - - pc_clear_error(pc); + pc_clear_error(&pc); + unsigned i = song; if (song == -1) { /* play any song ("current" song, or the first song */ - if (playlist->queue.IsEmpty()) + if (queue.IsEmpty()) return PLAYLIST_RESULT_SUCCESS; - if (playlist->playing) { + if (playing) { /* already playing: unpause playback, just in case it was paused, and return */ - pc_set_pause(pc, false); + pc_set_pause(&pc, false); return PLAYLIST_RESULT_SUCCESS; } /* select a song: "current" song, or the first one */ - i = playlist->current >= 0 - ? playlist->current + i = current >= 0 + ? current : 0; - } else if (!playlist->queue.IsValidPosition(song)) + } else if (!queue.IsValidPosition(song)) return PLAYLIST_RESULT_BAD_RANGE; - if (playlist->queue.random) { + if (queue.random) { if (song >= 0) /* "i" is currently the song position (which would be equal to the order number in no-random mode); convert it to a order number, because random mode is enabled */ - i = playlist->queue.PositionToOrder(song); + i = queue.PositionToOrder(song); - if (!playlist->playing) - playlist->current = 0; + if (!playing) + current = 0; /* swap the new song with the previous "current" one, so playback continues as planned */ - playlist->queue.SwapOrders(i, playlist->current); - i = playlist->current; + queue.SwapOrders(i, current); + i = current; } - playlist->stop_on_error = false; - playlist->error_count = 0; + stop_on_error = false; + error_count = 0; - playlist_play_order(playlist, pc, i); + PlayOrder(pc, i); return PLAYLIST_RESULT_SUCCESS; } enum playlist_result -playlist_play_id(struct playlist *playlist, struct player_control *pc, - int id) +playlist::PlayId(player_control &pc, int id) { - int song; - - if (id == -1) { - return playlist_play(playlist, pc, id); - } + if (id == -1) + return PlayPosition(pc, id); - song = playlist->queue.IdToPosition(id); + int song = queue.IdToPosition(id); if (song < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return playlist_play(playlist, pc, song); + return PlayPosition(pc, song); } void -playlist_next(struct playlist *playlist, struct player_control *pc) +playlist::PlayNext(player_control &pc) { - int next_order; - int current; - - if (!playlist->playing) + if (!playing) return; - assert(!playlist->queue.IsEmpty()); - assert(playlist->queue.IsValidOrder(playlist->current)); + assert(!queue.IsEmpty()); + assert(queue.IsValidOrder(current)); - current = playlist->current; - playlist->stop_on_error = false; + const int old_current = current; + stop_on_error = false; /* determine the next song from the queue's order list */ - next_order = playlist->queue.GetNextOrder(playlist->current); + const int next_order = queue.GetNextOrder(current); if (next_order < 0) { /* no song after this one: stop playback */ - playlist_stop(playlist, pc); + Stop(pc); /* reset "current song" */ - playlist->current = -1; + current = -1; } else { - if (next_order == 0 && playlist->queue.random) { + if (next_order == 0 && queue.random) { /* The queue told us that the next song is the first song. This means we are in repeat mode. Shuffle the queue order, so this time, the user hears the songs in a different than before */ - assert(playlist->queue.repeat); + assert(queue.repeat); - playlist->queue.ShuffleOrder(); + queue.ShuffleOrder(); - /* note that playlist->current and playlist->queued are + /* note that current and queued are now invalid, but playlist_play_order() will discard them anyway */ } - playlist_play_order(playlist, pc, next_order); + PlayOrder(pc, next_order); } /* Consume mode removes each played songs. */ - if(playlist->queue.consume) - playlist_delete(playlist, pc, - playlist->queue.OrderToPosition(current)); + if (queue.consume) + DeleteOrder(pc, old_current); } void -playlist_previous(struct playlist *playlist, struct player_control *pc) +playlist::PlayPrevious(player_control &pc) { - if (!playlist->playing) + if (!playing) return; - assert(playlist->queue.GetLength() > 0); + assert(!queue.IsEmpty()); - if (playlist->current > 0) { + int order; + if (current > 0) { /* play the preceding song */ - playlist_play_order(playlist, pc, - playlist->current - 1); - } else if (playlist->queue.repeat) { + order = current - 1; + } else if (queue.repeat) { /* play the last song in "repeat" mode */ - playlist_play_order(playlist, pc, - playlist->queue.GetLength() - 1); + order = queue.GetLength() - 1; } else { /* re-start playing the current song if it's the first one */ - playlist_play_order(playlist, pc, playlist->current); + order = current; } + + PlayOrder(pc, order); } enum playlist_result -playlist_seek_song(struct playlist *playlist, struct player_control *pc, - unsigned song, float seek_time) +playlist::SeekSongPosition(player_control &pc, unsigned song, float seek_time) { - const struct song *queued; - unsigned i; - bool success; - - if (!playlist->queue.IsValidPosition(song)) + if (!queue.IsValidPosition(song)) return PLAYLIST_RESULT_BAD_RANGE; - queued = playlist_get_queued_song(playlist); + const struct song *queued_song = GetQueuedSong(); - if (playlist->queue.random) - i = playlist->queue.PositionToOrder(song); - else - i = song; + unsigned i = queue.random + ? queue.PositionToOrder(song) + : song; - pc_clear_error(pc); - playlist->stop_on_error = true; - playlist->error_count = 0; + pc_clear_error(&pc); + stop_on_error = true; + error_count = 0; - if (!playlist->playing || (unsigned)playlist->current != i) { + if (!playing || (unsigned)current != i) { /* seeking is not within the current song - prepare song change */ - playlist->playing = true; - playlist->current = i; + playing = true; + current = i; - queued = NULL; + queued_song = nullptr; } - struct song *the_song = - song_dup_detached(playlist->queue.GetOrder(i)); - success = pc_seek(pc, the_song, seek_time); - if (!success) { - playlist_update_queued_song(playlist, pc, queued); + struct song *the_song = song_dup_detached(queue.GetOrder(i)); + if (!pc_seek(&pc, the_song, seek_time)) { + UpdateQueuedSong(pc, queued_song); return PLAYLIST_RESULT_NOT_PLAYING; } - playlist->queued = -1; - playlist_update_queued_song(playlist, pc, NULL); + queued = -1; + UpdateQueuedSong(pc, NULL); return PLAYLIST_RESULT_SUCCESS; } enum playlist_result -playlist_seek_song_id(struct playlist *playlist, struct player_control *pc, - unsigned id, float seek_time) +playlist::SeekSongId(player_control &pc, unsigned id, float seek_time) { - int song = playlist->queue.IdToPosition(id); + int song = queue.IdToPosition(id); if (song < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return playlist_seek_song(playlist, pc, song, seek_time); + return SeekSongPosition(pc, song, seek_time); } enum playlist_result -playlist_seek_current(struct playlist *playlist, struct player_control *pc, - float seek_time, bool relative) +playlist::SeekCurrent(player_control &pc, float seek_time, bool relative) { - if (!playlist->playing) + if (!playing) return PLAYLIST_RESULT_NOT_PLAYING; if (relative) { struct player_status status; - pc_get_status(pc, &status); + pc_get_status(&pc, &status); if (status.state != PLAYER_STATE_PLAY && status.state != PLAYER_STATE_PAUSE) @@ -282,5 +261,5 @@ playlist_seek_current(struct playlist *playlist, struct player_control *pc, if (seek_time < 0) seek_time = 0; - return playlist_seek_song(playlist, pc, playlist->current, seek_time); + return SeekSongPosition(pc, current, seek_time); } diff --git a/src/PlaylistEdit.cxx b/src/PlaylistEdit.cxx index e9e085897..22b7242c1 100644 --- a/src/PlaylistEdit.cxx +++ b/src/PlaylistEdit.cxx @@ -24,7 +24,7 @@ */ #include "config.h" -#include "PlaylistInternal.hxx" +#include "Playlist.hxx" #include "PlayerControl.hxx" extern "C" { @@ -38,67 +38,64 @@ extern "C" { #include <stdlib.h> -static void playlist_increment_version(struct playlist *playlist) +void +playlist::OnModified() { - playlist->queue.IncrementVersion(); + queue.IncrementVersion(); idle_add(IDLE_PLAYLIST); } void -playlist_clear(struct playlist *playlist, struct player_control *pc) +playlist::Clear(player_control &pc) { - playlist_stop(playlist, pc); - - playlist->queue.Clear(); + Stop(pc); - playlist->current = -1; + queue.Clear(); + current = -1; - playlist_increment_version(playlist); + OnModified(); } enum playlist_result -playlist_append_file(struct playlist *playlist, struct player_control *pc, +playlist::AppendFile(struct player_control &pc, const char *path_fs, unsigned *added_id) { struct song *song = song_file_load(path_fs, NULL); if (song == NULL) return PLAYLIST_RESULT_NO_SUCH_SONG; - return playlist_append_song(playlist, pc, song, added_id); + return AppendSong(pc, song, added_id); } enum playlist_result -playlist_append_song(struct playlist *playlist, struct player_control *pc, - struct song *song, unsigned *added_id) +playlist::AppendSong(struct player_control &pc, + struct song *song, unsigned *added_id) { - const struct song *queued; unsigned id; - if (playlist->queue.IsFull()) + if (queue.IsFull()) return PLAYLIST_RESULT_TOO_LARGE; - queued = playlist_get_queued_song(playlist); + const struct song *const queued_song = GetQueuedSong(); - id = playlist->queue.Append(song, 0); + id = queue.Append(song, 0); - if (playlist->queue.random) { + if (queue.random) { /* shuffle the new song into the list of remaining songs to play */ unsigned start; - if (playlist->queued >= 0) - start = playlist->queued + 1; + if (queued >= 0) + start = queued + 1; else - start = playlist->current + 1; - if (start < playlist->queue.GetLength()) - playlist->queue.ShuffleOrderLast(start, - playlist->queue.GetLength()); + start = current + 1; + if (start < queue.GetLength()) + queue.ShuffleOrderLast(start, queue.GetLength()); } - playlist_increment_version(playlist); - - playlist_update_queued_song(playlist, pc, queued); + UpdateQueuedSong(pc, queued_song); + OnModified(); if (added_id) *added_id = id; @@ -107,7 +104,7 @@ playlist_append_song(struct playlist *playlist, struct player_control *pc, } enum playlist_result -playlist_append_uri(struct playlist *playlist, struct player_control *pc, +playlist::AppendURI(struct player_control &pc, const char *uri, unsigned *added_id) { g_debug("add to playlist: %s", uri); @@ -126,8 +123,7 @@ playlist_append_uri(struct playlist *playlist, struct player_control *pc, return PLAYLIST_RESULT_NO_SUCH_SONG; } - enum playlist_result result = - playlist_append_song(playlist, pc, song, added_id); + enum playlist_result result = AppendSong(pc, song, added_id); if (db != nullptr) db->ReturnSong(song); @@ -135,335 +131,293 @@ playlist_append_uri(struct playlist *playlist, struct player_control *pc, } enum playlist_result -playlist_swap_songs(struct playlist *playlist, struct player_control *pc, - unsigned song1, unsigned song2) +playlist::SwapPositions(player_control &pc, unsigned song1, unsigned song2) { - const struct song *queued; - - if (!playlist->queue.IsValidPosition(song1) || - !playlist->queue.IsValidPosition(song2)) + if (!queue.IsValidPosition(song1) || !queue.IsValidPosition(song2)) return PLAYLIST_RESULT_BAD_RANGE; - queued = playlist_get_queued_song(playlist); + const struct song *const queued_song = GetQueuedSong(); - playlist->queue.SwapPositions(song1, song2); + queue.SwapPositions(song1, song2); - if (playlist->queue.random) { - /* update the queue order, so that playlist->current + if (queue.random) { + /* update the queue order, so that current still points to the current song order */ - playlist->queue.SwapOrders(playlist->queue.PositionToOrder(song1), - playlist->queue.PositionToOrder(song2)); + queue.SwapOrders(queue.PositionToOrder(song1), + queue.PositionToOrder(song2)); } else { /* correct the "current" song order */ - if (playlist->current == (int)song1) - playlist->current = song2; - else if (playlist->current == (int)song2) - playlist->current = song1; + if (current == (int)song1) + current = song2; + else if (current == (int)song2) + current = song1; } - playlist_increment_version(playlist); - - playlist_update_queued_song(playlist, pc, queued); + UpdateQueuedSong(pc, queued_song); + OnModified(); return PLAYLIST_RESULT_SUCCESS; } enum playlist_result -playlist_swap_songs_id(struct playlist *playlist, struct player_control *pc, - unsigned id1, unsigned id2) +playlist::SwapIds(player_control &pc, unsigned id1, unsigned id2) { - int song1 = playlist->queue.IdToPosition(id1); - int song2 = playlist->queue.IdToPosition(id2); + int song1 = queue.IdToPosition(id1); + int song2 = queue.IdToPosition(id2); if (song1 < 0 || song2 < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return playlist_swap_songs(playlist, pc, song1, song2); + return SwapPositions(pc, song1, song2); } enum playlist_result -playlist_set_priority(struct playlist *playlist, struct player_control *pc, - unsigned start, unsigned end, - uint8_t priority) +playlist::SetPriorityRange(player_control &pc, + unsigned start, unsigned end, + uint8_t priority) { - if (start >= playlist->queue.GetLength()) + if (start >= GetLength()) return PLAYLIST_RESULT_BAD_RANGE; - if (end > playlist->queue.GetLength()) - end = playlist->queue.GetLength(); + if (end > GetLength()) + end = GetLength(); if (start >= end) return PLAYLIST_RESULT_SUCCESS; /* remember "current" and "queued" */ - int current_position = playlist->current >= 0 - ? (int)playlist->queue.OrderToPosition(playlist->current) - : -1; - - const struct song *queued = playlist_get_queued_song(playlist); + const int current_position = GetCurrentPosition(); + const struct song *const queued_song = GetQueuedSong(); /* apply the priority changes */ - playlist->queue.SetPriorityRange(start, end, priority, - playlist->current); - - playlist_increment_version(playlist); + queue.SetPriorityRange(start, end, priority, current); /* restore "current" and choose a new "queued" */ if (current_position >= 0) - playlist->current = playlist->queue.PositionToOrder(current_position); + current = queue.PositionToOrder(current_position); - playlist_update_queued_song(playlist, pc, queued); + UpdateQueuedSong(pc, queued_song); + OnModified(); return PLAYLIST_RESULT_SUCCESS; } enum playlist_result -playlist_set_priority_id(struct playlist *playlist, struct player_control *pc, - unsigned song_id, uint8_t priority) +playlist::SetPriorityId(struct player_control &pc, + unsigned song_id, uint8_t priority) { - int song_position = playlist->queue.IdToPosition(song_id); + int song_position = queue.IdToPosition(song_id); if (song_position < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return playlist_set_priority(playlist, pc, - song_position, song_position + 1, - priority); + return SetPriorityRange(pc, song_position, song_position + 1, + priority); } -static void -playlist_delete_internal(struct playlist *playlist, struct player_control *pc, +void +playlist::DeleteInternal(player_control &pc, unsigned song, const struct song **queued_p) { - unsigned songOrder; - - assert(song < playlist->queue.GetLength()); + assert(song < GetLength()); - songOrder = playlist->queue.PositionToOrder(song); + unsigned songOrder = queue.PositionToOrder(song); - if (playlist->playing && playlist->current == (int)songOrder) { - bool paused = pc_get_state(pc) == PLAYER_STATE_PAUSE; + if (playing && current == (int)songOrder) { + bool paused = pc_get_state(&pc) == PLAYER_STATE_PAUSE; /* the current song is going to be deleted: stop the player */ - pc_stop(pc); - playlist->playing = false; + pc_stop(&pc); + playing = false; /* see which song is going to be played instead */ - playlist->current = playlist->queue.GetNextOrder(playlist->current); - if (playlist->current == (int)songOrder) - playlist->current = -1; + current = queue.GetNextOrder(current); + if (current == (int)songOrder) + current = -1; - if (playlist->current >= 0 && !paused) + if (current >= 0 && !paused) /* play the song after the deleted one */ - playlist_play_order(playlist, pc, playlist->current); + PlayOrder(pc, current); else /* no songs left to play, stop playback completely */ - playlist_stop(playlist, pc); + Stop(pc); *queued_p = NULL; - } else if (playlist->current == (int)songOrder) + } else if (current == (int)songOrder) /* there's a "current song" but we're not playing currently - clear "current" */ - playlist->current = -1; + current = -1; /* now do it: remove the song */ - playlist->queue.DeletePosition(song); + queue.DeletePosition(song); /* update the "current" and "queued" variables */ - if (playlist->current > (int)songOrder) { - playlist->current--; - } + if (current > (int)songOrder) + current--; } enum playlist_result -playlist_delete(struct playlist *playlist, struct player_control *pc, - unsigned song) +playlist::DeletePosition(struct player_control &pc, unsigned song) { - const struct song *queued; - - if (song >= playlist->queue.GetLength()) + if (song >= queue.GetLength()) return PLAYLIST_RESULT_BAD_RANGE; - queued = playlist_get_queued_song(playlist); + const struct song *queued_song = GetQueuedSong(); - playlist_delete_internal(playlist, pc, song, &queued); + DeleteInternal(pc, song, &queued_song); - playlist_increment_version(playlist); - playlist_update_queued_song(playlist, pc, queued); + UpdateQueuedSong(pc, queued_song); + OnModified(); return PLAYLIST_RESULT_SUCCESS; } enum playlist_result -playlist_delete_range(struct playlist *playlist, struct player_control *pc, - unsigned start, unsigned end) +playlist::DeleteRange(struct player_control &pc, unsigned start, unsigned end) { - const struct song *queued; - - if (start >= playlist->queue.GetLength()) + if (start >= queue.GetLength()) return PLAYLIST_RESULT_BAD_RANGE; - if (end > playlist->queue.GetLength()) - end = playlist->queue.GetLength(); + if (end > queue.GetLength()) + end = queue.GetLength(); if (start >= end) return PLAYLIST_RESULT_SUCCESS; - queued = playlist_get_queued_song(playlist); + const struct song *queued_song = GetQueuedSong(); do { - playlist_delete_internal(playlist, pc, --end, &queued); + DeleteInternal(pc, --end, &queued_song); } while (end != start); - playlist_increment_version(playlist); - playlist_update_queued_song(playlist, pc, queued); + UpdateQueuedSong(pc, queued_song); + OnModified(); return PLAYLIST_RESULT_SUCCESS; } enum playlist_result -playlist_delete_id(struct playlist *playlist, struct player_control *pc, - unsigned id) +playlist::DeleteId(struct player_control &pc, unsigned id) { - int song = playlist->queue.IdToPosition(id); + int song = queue.IdToPosition(id); if (song < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return playlist_delete(playlist, pc, song); + return DeletePosition(pc, song); } void -playlist_delete_song(struct playlist *playlist, struct player_control *pc, - const struct song *song) +playlist::DeleteSong(struct player_control &pc, const struct song &song) { - for (int i = playlist->queue.GetLength() - 1; i >= 0; --i) - if (song == playlist->queue.Get(i)) - playlist_delete(playlist, pc, i); + for (int i = queue.GetLength() - 1; i >= 0; --i) + // TODO: compare URI instead of pointer + if (&song == queue.Get(i)) + DeletePosition(pc, i); } enum playlist_result -playlist_move_range(struct playlist *playlist, struct player_control *pc, - unsigned start, unsigned end, int to) +playlist::MoveRange(player_control &pc, unsigned start, unsigned end, int to) { - const struct song *queued; - int currentSong; - - if (!playlist->queue.IsValidPosition(start) || - !playlist->queue.IsValidPosition(end - 1)) + if (!queue.IsValidPosition(start) || !queue.IsValidPosition(end - 1)) return PLAYLIST_RESULT_BAD_RANGE; - if ((to >= 0 && to + end - start - 1 >= playlist->queue.GetLength()) || - (to < 0 && abs(to) > (int)playlist->queue.GetLength())) + if ((to >= 0 && to + end - start - 1 >= GetLength()) || + (to < 0 && unsigned(abs(to)) > GetLength())) return PLAYLIST_RESULT_BAD_RANGE; if ((int)start == to) /* nothing happens */ return PLAYLIST_RESULT_SUCCESS; - queued = playlist_get_queued_song(playlist); + const struct song *const queued_song = GetQueuedSong(); /* * (to < 0) => move to offset from current song * (-playlist.length == to) => move to position BEFORE current song */ - currentSong = playlist->current >= 0 - ? (int)playlist->queue.OrderToPosition(playlist->current) - : -1; - if (to < 0 && playlist->current >= 0) { + const int currentSong = GetCurrentPosition(); + if (to < 0 && currentSong >= 0) { if (start <= (unsigned)currentSong && (unsigned)currentSong < end) /* no-op, can't be moved to offset of itself */ return PLAYLIST_RESULT_SUCCESS; - to = (currentSong + abs(to)) % playlist->queue.GetLength(); + to = (currentSong + abs(to)) % GetLength(); if (start < (unsigned)to) to--; } - playlist->queue.MoveRange(start, end, to); + queue.MoveRange(start, end, to); - if (!playlist->queue.random) { + if (!queue.random) { /* update current/queued */ - if ((int)start <= playlist->current && - (unsigned)playlist->current < end) - playlist->current += to - start; - else if (playlist->current >= (int)end && - playlist->current <= to) { - playlist->current -= end - start; - } else if (playlist->current >= to && - playlist->current < (int)start) { - playlist->current += end - start; - } + if ((int)start <= current && (unsigned)current < end) + current += to - start; + else if (current >= (int)end && current <= to) + current -= end - start; + else if (current >= to && current < (int)start) + current += end - start; } - playlist_increment_version(playlist); - - playlist_update_queued_song(playlist, pc, queued); + UpdateQueuedSong(pc, queued_song); + OnModified(); return PLAYLIST_RESULT_SUCCESS; } enum playlist_result -playlist_move_id(struct playlist *playlist, struct player_control *pc, - unsigned id1, int to) +playlist::MoveId(player_control &pc, unsigned id1, int to) { - int song = playlist->queue.IdToPosition(id1); + int song = queue.IdToPosition(id1); if (song < 0) return PLAYLIST_RESULT_NO_SUCH_SONG; - return playlist_move_range(playlist, pc, song, song+1, to); + return MoveRange(pc, song, song + 1, to); } void -playlist_shuffle(struct playlist *playlist, struct player_control *pc, - unsigned start, unsigned end) +playlist::Shuffle(player_control &pc, unsigned start, unsigned end) { - const struct song *queued; - - if (end > playlist->queue.GetLength()) + if (end > GetLength()) /* correct the "end" offset */ - end = playlist->queue.GetLength(); + end = GetLength(); - if ((start+1) >= end) + if (start + 1 >= end) /* needs at least two entries. */ return; - queued = playlist_get_queued_song(playlist); - if (playlist->playing && playlist->current >= 0) { - unsigned current_position; - current_position = playlist->queue.OrderToPosition(playlist->current); + const struct song *const queued_song = GetQueuedSong(); + if (playing && current >= 0) { + unsigned current_position = queue.OrderToPosition(current); - if (current_position >= start && current_position < end) - { + if (current_position >= start && current_position < end) { /* put current playing song first */ - playlist->queue.SwapPositions(start, current_position); + queue.SwapPositions(start, current_position); - if (playlist->queue.random) { - playlist->current = - playlist->queue.PositionToOrder(start); + if (queue.random) { + current = queue.PositionToOrder(start); } else - playlist->current = start; + current = start; /* start shuffle after the current song */ start++; } } else { - /* no playback currently: reset playlist->current */ + /* no playback currently: reset current */ - playlist->current = -1; + current = -1; } - playlist->queue.ShuffleRange(start, end); - - playlist_increment_version(playlist); + queue.ShuffleRange(start, end); - playlist_update_queued_song(playlist, pc, queued); + UpdateQueuedSong(pc, queued_song); + OnModified(); } diff --git a/src/PlaylistGlobal.cxx b/src/PlaylistGlobal.cxx index 92572cde9..8490392ea 100644 --- a/src/PlaylistGlobal.cxx +++ b/src/PlaylistGlobal.cxx @@ -34,14 +34,13 @@ extern "C" { static void playlist_tag_event(void) { - playlist_tag_changed(&global_partition->playlist); + global_partition->playlist.TagChanged(); } static void playlist_event(void) { - playlist_sync(&global_partition->playlist, - &global_partition->pc); + global_partition->playlist.SyncWithPlayer(global_partition->pc); } void diff --git a/src/PlaylistInternal.hxx b/src/PlaylistInternal.hxx deleted file mode 100644 index f0cad8e68..000000000 --- a/src/PlaylistInternal.hxx +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2003-2013 The Music Player Daemon Project - * http://www.musicpd.org - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/* - * Internal header for the components of the playlist code. - * - */ - -#ifndef MPD_PLAYLIST_INTERNAL_HXX -#define MPD_PLAYLIST_INTERNAL_HXX - -#include "Playlist.hxx" - -struct player_control; - -/** - * Returns the song object which is currently queued. Returns none if - * there is none (yet?) or if MPD isn't playing. - */ -const struct song * -playlist_get_queued_song(struct playlist *playlist); - -/** - * Updates the "queued song". Calculates the next song according to - * the current one (if MPD isn't playing, it takes the first song), - * and queues this song. Clears the old queued song if there was one. - * - * @param prev the song which was previously queued, as determined by - * playlist_get_queued_song() - */ -void -playlist_update_queued_song(struct playlist *playlist, - struct player_control *pc, - const struct song *prev); - -void -playlist_play_order(struct playlist *playlist, struct player_control *pc, - int orderNum); - -#endif diff --git a/src/PlaylistPrint.cxx b/src/PlaylistPrint.cxx index e12fc8c8b..e6ece7e6b 100644 --- a/src/PlaylistPrint.cxx +++ b/src/PlaylistPrint.cxx @@ -80,8 +80,7 @@ playlist_print_id(Client *client, const struct playlist *playlist, bool playlist_print_current(Client *client, const struct playlist *playlist) { - int current_position = playlist_get_current_song(playlist); - + int current_position = playlist->GetCurrentPosition(); if (current_position < 0) return false; diff --git a/src/PlaylistQueue.cxx b/src/PlaylistQueue.cxx index da9f2c370..1335fa401 100644 --- a/src/PlaylistQueue.cxx +++ b/src/PlaylistQueue.cxx @@ -52,7 +52,7 @@ playlist_load_into_queue(const char *uri, struct playlist_provider *source, if (song == NULL) continue; - result = playlist_append_song(dest, pc, song, NULL); + result = dest->AppendSong(*pc, song); song_free(song); if (result != PLAYLIST_RESULT_SUCCESS) { g_free(base_uri); diff --git a/src/PlaylistSave.cxx b/src/PlaylistSave.cxx index 4d537accf..e3b952280 100644 --- a/src/PlaylistSave.cxx +++ b/src/PlaylistSave.cxx @@ -132,8 +132,7 @@ playlist_load_spl(struct playlist *playlist, struct player_control *pc, for (unsigned i = start_index; i < end_index; ++i) { const auto &uri_utf8 = contents[i]; - if ((playlist_append_uri(playlist, pc, uri_utf8.c_str(), - nullptr)) != PLAYLIST_RESULT_SUCCESS) { + if ((playlist->AppendURI(*pc, uri_utf8.c_str())) != PLAYLIST_RESULT_SUCCESS) { /* for windows compatibility, convert slashes */ char *temp2 = g_strdup(uri_utf8.c_str()); char *p = temp2; @@ -142,9 +141,10 @@ playlist_load_spl(struct playlist *playlist, struct player_control *pc, *p = '/'; p++; } - if ((playlist_append_uri(playlist, pc, temp2, NULL)) != PLAYLIST_RESULT_SUCCESS) { + + if (playlist->AppendURI(*pc, temp2) != PLAYLIST_RESULT_SUCCESS) g_warning("can't add file \"%s\"", temp2); - } + g_free(temp2); } } diff --git a/src/PlaylistState.cxx b/src/PlaylistState.cxx index 40f503e22..14c6d231e 100644 --- a/src/PlaylistState.cxx +++ b/src/PlaylistState.cxx @@ -145,26 +145,16 @@ playlist_state_restore(const char *line, TextFile &file, seek_time = atoi(&(line[strlen(PLAYLIST_STATE_FILE_TIME)])); } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_REPEAT)) { - if (strcmp - (&(line[strlen(PLAYLIST_STATE_FILE_REPEAT)]), - "1") == 0) { - playlist_set_repeat(playlist, pc, true); - } else - playlist_set_repeat(playlist, pc, false); + playlist->SetRepeat(*pc, + strcmp(&(line[strlen(PLAYLIST_STATE_FILE_REPEAT)]), + "1") == 0); } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_SINGLE)) { - if (strcmp - (&(line[strlen(PLAYLIST_STATE_FILE_SINGLE)]), - "1") == 0) { - playlist_set_single(playlist, pc, true); - } else - playlist_set_single(playlist, pc, false); + playlist->SetSingle(*pc, + strcmp(&(line[strlen(PLAYLIST_STATE_FILE_SINGLE)]), + "1") == 0); } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CONSUME)) { - if (strcmp - (&(line[strlen(PLAYLIST_STATE_FILE_CONSUME)]), - "1") == 0) { - playlist_set_consume(playlist, true); - } else - playlist_set_consume(playlist, false); + playlist->SetConsume(strcmp(&(line[strlen(PLAYLIST_STATE_FILE_CONSUME)]), + "1") == 0); } else if (g_str_has_prefix(line, PLAYLIST_STATE_FILE_CROSSFADE)) { pc_set_cross_fade(pc, atoi(line + strlen(PLAYLIST_STATE_FILE_CROSSFADE))); @@ -188,7 +178,7 @@ playlist_state_restore(const char *line, TextFile &file, } } - playlist_set_random(playlist, pc, random_mode); + playlist->SetRandom(*pc, random_mode); if (!playlist->queue.IsEmpty()) { if (!playlist->queue.IsValidPosition(current)) @@ -210,9 +200,9 @@ playlist_state_restore(const char *line, TextFile &file, if (state == PLAYER_STATE_STOP /* && config_option */) playlist->current = current; else if (seek_time == 0) - playlist_play(playlist, pc, current); + playlist->PlayPosition(*pc, current); else - playlist_seek_song(playlist, pc, current, seek_time); + playlist->SeekSongPosition(*pc, current, seek_time); if (state == PLAYER_STATE_PAUSE) pc_pause(pc); diff --git a/src/QueueCommands.cxx b/src/QueueCommands.cxx index 7ef5bffab..4a3e1312d 100644 --- a/src/QueueCommands.cxx +++ b/src/QueueCommands.cxx @@ -27,6 +27,7 @@ #include "PlaylistPrint.hxx" #include "ClientFile.hxx" #include "ClientInternal.hxx" +#include "Partition.hxx" #include "protocol/ArgParser.hxx" #include "protocol/Result.hxx" #include "ls.hxx" @@ -50,10 +51,7 @@ handle_add(Client *client, G_GNUC_UNUSED int argc, char *argv[]) if (!client_allow_file(client, path, &error)) return print_error(client, error); - result = playlist_append_file(&client->playlist, - client->player_control, - path, - NULL); + result = client->partition.AppendFile(path); return print_playlist_result(client, result); } @@ -64,9 +62,7 @@ handle_add(Client *client, G_GNUC_UNUSED int argc, char *argv[]) return COMMAND_RETURN_ERROR; } - result = playlist_append_uri(&client->playlist, - client->player_control, - uri, NULL); + result = client->partition.AppendURI(uri); return print_playlist_result(client, result); } @@ -91,10 +87,7 @@ handle_addid(Client *client, int argc, char *argv[]) if (!client_allow_file(client, path, &error)) return print_error(client, error); - result = playlist_append_file(&client->playlist, - client->player_control, - path, - &added_id); + result = client->partition.AppendFile(path, &added_id); } else { if (uri_has_scheme(uri) && !uri_supported_scheme(uri)) { command_error(client, ACK_ERROR_NO_EXIST, @@ -102,9 +95,7 @@ handle_addid(Client *client, int argc, char *argv[]) return COMMAND_RETURN_ERROR; } - result = playlist_append_uri(&client->playlist, - client->player_control, - uri, &added_id); + result = client->partition.AppendURI(uri, &added_id); } if (result != PLAYLIST_RESULT_SUCCESS) @@ -114,15 +105,11 @@ handle_addid(Client *client, int argc, char *argv[]) unsigned to; if (!check_unsigned(client, &to, argv[2])) return COMMAND_RETURN_ERROR; - result = playlist_move_id(&client->playlist, - client->player_control, - added_id, to); + result = client->partition.MoveId(added_id, to); if (result != PLAYLIST_RESULT_SUCCESS) { enum command_return ret = print_playlist_result(client, result); - playlist_delete_id(&client->playlist, - client->player_control, - added_id); + client->partition.DeleteId(added_id); return ret; } } @@ -135,14 +122,11 @@ enum command_return handle_delete(Client *client, G_GNUC_UNUSED int argc, char *argv[]) { unsigned start, end; - enum playlist_result result; if (!check_range(client, &start, &end, argv[1])) return COMMAND_RETURN_ERROR; - result = playlist_delete_range(&client->playlist, - client->player_control, - start, end); + enum playlist_result result = client->partition.DeleteRange(start, end); return print_playlist_result(client, result); } @@ -150,13 +134,11 @@ enum command_return handle_deleteid(Client *client, G_GNUC_UNUSED int argc, char *argv[]) { unsigned id; - enum playlist_result result; if (!check_unsigned(client, &id, argv[1])) return COMMAND_RETURN_ERROR; - result = playlist_delete_id(&client->playlist, - client->player_control, id); + enum playlist_result result = client->partition.DeleteId(id); return print_playlist_result(client, result); } @@ -176,8 +158,7 @@ handle_shuffle(G_GNUC_UNUSED Client *client, if (argc == 2 && !check_range(client, &start, &end, argv[1])) return COMMAND_RETURN_ERROR; - playlist_shuffle(&client->playlist, client->player_control, - start, end); + client->partition.Shuffle(start, end); return COMMAND_RETURN_OK; } @@ -185,7 +166,7 @@ enum command_return handle_clear(G_GNUC_UNUSED Client *client, G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[]) { - playlist_clear(&client->playlist, client->player_control); + client->partition.ClearQueue(); return COMMAND_RETURN_OK; } @@ -296,10 +277,9 @@ handle_prio(Client *client, int argc, char *argv[]) return COMMAND_RETURN_ERROR; enum playlist_result result = - playlist_set_priority(&client->playlist, - client->player_control, - start_position, end_position, - priority); + client->partition.SetPriorityRange(start_position, + end_position, + priority); if (result != PLAYLIST_RESULT_SUCCESS) return print_playlist_result(client, result); } @@ -327,9 +307,7 @@ handle_prioid(Client *client, int argc, char *argv[]) return COMMAND_RETURN_ERROR; enum playlist_result result = - playlist_set_priority_id(&client->playlist, - client->player_control, - song_id, priority); + client->partition.SetPriorityId(song_id, priority); if (result != PLAYLIST_RESULT_SUCCESS) return print_playlist_result(client, result); } @@ -342,14 +320,14 @@ handle_move(Client *client, G_GNUC_UNUSED int argc, char *argv[]) { unsigned start, end; int to; - enum playlist_result result; if (!check_range(client, &start, &end, argv[1])) return COMMAND_RETURN_ERROR; if (!check_int(client, &to, argv[2])) return COMMAND_RETURN_ERROR; - result = playlist_move_range(&client->playlist, client->player_control, - start, end, to); + + enum playlist_result result = + client->partition.MoveRange(start, end, to); return print_playlist_result(client, result); } @@ -358,14 +336,12 @@ handle_moveid(Client *client, G_GNUC_UNUSED int argc, char *argv[]) { unsigned id; int to; - enum playlist_result result; if (!check_unsigned(client, &id, argv[1])) return COMMAND_RETURN_ERROR; if (!check_int(client, &to, argv[2])) return COMMAND_RETURN_ERROR; - result = playlist_move_id(&client->playlist, client->player_control, - id, to); + enum playlist_result result = client->partition.MoveId(id, to); return print_playlist_result(client, result); } @@ -373,14 +349,14 @@ enum command_return handle_swap(Client *client, G_GNUC_UNUSED int argc, char *argv[]) { unsigned song1, song2; - enum playlist_result result; if (!check_unsigned(client, &song1, argv[1])) return COMMAND_RETURN_ERROR; if (!check_unsigned(client, &song2, argv[2])) return COMMAND_RETURN_ERROR; - result = playlist_swap_songs(&client->playlist, client->player_control, - song1, song2); + + enum playlist_result result = + client->partition.SwapPositions(song1, song2); return print_playlist_result(client, result); } @@ -388,14 +364,12 @@ enum command_return handle_swapid(Client *client, G_GNUC_UNUSED int argc, char *argv[]) { unsigned id1, id2; - enum playlist_result result; if (!check_unsigned(client, &id1, argv[1])) return COMMAND_RETURN_ERROR; if (!check_unsigned(client, &id2, argv[2])) return COMMAND_RETURN_ERROR; - result = playlist_swap_songs_id(&client->playlist, - client->player_control, - id1, id2); + + enum playlist_result result = client->partition.SwapIds(id1, id2); return print_playlist_result(client, result); } diff --git a/src/UpdateRemove.cxx b/src/UpdateRemove.cxx index c1a0cd32b..41aa51773 100644 --- a/src/UpdateRemove.cxx +++ b/src/UpdateRemove.cxx @@ -64,9 +64,7 @@ song_remove_event(void) sticker_song_delete(removed_song); #endif - playlist_delete_song(&global_partition->playlist, - &global_partition->pc, - removed_song); + global_partition->DeleteSong(*removed_song); /* clear "removed_song" and send signal to update thread */ g_mutex_lock(remove_mutex); |