5

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%+")
            ]
mrQWERTY
  • 4,039
  • 13
  • 43
  • 91
  • Yikes, it's been ages since I've written that page! I wouldn't be surprised if the output of `amixer` has changed in an incompatible way since then. (I've moved from ALSA to pulse.) But, to check: if you bind some key to `getVolume >>= alert`, does it show the correct answer? Does changing volumes on the command line with `amixer` change your volume? What channel in `alsamixer` (if any) actually controls your volume correctly? – Daniel Wagner Mar 30 '15 at 00:55
  • Oh wow! You actually wrote that page! I binded a key as you said, and unfortunately nothing shows up. I apologize if for me being a newbie at this, but I don't understand what alsa or pulse is. I know that if I use the following command in the terminal, amixer -D pulse sset Master 15%, I can set the volume. As for channel in alsamixer, I'm not sure what that means. I ran alsamixer which led me to three s/pdif. I think that stands for Sony/Philips digital interface. – mrQWERTY Mar 30 '15 at 01:08
  • Ah, unfortunately, that module doesn't support controlling a specific device (and doesn't have a good way to munge the `amixer` command line by hand). You have a couple choices: copy the code from the module and fix it (the work of 10 seconds, but not usable by others); patch `xmonad-extras` to add this functionality (a bit more work, but I will happily include your patch, and others will be able to benefit); use `pacmd` instead of touching `amixer` at all (much more work if you want an on-screen volume display after you change it). Which do you want to hear more about? – Daniel Wagner Mar 30 '15 at 01:14
  • Hmm, sorry for the delay. Its possible to directly call amixer from the script right? Unfortunately, I've just started learning Haskell in my class coincidentally. So fixing and then patching something is probably out of my league at the moment. – mrQWERTY Mar 30 '15 at 02:21
  • Changing the module to include `-D pulse` in the `amixer` command line should be very, very easy -- just copy the module and look for all instances of `amixer` and change them. You can call `amixer` directly if you like; but then you might as well call `pacmd`, since presumably `amixer -D pulse` means you are using pulseaudio. I'm happy to talk about either approach. – Daniel Wagner Mar 30 '15 at 02:34
  • Can you talk more about the pacmd approach? It would be wonderful if there was a way to feed the get the display for volume working too. Although that wouldn't be a priority since I could just include the volume in xmobarr – mrQWERTY Mar 30 '15 at 02:58
  • Reading your updated question: I'm baffled why having your audio key spawn amixer directly didn't work. That seems like the (or at least, "a") core problem. Can you open `xev` and see what key it thinks you're pressing when you press your audio volume down key? – Daniel Wagner Apr 01 '15 at 00:25
  • xev outputs are extremely bizarre. Since my multimedia keys are executed via holding fn down, xev only outputs Fn and f2 or f3 depending on what is pressed. Only AudioMute gets recognized by xev. I booted into Unity, and my multimedia keys works like a charm. – mrQWERTY Apr 01 '15 at 05:26
  • Okay, so... bind to something like `(mod3Mask, xK_F2)` instead of `(0, xF86XK_AudioLowerVolume)`, where you should replace `mod3Mask` with the appropriate mask for your Fn key (which I can't guess without seeing your xev output). – Daniel Wagner Apr 01 '15 at 16:57

2 Answers2

4

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")
]
rarsa
  • 3
  • 3
fimad
  • 346
  • 2
  • 7
0

This can also be achieved using the following spawn:

      [ ((0, 0x1008FF11), spawn "amixer -q sset Master 2%-"),
        ((0, 0x1008FF13), spawn "amixer -q sset Master 2%+"),
        ((0, 0x1008FF12), spawn "amixer set Master toggle")]

These are multimedia keys but you could also use x86Vol binds instead of hex's.

Yashank
  • 743
  • 2
  • 7
  • 23