tmus

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

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:
Msrc/list.c | 1+
Msrc/main.c | 60++++++++++++++++++++++++++++++++----------------------------
Msrc/player.c | 171++++++++++++++++++++++++++++++++++++++-----------------------------------------
Msrc/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;