void
playlist_stop(struct playlist *playlist, struct player_control *pc)
{
	if (!playlist->playing)
		return;

	assert(playlist->current >= 0);

	g_debug("stop");
	pc_stop(pc);
	playlist->queued = -1;
	playlist->playing = false;

	if (playlist->queue.random) {
		/* shuffle the playlist, so the next playback will
		   result in a new random order */

		unsigned current_position =
			queue_order_to_position(&playlist->queue,
						playlist->current);

		queue_shuffle_order(&playlist->queue);

		/* make sure that "current" stays valid, and the next
		   "play" command plays the same song again */
		playlist->current =
			queue_position_to_order(&playlist->queue,
						current_position);
	}
}
コード例 #2
0
ファイル: playlist.c プロジェクト: pallotron/MPD
void
playlist_update_queued_song(struct playlist *playlist,
			    struct player_control *pc,
			    const struct song *prev)
{
	int next_order;
	const struct song *next_song;

	if (!playlist->playing)
		return;

	assert(!queue_is_empty(&playlist->queue));
	assert((playlist->queued < 0) == (prev == NULL));

	next_order = playlist->current >= 0
		? queue_next_order(&playlist->queue, playlist->current)
		: 0;

	if (next_order == 0 && playlist->queue.random &&
	    !playlist->queue.single) {
		/* shuffle the song order again, so we get a different
		   order each time the playlist is played
		   completely */
		unsigned current_position =
			queue_order_to_position(&playlist->queue,
						playlist->current);

		queue_shuffle_order(&playlist->queue);

		/* make sure that the playlist->current still points to
		   the current song, after the song order has been
		   shuffled */
		playlist->current =
			queue_position_to_order(&playlist->queue,
						current_position);
	}

	if (next_order >= 0)
		next_song = queue_get_order(&playlist->queue, next_order);
	else
		next_song = NULL;

	if (prev != NULL && next_song != prev) {
		/* clear the currently queued song */
		pc_cancel(pc);
		playlist->queued = -1;
	}

	if (next_order >= 0) {
		if (next_song != prev)
			playlist_queue_song_order(playlist, pc, next_order);
		else
			playlist->queued = next_order;
	}
}
コード例 #3
0
static void
playlist_delete_internal(struct playlist *playlist, unsigned song,
			 const struct song **queued_p)
{
	unsigned songOrder;

	assert(song < queue_length(&playlist->queue));

	songOrder = queue_position_to_order(&playlist->queue, song);

	if (playlist->playing && playlist->current == (int)songOrder) {
		bool paused = pc_get_state() == PLAYER_STATE_PAUSE;

		/* the current song is going to be deleted: stop the player */

		pc_stop();
		playlist->playing = false;

		/* see which song is going to be played instead */

		playlist->current = queue_next_order(&playlist->queue,
						     playlist->current);
		if (playlist->current == (int)songOrder)
			playlist->current = -1;

		if (playlist->current >= 0 && !paused)
			/* play the song after the deleted one */
			playlist_play_order(playlist, playlist->current);
		else
			/* no songs left to play, stop playback
			   completely */
			playlist_stop(playlist);

		*queued_p = NULL;
	} else if (playlist->current == (int)songOrder)
		/* there's a "current song" but we're not playing
		   currently - clear "current" */
		playlist->current = -1;

	/* now do it: remove the song */

	if (!song_in_database(queue_get(&playlist->queue, song)))
		pc_song_deleted(queue_get(&playlist->queue, song));

	queue_delete(&playlist->queue, song);

	/* update the "current" and "queued" variables */

	if (playlist->current > (int)songOrder) {
		playlist->current--;
	}
}
enum playlist_result
playlist_play(struct playlist *playlist, struct player_control *pc,
	      int song)
{
	unsigned i = song;

	pc_clear_error(pc);

	if (song == -1) {
		/* play any song ("current" song, or the first song */

		if (queue_is_empty(&playlist->queue))
			return PLAYLIST_RESULT_SUCCESS;

		if (playlist->playing) {
			/* already playing: unpause playback, just in
			   case it was paused, and return */
			pc_set_pause(pc, false);
			return PLAYLIST_RESULT_SUCCESS;
		}

		/* select a song: "current" song, or the first one */
		i = playlist->current >= 0
			? playlist->current
			: 0;
	} else if (!queue_valid_position(&playlist->queue, song))
		return PLAYLIST_RESULT_BAD_RANGE;

	if (playlist->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 = queue_position_to_order(&playlist->queue, song);

		if (!playlist->playing)
			playlist->current = 0;

		/* swap the new song with the previous "current" one,
		   so playback continues as planned */
		queue_swap_order(&playlist->queue,
				 i, playlist->current);
		i = playlist->current;
	}

	playlist->stop_on_error = false;
	playlist->error_count = 0;

	playlist_play_order(playlist, pc, i);
	return PLAYLIST_RESULT_SUCCESS;
}
コード例 #5
0
ファイル: playlist_edit.c プロジェクト: mvasilkov/mpd
enum playlist_result
playlist_swap_songs(struct playlist *playlist, struct player_control *pc,
		    unsigned song1, unsigned song2)
{
	const struct song *queued;

	if (!queue_valid_position(&playlist->queue, song1) ||
	    !queue_valid_position(&playlist->queue, song2))
		return PLAYLIST_RESULT_BAD_RANGE;

	queued = playlist_get_queued_song(playlist);

	queue_swap(&playlist->queue, song1, song2);

	if (playlist->queue.random) {
		/* update the queue order, so that playlist->current
		   still points to the current song order */

		queue_swap_order(&playlist->queue,
				 queue_position_to_order(&playlist->queue,
							 song1),
				 queue_position_to_order(&playlist->queue,
							 song2));
	} else {
		/* correct the "current" song order */

		if (playlist->current == (int)song1)
			playlist->current = song2;
		else if (playlist->current == (int)song2)
			playlist->current = song1;
	}

	playlist_increment_version(playlist);

	playlist_update_queued_song(playlist, pc, queued);

	return PLAYLIST_RESULT_SUCCESS;
}
コード例 #6
0
ファイル: playlist_edit.c プロジェクト: mvasilkov/mpd
void
playlist_shuffle(struct playlist *playlist, struct player_control *pc,
		 unsigned start, unsigned end)
{
	const struct song *queued;

	if (end > queue_length(&playlist->queue))
		/* correct the "end" offset */
		end = queue_length(&playlist->queue);

	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 = queue_order_to_position(&playlist->queue,
	                                                   playlist->current);

		if (current_position >= start && current_position < end)
		{
			/* put current playing song first */
			queue_swap(&playlist->queue, start, current_position);

			if (playlist->queue.random) {
				playlist->current =
					queue_position_to_order(&playlist->queue, start);
			} else
				playlist->current = start;

			/* start shuffle after the current song */
			start++;
		}
	} else {
		/* no playback currently: reset playlist->current */

		playlist->current = -1;
	}

	queue_shuffle_range(&playlist->queue, start, end);

	playlist_increment_version(playlist);

	playlist_update_queued_song(playlist, pc, queued);
}
enum playlist_result
playlist_seek_song(struct playlist *playlist, struct player_control *pc,
		   unsigned song, float seek_time)
{
	const struct song *queued;
	unsigned i;
	bool success;

	if (!queue_valid_position(&playlist->queue, song))
		return PLAYLIST_RESULT_BAD_RANGE;

	queued = playlist_get_queued_song(playlist);

	if (playlist->queue.random)
		i = queue_position_to_order(&playlist->queue, song);
	else
		i = song;

	pc_clear_error(pc);
	playlist->stop_on_error = true;
	playlist->error_count = 0;

	if (!playlist->playing || (unsigned)playlist->current != i) {
		/* seeking is not within the current song - prepare
		   song change */

		playlist->playing = true;
		playlist->current = i;

		queued = NULL;
	}

	success = pc_seek(pc, queue_get_order(&playlist->queue, i), seek_time);
	if (!success) {
		playlist_update_queued_song(playlist, pc, queued);

		return PLAYLIST_RESULT_NOT_PLAYING;
	}

	playlist->queued = -1;
	playlist_update_queued_song(playlist, pc, NULL);

	return PLAYLIST_RESULT_SUCCESS;
}
コード例 #8
0
ファイル: playlist.c プロジェクト: pallotron/MPD
void
playlist_set_random(struct playlist *playlist, struct player_control *pc,
		    bool status)
{
	const struct song *queued;

	if (status == playlist->queue.random)
		return;

	queued = playlist_get_queued_song(playlist);

	playlist->queue.random = status;

	if (playlist->queue.random) {
		/* shuffle the queue order, but preserve
		   playlist->current */

		int current_position =
			playlist->playing && playlist->current >= 0
			? (int)queue_order_to_position(&playlist->queue,
						       playlist->current)
			: -1;

		queue_shuffle_order(&playlist->queue);

		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 =
				queue_position_to_order(&playlist->queue,
							current_position);
			queue_swap_order(&playlist->queue, 0, current_order);
			playlist->current = 0;
		} else
			playlist->current = -1;
	} else
		playlist_order(playlist);

	playlist_update_queued_song(playlist, pc, queued);

	idle_add(IDLE_OPTIONS);
}
コード例 #9
0
ファイル: playlist_edit.c プロジェクト: mvasilkov/mpd
enum playlist_result
playlist_set_priority(struct playlist *playlist, struct player_control *pc,
		      unsigned start, unsigned end,
		      uint8_t priority)
{
	if (start >= queue_length(&playlist->queue))
		return PLAYLIST_RESULT_BAD_RANGE;

	if (end > queue_length(&playlist->queue))
		end = queue_length(&playlist->queue);

	if (start >= end)
		return PLAYLIST_RESULT_SUCCESS;

	/* remember "current" and "queued" */

	int current_position = playlist->current >= 0
		? (int)queue_order_to_position(&playlist->queue,
					       playlist->current)
		: -1;

	const struct song *queued = playlist_get_queued_song(playlist);

	/* apply the priority changes */

	queue_set_priority_range(&playlist->queue, start, end, priority,
				 playlist->current);

	playlist_increment_version(playlist);

	/* restore "current" and choose a new "queued" */

	if (current_position >= 0)
		playlist->current = queue_position_to_order(&playlist->queue,
							    current_position);

	playlist_update_queued_song(playlist, pc, queued);

	return PLAYLIST_RESULT_SUCCESS;
}
コード例 #10
0
void
queue_delete(struct queue *queue, unsigned position)
{
	struct song *song;
	unsigned id, order;

	assert(position < queue->length);

	song = queue_get(queue, position);
	if (!song_in_database(song))
		song_free(song);

	id = queue_position_to_id(queue, position);
	order = queue_position_to_order(queue, position);

	--queue->length;

	/* release the song id */

	queue->id_to_position[id] = -1;

	/* delete song from songs array */

	for (unsigned i = position; i < queue->length; i++)
		queue_move_song_to(queue, i + 1, i);

	/* delete the entry from the order array */

	for (unsigned i = order; i < queue->length; i++)
		queue->order[i] = queue->order[i + 1];

	/* readjust values in the order array */

	for (unsigned i = 0; i < queue->length; i++)
		if (queue->order[i] > position)
			--queue->order[i];
}
コード例 #11
0
int
main(G_GNUC_UNUSED int argc, G_GNUC_UNUSED char **argv)
{
	struct song songs[16];

	struct queue queue;
	queue_init(&queue, 32);

	for (unsigned i = 0; i < G_N_ELEMENTS(songs); ++i)
		queue_append(&queue, &songs[i]);

	assert(queue_length(&queue) == G_N_ELEMENTS(songs));

	/* priority=10 for 4 items */

	queue_set_priority_range(&queue, 4, 8, 10, -1);

	queue.random = true;
	queue_shuffle_order(&queue);
	check_descending_priority(&queue, 0);

	for (unsigned i = 0; i < 4; ++i) {
		assert(queue_position_to_order(&queue, i) >= 4);
	}

	for (unsigned i = 4; i < 8; ++i) {
		assert(queue_position_to_order(&queue, i) < 4);
	}

	for (unsigned i = 8; i < G_N_ELEMENTS(songs); ++i) {
		assert(queue_position_to_order(&queue, i) >= 4);
	}

	/* priority=50 one more item */

	queue_set_priority_range(&queue, 15, 16, 50, -1);
	check_descending_priority(&queue, 0);

	assert(queue_position_to_order(&queue, 15) == 0);

	for (unsigned i = 0; i < 4; ++i) {
		assert(queue_position_to_order(&queue, i) >= 4);
	}

	for (unsigned i = 4; i < 8; ++i) {
		assert(queue_position_to_order(&queue, i) >= 1 &&
		       queue_position_to_order(&queue, i) < 5);
	}

	for (unsigned i = 8; i < 15; ++i) {
		assert(queue_position_to_order(&queue, i) >= 5);
	}

	/* priority=20 for one of the 4 priority=10 items */

	queue_set_priority_range(&queue, 3, 4, 20, -1);
	check_descending_priority(&queue, 0);

	assert(queue_position_to_order(&queue, 3) == 1);
	assert(queue_position_to_order(&queue, 15) == 0);

	for (unsigned i = 0; i < 3; ++i) {
		assert(queue_position_to_order(&queue, i) >= 5);
	}

	for (unsigned i = 4; i < 8; ++i) {
		assert(queue_position_to_order(&queue, i) >= 2 &&
		       queue_position_to_order(&queue, i) < 6);
	}

	for (unsigned i = 8; i < 15; ++i) {
		assert(queue_position_to_order(&queue, i) >= 6);
	}

	/* priority=20 for another one of the 4 priority=10 items;
	   pass "after_order" (with priority=10) and see if it's moved
	   after that one */

	unsigned current_order = 4;
	unsigned current_position =
		queue_order_to_position(&queue, current_order);

	unsigned a_order = 3;
	unsigned a_position = queue_order_to_position(&queue, a_order);
	assert(queue.items[a_position].priority == 10);
	queue_set_priority(&queue, a_position, 20, current_order);

	current_order = queue_position_to_order(&queue, current_position);
	assert(current_order == 3);

	a_order = queue_position_to_order(&queue, a_position);
	assert(a_order == 4);

	check_descending_priority(&queue, current_order + 1);

	/* priority=70 for one of the last items; must be inserted
	   right after the current song, before the priority=20 one we
	   just created */

	unsigned b_order = 10;
	unsigned b_position = queue_order_to_position(&queue, b_order);
	assert(queue.items[b_position].priority == 0);
	queue_set_priority(&queue, b_position, 70, current_order);

	current_order = queue_position_to_order(&queue, current_position);
	assert(current_order == 3);

	b_order = queue_position_to_order(&queue, b_position);
	assert(b_order == 4);

	check_descending_priority(&queue, current_order + 1);

	/* priority=60 for the old prio50 item; must not be moved,
	   because it's before the current song, and it's status
	   hasn't changed (it was already higher before) */

	unsigned c_order = 0;
	unsigned c_position = queue_order_to_position(&queue, c_order);
	assert(queue.items[c_position].priority == 50);
	queue_set_priority(&queue, c_position, 60, current_order);

	current_order = queue_position_to_order(&queue, current_position);
	assert(current_order == 3);

	c_order = queue_position_to_order(&queue, c_position);
	assert(c_order == 0);

	/* move the prio=20 item back */

	a_order = queue_position_to_order(&queue, a_position);
	assert(a_order == 5);
	assert(queue.items[a_position].priority == 20);
	queue_set_priority(&queue, a_position, 5, current_order);


	current_order = queue_position_to_order(&queue, current_position);
	assert(current_order == 3);

	a_order = queue_position_to_order(&queue, a_position);
	assert(a_order == 6);
}