aboutsummaryrefslogtreecommitdiff
path: root/vol
blob: 14425d7e7770cadb3d2d0730ea18cbfa8b28223a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#!/bin/sh

# vol - Adjust volume, with on-screen display.

# (c) 2020 B. Watson <urchlay@slackware.uk>
# 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 <<EOF
$SELF [up|down|mute|<nnn>]

<nnn> 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]