#!/bin/sh # vol - Adjust volume, with on-screen display. # (c) 2020 B. Watson # Released under the WTFPL, see http://www.wtfpl.net/txt/copying/ # Requires xosd. # Intended for use with xbindkeys, like so: #$ cat ~/.xbindkeysrc #"vol up &" # Control+Alt + Prior # #"vol down &" # Control+Alt + Next # #"vol mute &" # Control+Alt + Pause # "Next" and "Prior" are PageDown and PageUp. Replace with "Up" and "Down" # to use arrow keys. If you have multimedia keys, you can probably use # them. See xbindkeys(1). # Can also be used from the command line. Run with no args for help. # -------------------- # Configurable options # -------------------- # Should be "Master" for most (all?) cards. Use "amixer scontrols" to # get a list. CHANNEL=Master # Each up/down adjustment is by this much. Use the dB suffix if you # prefer decibels, or leave it off for percentage. ADJ=3dB # osd_cat seems a bit picky about what fonts it'll use. If you give a # nonexistent font, it won't run at all. If you give a font it "doesn't # like", you'll see the percentage bar, but no "Volume" text. FONT=12x24 # What color is the OSD bar and text? See /usr/share/X11/rgb.txt. # COLOR is for when we're unmuted, MUTECOLOR is for muted. COLOR=orange MUTECOLOR=red # Text drop shadow, 0 to disable. SHADOW=3 # Where does the OSD show up on screen? One of: top middle bottom POSITION=bottom # How long does the OSD persist? In seconds, integer only. DELAY=2 # amixer options. Could use -c, -D here. Don't use -q. # default is "-M", see amixer(1). AMIXER_OPTS="-M" # ------------------------------------------ # End of configurable options, rest is code. # ------------------------------------------ SELF="$( basename $0 )" PIDFILE="$HOME/.$SELF.osd.pid" # osd() will kill any previously-spawned osd_cat process. Ideally this # means rapid multiple keypresses won't "step on" each other. In practice # it seems to work OK, but if you press the key really fast on a slow # system, or hold it down with your key-repeat rate cranked up (on any # system), the OSD bar will never get a chance to display. osd() { local got="$( amixer $AMIXER_OPTS get $CHANNEL | tail -1 )" local muted="$( echo "$got" | grep '\[off\]$' )" local volpct="$( echo "$got" | cut -d'[' -f2 | cut -d% -f1 )" local db="$( echo "$got" | cut -d'[' -f3 | cut -d']' -f1 )" local text="Volume $db ($volpct%)" local color="$COLOR" local oldpid if [ -n "$muted" ]; then text="$text [Muted]" color="$MUTECOLOR" fi # the silliness with grepping in /proc is meant to avoid stale PID # files whose PIDs have been recycled. if [ -e $PIDFILE ]; then oldpid="$( cat $PIDFILE )" grep -q '^osd_cat' /proc/$oldpid/cmdline 2>/dev/null && \ kill "$oldpid" 2>/dev/null fi osd_cat -b percentage \ -d $DELAY \ -P $volpct \ -p $POSITION \ -c $color \ -s $SHADOW \ -f $FONT \ -T "$text" & echo "$!" > $PIDFILE } amixer_set() { amixer -q $AMIXER_OPTS set $CHANNEL $1 } vol() { amixer_set ${ADJ}${1} } mute() { amixer_set toggle } usage() { cat <] is a numeric volume, possibly followed by "dB" and/or "+" or "-". It will be passed to 'amixer $AMIXER_OPTS set $CHANNEL' as-is. EOF exit 1 } check_deps() { local missing="no" for dep in osd_cat amixer; do if ! type -p "$dep" > /dev/null; then echo "$SELF: missing required executable '$dep'" 1>&2 missing="yes" fi done if [ "$missing" = "yes" ]; then echo "$SELF: please install the missing executable(s)" 1>&2 exit 1 fi } ###main() check_deps case "$1" in up) vol + ;; down) vol - ;; mute) mute ;; [0-9]*) amixer_set "$1" ;; *) usage ;; esac osd exit 0 # For reference: #$ amixer get Master #Simple mixer control 'Master',0 # Capabilities: pvolume pvolume-joined pswitch pswitch-joined # Playback channels: Mono # Limits: Playback 0 - 87 # Mono: Playback 31 [36%] [-42.00dB] [on]