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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
|
#!/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 aosd_cat (on Slackware, libaosd from SBo).
# 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 (try XF86AudioRaiseVolume, XF86AudioLowerVolume, and
# XF86AudioMute). 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, % percentage, no suffix for raw units (on one of my
# sound cards, the raw unit range is 0 to 87; on another, 0-127).
ADJ=1%
# Pango font string, see:
# https://docs.gtk.org/Pango/type_func.FontDescription.from_string.html
# The size is in points; 30px would be pixels.
FONT="Mono Normal 30"
# What color is the OSD bar and text? See /usr/share/X11/rgb.txt,
# or use hex escapes (with #).
# COLOR is for when we're unmuted, MUTECOLOR is for muted.
COLOR='#00ff00'
MUTECOLOR='#ff0000'
# How long does the OSD persist? In milliseconds.
DELAY=2000
# 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"
BLOCKS="██████████████████████████████████████████████████"
BLANKS="──────────────────────────────────────────────────"
PARTIAL="▌"
# progress() prints a UTF-8 progress bar with 50 characters.
# takes a percentage, 0 to 100
progress() {
local text="$1"
local count="$2"
local solidblocks
local partial
local trailing
solidblocks="$(( $count / 2 ))"
partial="$(( $count % 2 ))"
trailing="$(( 50 - ( $solidblocks + $partial) ))"
echo -n "$text${BLOCKS:0:$solidblocks}"
[ "$partial" = "1" ] && echo -n $PARTIAL
echo -n "${BLANKS:0:$trailing}"
}
# osd() will kill any previously-spawned aosd_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 color="$COLOR"
local text="$( printf "%8s" $db) $( printf "%-3s" $volpct% ) "
local oldpid
if [ -n "$muted" ]; then
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 '^aosd_cat' /proc/$oldpid/cmdline 2>/dev/null && \
kill -9 "$oldpid" 2>/dev/null
rm -f $PIDFILE
fi
# TODO: make these variables in the config section rather than
# hardcoding them.
progress "$text" "$volpct" | \
aosd_cat \
--fore-color $color \
--back-color '#808080' \
--font "$FONT" \
--output 1 \
--x-offset 159 \
--y-offset 0 \
--position 7 \
--transparency 1 \
--back-opacity 128 \
--padding 7 \
--alignment 0 \
--fade-in 0 \
--fade-out 0 \
--fade-full $DELAY &
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|<nn>]
<nn> is a numeric volume, possibly followed by "dB" or "%", 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 aosd_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
|