Search code examples
haskellxmonad

XMonad Volume configuration not working


I recently got into XMonad and unforunately I don't know much Haskell at all. I'm trying to configure my xmonad.hs file such that I can control the volume. However, right now, even though my xmonad.hs file compiles without errors, I cannot control the volume.

I got the volume control code from this link:http://dmwit.com/volume/

Here is my configuration file:

import XMonad
import XMonad.Util.Run(spawnPipe)
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Actions.Volume
import XMonad.Util.Dzen
import Data.Map (fromList)
import Data.Monoid (mappend)
import System.IO

alert = dzenConfig centered . show . round
centered =
        onCurr (center 150 66)
    >=> font "-*-helvetica-*-r-*-*-64-*-*-*-*-*-*-*"
    >=> addArgs ["-fg", "#80c0ff"]
    >=> addArgs ["-bg", "#000040"]

main = do 
        xmproc <- spawnPipe "xmobar /home/david/.xmobarrc"
        xmonad $ defaultConfig
                {
                        manageHook = manageDocks <+> manageHook defaultConfig
                        , layoutHook = avoidStruts  $  layoutHook defaultConfig
                        , logHook = dynamicLogWithPP xmobarPP
                                { ppOutput = hPutStrLn xmproc
                                , ppTitle = xmobarColor "green" "" . shorten 50
                                }
                        , modMask = mod4Mask 
                        , keys =
                            keys defaultConfig `mappend`
                            \c -> fromList [
                                ((0, xK_F6), lowerVolume 4 >>= alert),
                                ((0, xK_F7), raiseVolume 4 >>= alert)
                            ]
                }

I have changed my code the following, however the volume has not changed:

main = do 
    xmproc <- spawnPipe "xmobar /home/luren/.xmobarrc"
    xmonad $ defaultConfig
            {
                    manageHook = manageDocks <+> manageHook defaultConfig
                    , layoutHook = avoidStruts  $  layoutHook defaultConfig
                    , logHook = dynamicLogWithPP xmobarPP
                            { ppOutput = hPutStrLn xmproc
                            , ppTitle = xmobarColor "green" "" . shorten 50
                            }
                    , modMask = mod4Mask 
                    , keys =
                        keys defaultConfig `mappend`
                        \c -> fromList [
                            ((0, 0x1008FF11), spawn "amixer -D pulse sset Master 4-"),
                            ((0, 0x1008FF13), spawn "amixer -D pulse sset Master 4+")
                        ]
            }

(END)

Those keys are the codes for the volume media keys on my laptop.

I snooped around and saw some other configurations. I decided to do a little test and make the audio lower volume key print Hi ppl! when pressed. Unfortunately, this does not work.

main = do 
    xmproc <- spawnPipe "xmobar /home/luren/.xmobarrc"
    xmonad $ defaultConfig
            {
                    manageHook = manageDocks <+> manageHook defaultConfig
                    , layoutHook = avoidStruts  $  layoutHook defaultConfig
                    , logHook = dynamicLogWithPP xmobarPP
                            { ppOutput = hPutStrLn xmproc
                            , ppTitle = xmobarColor "green" "" . shorten 50
                            }
                    , modMask = mod4Mask
            }
            `additionalKeys`
            [
                    ((0, xF86XK_AudioLowerVolume), spawn "echo 'Hi ppl!'"),
                    ((0, xF86XK_AudioRaiseVolume), spawn "amixer -D pulse sset Master 15%+")
            ]

Solution

  • Here is a script that I wrote to control pulse audio volume. Dump it in a file named pulse_control.pl and make sure it is executable and in your PATH. It uses pacmd and pactl which you may have to install with your distro's package manager.

    #!/usr/bin/perl
    
    use List::Util qw[min max];
    use Getopt::Long;
    
    my $_IS_MUTED;
    my $_TOGGLE_MUTE;
    my $_VOL;
    my $_INC_VOL;
    my $_DEC_VOL;
    
    GetOptions(
        "is-muted"    => \$_IS_MUTED
    ,   "toggle-mute" => \$_TOGGLE_MUTE
    ,   "volume"      => \$_VOL
    ,   "inc-vol"     => \$_INC_VOL
    ,   "dec-vol"     => \$_DEC_VOL
    );
    
    my $sink = `pactl info | sed -rn 's/^Default Sink: (.+)\$/\\1/gp'`;
    chomp $sink;
    
    sub ismuted {
        my $ismuted = `pacmd dump | grep "$sink" | grep sink-mute | grep yes`;
        chomp $ismuted;
        if ($ismuted ne "") {
            return 1;
        } else {
            0;
        }
    }
    
    sub curvol {
        my $volline = `pacmd dump | grep "$sink" | grep sink-vol`;
        if ($volline =~ m/(0x[0-9a-f]+)/ ) {
            return hex $1;
        } else {
            return 0;
        }
    }
    
    if ($_IS_MUTED) {
        print ismuted(), "\n";
    }
    elsif($_TOGGLE_MUTE) {
        if (ismuted()) {
            `pactl set-sink-mute $sink 0`;
        } else {
            `pactl set-sink-mute $sink 1`;
        }
    }
    elsif($_VOL) {
        print int(curvol() * 100.0 / hex("0x10000")), "%\n";
    }
    elsif($_INC_VOL) {
        my $newvol = min(hex("0x10000"), curvol() + int((hex("0x10000") * .04)));
        `pactl set-sink-volume $sink $newvol`;
    }
    elsif($_DEC_VOL) {
        my $newvol = max(0, curvol() - int((hex("0x10000") * .04)));
        `pactl set-sink-volume $sink $newvol`;
    }
    

    Then in my xmonad config, I have volume control bound to ctrl+alt+(page up/page down/end).

    `additionalKeys`
    [
        ((controlMask .|. mod1Mask, xK_Page_Up), spawn "pulse_control.pl -inc")
    ,   ((controlMask .|. mod1Mask, xK_Page_Down), spawn "pulse_control.pl -dec")
    ,   ((controlMask .|. mod1Mask, xK_End), spawn "pulse_control.pl -toggle")
    ]