~q3cpma/mus

Suckless music player daemon

35e02a5 refactor: centralize error logging and cancel_flag check in decoder.c

~q3cpma pushed to ~q3cpma/mus git

20 hours ago

b42dbcb Sync genhtab and document future architecture in README

~q3cpma pushed to ~q3cpma/mus git

2 days ago

#mus

mus is a simple CLI client/daemon music player consuming a newline separated plaintext path (files or directories) playlist. It is formed of several independent parts:

  • mus_daemon: consume the playlist and play its items via mus_player.
  • mus_client: send commands to mus_player and receive its answers, read or modify the playlist.
  • mus_player: play audio files and answer to mus_client's commands. Notable features include gapless playback, ReplayGain support and event reporting. Format support: FLAC (16 bits), Vorbis and Opus; mono/stereo only.
  • mus_album_* and fair_shuf: optional album tools for random but fair album picking. These assume that your music directory arborescence stores its albums at depth 2.

A lemonbar status script can be found here (superseded by this, though).

#Usage examples

Launch the server with cat as status notification command:

$ mus_daemon -s cat &

then append two albums to the playlist and start issuing some commands to the player

$ printf '%s\n' ~/Music/album1/ ~/Music/album2/ | mus_client PL_APPEND
$ mus_client TOGGLE_PLAY_PAUSE
$ mus_client ALBUM_NEXT
$ mus_client PL_EDIT
...

See mus_player/IPC.txt for internal notes about the commands and their outputs.

If using the album tools, create the database and randomly fill the playlist (here, 100 random albums strongly weighted for "fairness", cf fair_shuf):

$ mus_album_db_create ~/Music
$ mus_album_rand -o '-e3' -n100 ~/Music | mus_client PL_APPEND

#Dependencies and portability

In addition to a POSIX environment, posix-build's requirements, and a GNU11 compiler (gcc or clang), you'll need the following:

  • libao
  • libflac, vorbisfile, opusfile (each optional)
  • socat
  • flock (util-linux, BSD base or port; cf this for other platforms)
  • ed (POSIX, but often missing from GNU/Linux distros)

In brief, at least GNU/Linux, *BSD and MacOS should work.

#Building and installation

To build and install mus (default values shown in brackets):

$ [CC=gcc] [LTO=false] [NATIVE=false] [USE_FLAC=true] [USE_OGG_VORBIS=false] [USE_OGG_OPUS=false] ./build.sh
$ [DESTDIR=] [PREFIX=/usr/local] ./build.sh install

To install the optional album tools:

$ [DESTDIR=] [PREFIX=/usr/local] ./build.sh albumtools_install

To uninstall:

# [DESTDIR=] [PREFIX=/usr/local] ./build.sh uninstall
# [DESTDIR=] [PREFIX=/usr/local] ./build.sh albumtools_uninstall

#TODO

  • Start paused option
  • Pause on device error
  • mp3 support via libmpg123
  • Architecture rework:
    • Internal pipe -> concurrent ring buffer + simple buffer pool (much less copying around, no syscalls and no more CLOEXEC/EINTR/etc... headaches)
    • Thread 0 event loop (IPC & libao)
      • If status_cmd_pid != -1, try to reap (WNOHANG)
      • Process all pending IPC queries
        • TRACK_NEXT:
          • Send "stop" to T1
          • Drain PCM queue until "track change" event
        • TRACK_PREV or TRACK_FIRST:
          • Send "prev" or "0" to T2's "track jump" queue
          • Send "stop and jump" to T1 (stop current Decoder and discard next from T2)
        • TRACK_REWIND:
          • Send "rewind" to T1 (implement in all backends as seek 0)
      • If not paused
        • Pop PCM/track change queue
          • If track change
            • Compare ao_sample_format with prev to see if device must be reopened
            • Exec STATUS cmd
          • Else (PCM buf), send to ao_play
    • Thread 1 event loop (decoder)
      • Try pop event queue from T0 and apply
      • If there is data to decode do it and enqueue resulting PCM buffer(s)
      • Else pop Decoder queue, signal T0 and set global "current track"
    • Thread 2 event loop (background next track Decoder creation)
      • Try pop "track jump" queue from T0
      • Create decoder and push to T1 via queue of size 1
    • FLAC -> process frame per frame to centralize cancellation checking in the event loop
  • Man pages ?