The terminal app Alsa allows you to audio volume programmatically. You can use it from within XMonad as a workaround when FN function keys don’t work by default.

On Ubuntu 18.04 there two terminal apps to control the volume, amixer and pactl. I use pactl (and amixer as a second option) as a workaround when i use XMonad on my Ubuntu notebook, because my FN function keys don’t work by default. The amixer app comes from the Alsa framework, which is an abstraction to use every sound card in more or less the same way, while pactl is part of PulseAudio, which is a sound server on top of Alsa to send sound-data from any input to any output, e.g., from your music app through an internet network to a remote speaker.

The amixer app comes preinstalled on Ubuntu 18.04 so you don’t have to install it manually. The pactl app should come preinstalled as well, but if it doesn’t, you can install it with

sudo apt install pulseaudio-utils pavucontrol

To see and select which audio devices the sound is coming from and send to, you should also install the graphical “PulseAudio Volume Control” pavucontrol app.

Just to make sure that that amixer is indeed installed, run in a terminal

amixer

You should see a an output like this:

Simple mixer control 'IEC958',0
  Capabilities: pswitch pswitch-joined
  Playback channels: Mono
  Mono: Playback [on]
...

To make sure that that pactl is indeed installed, run in a terminal

pactl

You should see a an output like this:

pactl [options] stat
pactl [options] info
pactl [options] list [short] [TYPE]
pactl [options] exit
pactl [options] upload-sample FILENAME [NAME]
...

Configure XMonad to use pactl or amixer

To actually use pactl within XMonad, add these lines into the list of keymaps in your XMonad config file:

import Graphics.X11.ExtraTypes.XF86

myKeys = [
-- ...
  , ((0, xF86XK_AudioMute), spawn "pactl set-sink-mute @DEFAULT_SINK@ toggle")
  , ((0, xF86XK_AudioLowerVolume), spawn "pactl set-sink-volume @DEFAULT_SINK@ -10%")
  , ((0, xF86XK_AudioRaiseVolume), spawn "pactl set-sink-volume @DEFAULT_SINK@ +10%")
-- ...
]

If you use the EZ keymap notation, use these lines:

myKeys = [
-- ...
  , ("<XF86AudioMute>", spawn "pactl set-sink-mute @DEFAULT_SINK@ toggle")
  , ("<XF86AudioLowerVolume>", spawn "pactl set-sink-volume @DEFAULT_SINK@ -10%")
  , ("<XF86AudioRaiseVolume>", spawn "pactl set-sink-volume @DEFAULT_SINK@ +10%")
-- ...
]
Explain the code
Code Note
import ... Make the functions and constants from a module available.
...XF86 Module that includes Haskell representations of multimedia keyboard keys.
xF86XK_AudioRaiseVolume Haskell representation of the “Brightness up” multimedia keyboard key.
spawn ".." Run an app or script. You can run anything that you can run in a terminal.
DEFAULT_SINK Device/Channel where audio data is sent to by default. Use pavucontrol to change the default device.

[How to configure XMonad?]

If you can’t control the volume, try this workaround.

To use amixer instead of pactl within XMonad (it still requires that you have the PulseAudio server installed), add these lines into the list of keymaps in your XMonad config file:

import Graphics.X11.ExtraTypes.XF86
myKeys = [
-- ...
  , ((0, xF86XK_AudioMute), spawn "amixer -D pulse set Master 1+ toggle")
  , ((0, xF86XK_AudioLowerVolume), spawn "amixer -D pulse set Master 10%-")
  , ((0, xF86XK_AudioRaiseVolume), spawn "amixer -D pulse set Master 10%+")
-- ...
]

If you use the EZ keymap notation, use these lines:

myKeys = [
-- ...
  , ("<XF86AudioMute>", spawn "amixer -D pulse set Master 1+ toggle")
  , ("<XF86AudioLowerVolume>", spawn "amixer -D pulse set Master 10%-")
  , ("<XF86AudioRaiseVolume>", spawn "amixer -D pulse set Master 10%+")
-- ...
]
If you still can’t control the volume, try this workaround.

To use amixer instead of pactl within XMonad (without the PulseAudio server at all), add these lines into the list of keymaps in your XMonad config file:

import Graphics.X11.ExtraTypes.XF86
myKeys = [
-- ...
  , ((0, xF86XK_AudioMute), spawn "amixer -q set PCM toggle")
  , ((0, xF86XK_AudioLowerVolume), spawn "amixer -q set PCM 1-")
  , ((0, xF86XK_AudioRaiseVolume), spawn "amixer -q set PCM 1+")
-- ...
]

If you use the EZ keymap notation, use these lines:

myKeys = [
-- ...
  , ("<XF86AudioMute>", spawn "amixer -q set PCM toggle")
  , ("<XF86AudioLowerVolume>", spawn "amixer -q set PCM 1-")
  , ("<XF86AudioRaiseVolume>", spawn "amixer -q set PCM 1+")
-- ...
]
Tags: xmonad ubuntu alsa pulseaudio haskell tutorial configuration

Malte Neuss

Java Software Engineer by day, Haskell enthusiast by night.

Other Posts In Series

Just Enough Haskell For XMonad

Configure a light-weight status bar for XMonad: Xmobar

The status bar Xmobar works out of the box on the top edge of your screen and shows useful system info. However, if you want to make it look nice and change what information to show, you can customize it with a tiny bit of Haskell.

Read More

Just Enough Haskell For XMonad

Control the screen brightness in XMonad with Lux

The terminal app Lux allows you to set the screen brightness programmatically. You can use it from within XMonad as a workaround when FN function keys don’t work by default.

Read More

Just Enough Haskell For XMonad

Replace XMonad's app launcher with a time-saving alternative: Yeganesh

The minimalistic app Yeganesh improves XMonad’s default app launcher with a small but time-saving feature: It shows your most frequently used apps first. So most of the time you will be able start an app by writing a single character.

Read More