commit fee76b1e3d8da5152e44d67293165ae0c5651d25
parent 2b09bac500bfc2b65467b35520076622d1d67afb
Author: Louis Burda <quent.burda@gmail.com>
Date: Tue, 28 Dec 2021 20:34:33 +0100
In working condition, but with shitty implementation for selecting next track
Diffstat:
M | src/list.c | | | 1 | + |
M | src/main.c | | | 60 | ++++++++++++++++++++++++++++++++---------------------------- |
M | src/player.c | | | 171 | ++++++++++++++++++++++++++++++++++++++----------------------------------------- |
M | src/player.h | | | 23 | ++++++++++++++++++++--- |
4 files changed, 135 insertions(+), 120 deletions(-)
diff --git a/src/list.c b/src/list.c
@@ -70,6 +70,7 @@ struct link *
list_pop_front(struct link *head)
{
ASSERT(head != NULL);
+ if (!head->next) return NULL;
return link_pop(head->next);
}
diff --git a/src/main.c b/src/main.c
@@ -74,11 +74,6 @@ struct cmd {
cmd_handler func;
};
-struct autoplay {
- int enabled;
- int shuffle;
-};
-
static const char player_state_chars[] = {
[PLAYER_STATE_PAUSED] = '|',
[PLAYER_STATE_PLAYING] = '>',
@@ -108,7 +103,8 @@ static struct history search_history, command_history;
static struct history *history;
static int cmd_show, cmd_mode;
-static struct autoplay autoplay;
+static int autoplay;
+static int shuffle;
static struct pane *tag_pane;
static struct listnav tag_nav;
@@ -143,7 +139,7 @@ static void style_off(WINDOW *win, int style);
static wchar_t *command_name_generator(const wchar_t *text, int fwd, int state);
static wchar_t *track_name_generator(const wchar_t *text, int fwd, int state);
-static void select_current_tag(void);
+static void toggle_current_tag(void);
static int tag_input(wint_t c);
static void tag_vis(struct pane *pane, int sel);
@@ -180,8 +176,6 @@ init(void)
history_init(&search_history);
history_init(&command_history);
- datadir = getenv("TMUS_DATA");
- ASSERT(datadir != NULL);
data_load();
player_init();
@@ -215,8 +209,8 @@ init(void)
playlist = LIST_HEAD;
tags_sel = LIST_HEAD;
- autoplay.enabled = 0;
- autoplay.shuffle = 0;
+ autoplay = 0;
+ shuffle = 0;
listnav_init(&tag_nav);
listnav_init(&track_nav);
@@ -249,6 +243,9 @@ data_load(void)
tags = LIST_HEAD;
+ datadir = getenv("TMUS_DATA");
+ ASSERT(datadir != NULL);
+
dir = opendir(datadir);
ASSERT(dir != NULL);
while ((ent = readdir(dir))) {
@@ -440,7 +437,7 @@ track_name_generator(const wchar_t *text, int fwd, int reset)
}
void
-select_current_tag(void)
+toggle_current_tag(void)
{
struct link *link, *iter;
struct track *track;
@@ -481,8 +478,13 @@ tag_input(wint_t c)
listnav_update_sel(&tag_nav, tag_nav.sel + 1);
return 1;
case KEY_SPACE:
- select_current_tag();
+ player->next = NULL;
+ toggle_current_tag();
return 1;
+ case KEY_ENTER:
+ player->next = NULL;
+ refs_free(&tags_sel);
+ toggle_current_tag();
case KEY_NPAGE:
listnav_update_sel(&track_nav,
track_nav.sel - track_nav.wlen / 2);
@@ -744,10 +746,11 @@ cmd_vis(struct pane *pane, int sel)
line = appendstrf(line, " | [QUEUE] %i tracks",
list_len(&player->queue));
- if (autoplay.enabled && !autoplay.shuffle)
+ if (autoplay)
line = appendstrf(line, " | AUTOPLAY");
- else if (autoplay.enabled && autoplay.shuffle)
- line = appendstrf(line, " | AUTOPLAY [S]");
+
+ if (shuffle)
+ line = appendstrf(line, " | SHUFFLE");
wmove(pane->win, 1, 0);
ATTR_ON(pane->win, A_REVERSE);
@@ -846,10 +849,11 @@ main_input(wint_t c)
player_prev();
break;
case L'w':
- autoplay.enabled ^= 1;
+ autoplay ^= 1;
break;
- case KEY_CTRL('w'):
- autoplay.shuffle ^= 1;
+ case L'g':
+ player->next = NULL;
+ shuffle ^= 1;
break;
case L'b':
player_seek(0);
@@ -911,38 +915,37 @@ usercmd_save(const char *args)
void
update_player(void)
{
- static struct track *last = NULL;
+ static struct track *first = NULL;
struct track *track;
struct link *iter;
int index;
player_update();
- if (list_empty(&playlist)) last = NULL;
+ if (list_empty(&playlist)) first = NULL;
/* dont start autoplay before the first song was chosen */
- if (!player->loaded && autoplay.enabled && last) {
+ if (!player->next && first) {
iter = NULL;
- if (autoplay.shuffle) {
+ if (shuffle) {
/* TODO better algorithm for random sequence */
index = rand() % list_len(&playlist);
iter = link_iter(playlist.next, index);
ASSERT(iter != NULL);
- } else if (last) {
+ } else if (player->loaded) {
iter = playlist.next;
for (; iter; iter = iter->next) {
track = UPCAST(iter, struct ref)->data;
- if (track == last)
+ if (track == player->track)
break;
}
iter = iter->next;
}
if (!iter) iter = playlist.next;
- track = UPCAST(iter, struct ref)->data;
- player_play_track(track);
+ player->next = UPCAST(iter, struct ref)->data;
} else {
- last = player->track;
+ first = player->track;
}
}
@@ -974,6 +977,7 @@ main(int argc, const char **argv)
panes[i]->update(panes[i], pane_sel == panes[i]);
wnoutrefresh(panes[i]->win);
}
+
main_vis();
doupdate();
diff --git a/src/player.c b/src/player.c
@@ -22,23 +22,34 @@
static struct player player_static;
struct player *player;
+static void player_clear_msg(void);
+static int handle_mpd_status(int status);
+
static void
-handle_mpd_status(struct mpd_connection *conn, int status)
+player_clear_msg(void)
{
+ free(player->msg);
+ player->msg = NULL;
+ player->msglvl = PLAYER_MSG_NONE;
+}
+
+static int
+handle_mpd_status(int status)
+{
+ player_clear_msg();
switch (status) {
- case MPD_ERROR_SYSTEM:
- PLAYER_STATUS(PLAYER_MSG_ERR, "%s",
- mpd_connection_get_error_message(conn));
- break;
case MPD_ERROR_SERVER:
case MPD_ERROR_ARGUMENT:
- if (!mpd_connection_clear_error(conn))
+ if (!mpd_connection_clear_error(player->conn))
PANIC("Player failed to recover from error");
- break;
+ case MPD_ERROR_SYSTEM:
+ PLAYER_STATUS(PLAYER_MSG_ERR, "%s",
+ mpd_connection_get_error_message(player->conn));
+ return 1;
case MPD_ERROR_CLOSED:
PANIC("Player encountered non-recoverable error");
- break;
}
+ return 0;
}
void
@@ -55,6 +66,8 @@ player_init(void)
player->track = NULL;
player->state = PLAYER_STATE_PAUSED;
+ player->next = NULL;
+
player->seek_delay = 0;
player->volume = 0;
@@ -63,8 +76,6 @@ player_init(void)
player->msg = NULL;
player->msglvl = PLAYER_MSG_INFO;
-
- // mpd_run_clear(player->conn);
}
void
@@ -77,7 +88,7 @@ player_free(void)
refs_free(&player->history);
refs_free(&player->queue);
- mpd_run_clear(player->conn);
+ //mpd_run_clear(player->conn);
mpd_connection_free(player->conn);
}
@@ -90,25 +101,32 @@ player_update(void)
const char *tmp;
if (player->action != PLAYER_ACTION_NONE) {
- mpd_run_clear(player->conn);
+ handle_mpd_status(mpd_run_clear(player->conn));
ref = NULL;
switch (player->action) {
case PLAYER_ACTION_PLAY_PREV:
- if (!list_empty(&player->history))
+ if (list_empty(&player->history))
break;
ref = UPCAST(list_pop_front(&player->history),
struct ref);
+
+ /* dont add current song to history */
+ player->track = NULL;
+
player_play_track(ref->data);
ref_free(ref);
break;
case PLAYER_ACTION_PLAY_NEXT:
- if (list_empty(&player->queue))
- break;
- ref = UPCAST(list_pop_front(&player->queue),
- struct ref);
- player_play_track(ref->data);
- ref_free(ref);
+ if (!list_empty(&player->queue)) {
+ ref = UPCAST(list_pop_front(&player->queue),
+ struct ref);
+ player_play_track(ref->data);
+ ref_free(ref);
+ } else if (player->next) {
+ player_play_track(player->next);
+ player->next = NULL;
+ }
break;
default:
PANIC();
@@ -147,10 +165,6 @@ player_update(void)
player->time_end = mpd_song_get_duration(song);
mpd_song_free(song);
} else {
- if (player->track) {
- list_push_front(&player->history,
- LINK(ref_init(player->track)));
- }
player->track = NULL;
player->loaded = false;
player->time_pos = 0;
@@ -196,17 +210,25 @@ player_queue_insert(struct track *track, size_t pos)
int
player_play_track(struct track *track)
{
- player_clear_msg();
+ struct link *link;
+ int status;
+
+ player->next = NULL;
+ if (player->track && player->track != track) {
+ list_push_front(&player->history,
+ LINK(ref_init(player->track)));
+ }
+
player->track = track;
- mpd_run_stop(player->conn);
- mpd_run_clear(player->conn);
+ handle_mpd_status(mpd_run_clear(player->conn));
- if (!mpd_run_add(player->conn, player->track->fpath)
- || !mpd_run_play(player->conn)) {
- PLAYER_STATUS(PLAYER_MSG_ERR, "Playback failed");
- mpd_run_clearerror(player->conn);
+ status = mpd_run_add(player->conn, player->track->fpath);
+ if (handle_mpd_status(status))
+ return PLAYER_ERR;
+
+ status = mpd_run_play(player->conn);
+ if (handle_mpd_status(status))
return PLAYER_ERR;
- }
return PLAYER_OK;
}
@@ -214,11 +236,11 @@ player_play_track(struct track *track)
int
player_toggle_pause(void)
{
- if (!mpd_run_toggle_pause(player->conn)) {
- PLAYER_STATUS(PLAYER_MSG_ERR, "Pause toggle failed");
- mpd_run_clearerror(player->conn);
+ int status;
+
+ status = mpd_run_toggle_pause(player->conn);
+ if (handle_mpd_status(status))
return PLAYER_ERR;
- }
return PLAYER_OK;
}
@@ -226,11 +248,11 @@ player_toggle_pause(void)
int
player_pause(void)
{
- if (!mpd_run_pause(player->conn, true)) {
- PLAYER_STATUS(PLAYER_MSG_ERR, "Pausing track failed");
- mpd_run_clearerror(player->conn);
+ int status;
+
+ status = mpd_run_pause(player->conn, true);
+ if (handle_mpd_status(status))
return PLAYER_ERR;
- }
return PLAYER_OK;
}
@@ -238,11 +260,11 @@ player_pause(void)
int
player_resume(void)
{
- if (!mpd_run_pause(player->conn, false)) {
- PLAYER_STATUS(PLAYER_MSG_ERR, "Resuming track failed");
- mpd_run_clearerror(player->conn);
+ int status;
+
+ status = mpd_run_pause(player->conn, false);
+ if (handle_mpd_status(status))
return PLAYER_ERR;
- }
return PLAYER_OK;
}
@@ -250,14 +272,6 @@ player_resume(void)
int
player_next(void)
{
- player_clear_msg();
-
- if (!player->loaded)
- return PLAYER_ERR;
-
- if (!mpd_run_clear(player->conn))
- return PLAYER_ERR;
-
player->action = PLAYER_ACTION_PLAY_NEXT;
return PLAYER_OK;
@@ -266,13 +280,6 @@ player_next(void)
int
player_prev(void)
{
- /* TODO prevent mpd from dying on error, how to use properly */
- if (!player->loaded)
- return PLAYER_ERR;
-
- if (!mpd_run_clear(player->conn))
- return PLAYER_ERR;
-
player->action = PLAYER_ACTION_PLAY_PREV;
return PLAYER_OK;
@@ -281,13 +288,11 @@ player_prev(void)
int
player_play(void)
{
- player_clear_msg();
+ int status;
- if (!mpd_run_play(player->conn)) {
- PLAYER_STATUS(PLAYER_MSG_ERR, "Playing track failed");
- mpd_run_clearerror(player->conn);
+ status = mpd_run_play(player->conn);
+ if (handle_mpd_status(status))
return PLAYER_ERR;
- }
return PLAYER_OK;
}
@@ -295,13 +300,11 @@ player_play(void)
int
player_stop(void)
{
- player_clear_msg();
+ int status;
- if (!mpd_run_stop(player->conn)) {
- PLAYER_STATUS(PLAYER_MSG_ERR, "Stopping track failed");
- mpd_run_clearerror(player->conn);
+ status = mpd_run_stop(player->conn);
+ if (handle_mpd_status(status))
return PLAYER_ERR;
- }
return PLAYER_OK;
}
@@ -309,20 +312,19 @@ player_stop(void)
int
player_seek(int sec)
{
- player_clear_msg();
+ int status;
+ player_clear_msg();
if (!player->loaded || player->state == PLAYER_STATE_STOPPED) {
- PLAYER_STATUS(PLAYER_MSG_ERR, "No track loaded");
+ PLAYER_STATUS(PLAYER_MSG_INFO, "No track loaded");
return PLAYER_ERR;
}
- if (!mpd_run_seek_current(player->conn, sec, false)) {
- PLAYER_STATUS(PLAYER_MSG_ERR, "Track seek failed");
- mpd_run_clearerror(player->conn);
+ status = mpd_run_seek_current(player->conn, sec, false);
+ if (handle_mpd_status(status))
return PLAYER_ERR;
- }
- player->seek_delay = 8;
+ player->seek_delay = 7;
player_pause();
return PLAYER_OK;
@@ -331,27 +333,18 @@ player_seek(int sec)
int
player_set_volume(unsigned int vol)
{
- player_clear_msg();
+ int status;
+ player_clear_msg();
if (player->volume == -1) {
- PLAYER_STATUS(PLAYER_MSG_INFO, "Setting volume not supported");
- mpd_run_clearerror(player->conn);
+ PLAYER_STATUS(PLAYER_MSG_INFO, "Volume control not supported");
return PLAYER_ERR;
}
- if (!mpd_run_set_volume(player->conn, vol)) {
- PLAYER_STATUS(PLAYER_MSG_ERR, "Setting volume failed");
- mpd_run_clearerror(player->conn);
+ status = mpd_run_set_volume(player->conn, vol);
+ if (handle_mpd_status(status))
return PLAYER_ERR;
- }
return PLAYER_OK;
}
-void
-player_clear_msg(void)
-{
- free(player->msg);
- player->msg = NULL;
- player->msglvl = PLAYER_MSG_NONE;
-}
diff --git a/src/player.h b/src/player.h
@@ -33,20 +33,39 @@ enum {
};
struct player {
+ /* TODO move implementation details to source file */
struct mpd_connection *conn;
struct link queue;
struct link history;
+
+ /* current loaded track */
struct track *track;
+ int loaded;
+
+ /* stopped, paused or playing */
int state;
+ /* TODO: replace with JIT solution */
+ /* track to play when queue is empty
+ * and player_next is called */
+ struct track *next;
+
+ /* automatically start playing player->next
+ * when queue is empty */
+ int autoplay;
+
int action;
+
+ /* number of frames to wait before unpausing after
+ * seek to prevent pause-play cycle noises */
int seek_delay;
- int loaded;
int volume;
+
unsigned int time_pos, time_end;
+ /* status messaging */
char *msg;
int msglvl;
};
@@ -72,7 +91,5 @@ int player_stop(void);
int player_set_volume(unsigned int vol);
-void player_clear_msg(void);
-
extern struct player *player;