https://alexanderacker-com.github.io/blog/feed.xml

Music player minimalism

2024-02-05

After installing Arch Linux and beginning to use it again for the fourth or so time I've given myself a new challenge. Try to eliminate packages that I feel like are unnecessary. I like foobar2000 but it's a Windows program and I only use a small subset of its features. I don't really have a lot of experience with Linux music playing software and have tried to avoid it. Avoiding a proper music player has resulted in me doing some funny things.

The first music player (a shell script)

The idea is to make a shell script that can do at least the following:

  • Recursively find files according to some pattern
  • Loop a list of files
  • Shuffle a list of files
  • Set the volume

I chose gstreamer a multimedia framework for handling the file reading, decoding, playing of audio files which is built around the idea of a configurable pipeline as the method of playing the files.

Here is the source code to play-audio.sh

#!/bin/sh

usage() {
    echo "Usage: $0 <AUDIO_FILE_OR_GLOB> [LOOP=false]|[shuffle] [VOLUME=1.0]"
    echo "Simple GStreamer pipeline to play audio to your default audio output"
    exit 1
}

if [[ $# -eq 0 ]]; then
    usage
fi

loop=0
shuffle=0
file_reorder="sort -z"
if [[ $# -ge 2 ]]; then
    case "$2" in
        loop)
            loop=1
            ;;
        shuffle)
            loop=1
            shuffle=1
            file_reorder="shuf -z"
            ;;
        *)
            usage
    esac
fi

files="$1"
if [[ $1 == *\*** ]]; then
    files="$(find . -name "$1" -type f -print0 | $file_reorder | xargs -n1 -d '\0')"
fi


vol_elem="identity"
if [[ $# -eq 3 ]]; then
    vol_elem="volume volume=$3"
fi

finish() {
    exit 1
}
trap finish INT

while true; do
    # play the playlist
    while IFS= read -r file; do
        echo "Playing $(basename "$file")"
        gst-launch-1.0 --quiet filesrc location="$file" ! decodebin ! audioconvert ! $vol_elem ! autoaudiosink
    done <<< "$files"
    # shuffle the playlist if shuffle is on
    if [[ $shuffle -eq 1 ]]; then
        if [[ $1 == *\*** ]]; then
            files="$(find . -name "$1" -type f -print0 | $file_reorder | xargs -n1 -d '\0')"
        fi
    fi
    [[ $loop -eq 1 ]] || break
done

This solution is pretty good but it has a few large glaring flaws:

  • No way to pause the audio or remember state
  • No playlist controls (skip, previous, etc..)
  • No way to change the volume once a song is playing

The second music player (a daemon)

The idea is to make a daemon that runs in the background and is commanded through a socket

I chose mpv specifically libmpv bindings in Rust as the audio playing backend.