CLI volume MUTE script in FreeBSD

CLI volume control

I like window managers (WMs) like spectrwm and like many of its kin, you have to set up media keys manually. There are two parts to this: (1) telling the WM what thing to do when a key is struck, and (2) do the thing.

Part (1) is easy; for example in spectrwm it’s

bind[vol_mt] = XF86AudioMute

where we’re making a function called vol_mt (aka volume mute) where the input is the mute key on your keyboard.

Part (2) isn’t so bad either, it’s

program[vol_mt] = ~/bin/volmt.sh

where we’re saying that the vol_mt function triggers the script called volmt.sh.

This is where it’s tricky on FreeBSD, because while Linux has amixer(1) and amixer has a mute toggle feature, there’s no mute toggle in FreeBSD’s mixer(8) program. So when you mute the mixer, your only option is to drop the volume to 0, but then unmuting means clicking all the way back to your listening volume from 0. Click-click-click-click… Not ideal.

Thanks to a post on the FreeBSD forum though, there’s a clever workaround: mixer actually has more than one ‘master’ volume control. There’s one called vol and one called pcm (and another called ogain which we’ll skip). Tapping into both means you can use pcm to set your volume up and down as you wish:

mixer pcm +1
mixer pcm -1

but use your mute button to set the vol to either 0 or 100 (meaning mute or unmute) while still preserving your ‘master’ volume (aka pcm) setting. We’re only a bash script away:

#!/bin/sh

STATE=$(mixer | awk 'NR==1{print substr($7,1,3)}')
if [ $STATE != "100" ]
then
    mixer vol 100 > /dev/null 2>&1
else
    mixer vol 0 > /dev/null 2>&1
fi

In words, I’m saying the STATE variable is set to mixer’s vol value. If that value is 100, I know the audio is not muted so set vol to 0. Conversely if vol is not 100, I know the audio is muted so set vol to 100. And the /dev/null business just keeps stdout and stderr from echoing what they’re doing.

If you use this script, just tweak the awk command to capture the actual output of your mixer command.

And there was much rejoicing.