tmus

TUI Music Player
git clone https://git.sinitax.com/sinitax/tmus
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

player.c (3669B)


      1#include "player.h"
      2
      3#include "list.h"
      4#include "data.h"
      5
      6#include <stdlib.h>
      7
      8static bool player_history_contains(struct track *cmp, int depth);
      9static struct track *playlist_track_next_unused(struct list_link *start);
     10static struct track *player_next_from_playlist(void);
     11
     12bool
     13player_history_contains(struct track *cmp, int depth)
     14{
     15	struct list_link *link;
     16	struct track *track;
     17
     18	link = list_back(&player.history);
     19	while (LIST_INNER(link) && depth-- > 0) {
     20		track = LIST_UPCAST(link, struct track, link_hs);
     21		if (track == cmp)
     22			return true;
     23		link = link->prev;
     24	}
     25
     26	return false;
     27}
     28
     29struct track *
     30playlist_track_next_unused(struct list_link *start)
     31{
     32	struct track *track;
     33	struct list_link *link;
     34	bool in_history;
     35	int len;
     36
     37	track = NULL;
     38
     39	len = list_len(&player.playlist);
     40	if (!len) return NULL;
     41
     42	link = start;
     43	while (LIST_INNER(link)) {
     44		track = LIST_UPCAST(link, struct track, link_pl);
     45
     46		in_history = player_history_contains(track, len - 2);
     47		if (track != player.track && !in_history)
     48			break;
     49
     50		link = link->next;
     51		if (!LIST_INNER(link))
     52			link = list_front(&player.playlist);
     53
     54		if (link == start)
     55			return NULL;
     56	}
     57
     58	return track;
     59}
     60
     61struct track *
     62player_next_from_playlist(void)
     63{
     64	struct list_link *link;
     65	int index;
     66
     67	if (list_empty(&player.playlist))
     68		return NULL;
     69
     70	if (player.shuffle) {
     71		index = rand() % list_len(&player.playlist);
     72		link = list_at(&player.playlist, index);
     73		return playlist_track_next_unused(link);
     74	} else {
     75		if (player.track && list_link_inuse(&player.track->link_pl)) {
     76			index = list_index(&player.playlist,
     77				&player.track->link_pl);
     78			ASSERT(index >= 0);
     79			if (++index == list_len(&player.playlist))
     80				return NULL;
     81		} else {
     82			index = 0;
     83		}
     84		link = list_at(&player.playlist, index);
     85		return LIST_UPCAST(link, struct track, link_pl);
     86	}
     87
     88	return NULL;
     89}
     90
     91/* implemented by backend:
     92 *
     93 * void player_init(void);
     94 * void player_deinit(void);
     95 *
     96 * void player_update(void);
     97 *
     98 * int player_play_track(struct track *track, bool new);
     99 * int player_clear_track(void);
    100 */
    101
    102void
    103player_add_history(struct track *new)
    104{
    105	if (!list_link_inuse(&new->link_hs)) {
    106		list_link_pop(&new->link_hs);
    107		list_insert_back(&player.history, &new->link_hs);
    108	}
    109}
    110
    111/* implemented by backend:
    112 *
    113 * int player_toggle_pause(void);
    114 * int player_pause(void);
    115 * int player_resume(void);
    116 */
    117
    118int
    119player_prev(void)
    120{
    121	struct list_link *next;
    122	struct track *track;
    123
    124	if (list_empty(&player.history))
    125		return PLAYER_ERR;
    126
    127	if (!player.track || !list_link_inuse(&player.track->link_hs)) {
    128		next = list_back(&player.history);
    129	} else if (LIST_INNER(player.track->link_hs.prev)) {
    130		next = player.track->link_hs.prev;
    131	} else {
    132		return PLAYER_ERR;
    133	}
    134
    135	track = LIST_UPCAST(next, struct track, link_hs);
    136	player_play_track(track, false);
    137
    138	return PLAYER_OK;
    139}
    140
    141int
    142player_next(void)
    143{
    144	struct track *next_track;
    145	struct list_link *link;
    146	bool new_entry;
    147
    148	if (player.track && list_link_inuse(&player.track->link_hs)
    149			&& LIST_INNER(player.track->link_hs.next)) {
    150		next_track = LIST_UPCAST(player.track->link_hs.next,
    151			struct track, link_hs);
    152		new_entry = false;
    153	} else if (!list_empty(&player.queue)) {
    154		link = list_pop_front(&player.queue);
    155		next_track = LIST_UPCAST(link, struct track, link_pq);
    156		new_entry = true;
    157	} else {
    158		next_track = player_next_from_playlist();
    159		if (!next_track) goto clear;
    160		new_entry = true;
    161	}
    162
    163	player_play_track(next_track, new_entry);
    164	return PLAYER_OK;
    165
    166clear:
    167	player_clear_track();
    168	return PLAYER_ERR;
    169}
    170
    171/* implemented by backend:
    172 *
    173 * int player_seek(int sec);
    174 * int player_play(void);
    175 * int player_stop(void);
    176 *
    177 * int player_set_volume(unsigned int vol);
    178 */
    179