diff options
Diffstat (limited to 'src/XMonad/Actions')
-rw-r--r-- | src/XMonad/Actions/Alsa.hs | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/src/XMonad/Actions/Alsa.hs b/src/XMonad/Actions/Alsa.hs new file mode 100644 index 0000000..362f73b --- /dev/null +++ b/src/XMonad/Actions/Alsa.hs @@ -0,0 +1,179 @@ +{-# LANGUAGE CPP #-} + +---------------------------------------------------------------------------- +-- | +-- Module : XMonad.Util.ALSA +-- Copyright : (c) daniel@wagner-home.com +-- License : BSD3-style (see LICENSE) +-- +-- Maintainer : daniel@wagner-home.com +-- Stability : unstable +-- Portability : unportable +-- +---------------------------------------------------------------------------- + +module XMonad.Util.ALSA + ( defaultChannels + + , toggleMute + , raiseVolume + , lowerVolume + + , getVolume + , getMute + , getVolumeMute + + , setVolume + , setMute + , setVolumeMute + + , modifyVolume + , modifyMute + , modifyVolumeMute + + + , toggleMuteChannels + , raiseVolumeChannels + , lowerVolumeChannels + + , getVolumeChannels + , getMuteChannels + , getVolumeMuteChannels + + , setVolumeChannels + , setMuteChannels + , setVolumeMuteChannels + + , modifyVolumeChannels + , modifyMuteChannels + , modifyVolumeMuteChannels + ) where + +import Control.Monad +import Control.Monad.Trans +import Data.Maybe +import Sound.ALSA.Mixer + +defaultChannels :: [String] +defaultChannels = ["Master", "Headphone", "Speaker", "PCM"] + +toggleMute :: MonadIO m => m Bool +raiseVolume :: MonadIO m => Double -> m Double +lowerVolume :: MonadIO m => Double -> m Double +toggleMute = toggleMuteChannels defaultChannels +raiseVolume = raiseVolumeChannels defaultChannels +lowerVolume = lowerVolumeChannels defaultChannels + +getVolume :: MonadIO m => m Double +getMute :: MonadIO m => m Bool +getVolumeMute :: MonadIO m => m (Double, Bool) +getVolume = getVolumeChannels defaultChannels +getMute = getMuteChannels defaultChannels +getVolumeMute = getVolumeMuteChannels defaultChannels + +setVolume :: MonadIO m => Double -> m () +setMute :: MonadIO m => Bool -> m () +setVolumeMute :: MonadIO m => Double -> Bool -> m () +setVolume = setVolumeChannels defaultChannels +setMute = setMuteChannels defaultChannels +setVolumeMute = setVolumeMuteChannels defaultChannels + +modifyVolume :: MonadIO m => (Double -> Double) -> m Double +modifyMute :: MonadIO m => (Bool -> Bool) -> m Bool +modifyVolumeMute :: MonadIO m => (Double -> Bool -> (Double, Bool)) -> m (Double, Bool) +modifyVolume = modifyVolumeChannels defaultChannels +modifyMute = modifyMuteChannels defaultChannels +modifyVolumeMute = modifyVolumeMuteChannels defaultChannels + +toggleMuteChannels :: MonadIO m => [String] -> m Bool +raiseVolumeChannels :: MonadIO m => [String] -> Double -> m Double +lowerVolumeChannels :: MonadIO m => [String] -> Double -> m Double +toggleMuteChannels cs = modifyMuteChannels cs not +raiseVolumeChannels cs = modifyVolumeChannels cs . (+) +lowerVolumeChannels cs = modifyVolumeChannels cs . (subtract) + +getVolumeChannels :: MonadIO m => [String] -> m Double +getMuteChannels :: MonadIO m => [String] -> m Bool +getVolumeMuteChannels :: MonadIO m => [String] -> m (Double, Bool) +getVolumeChannels = liftIO . fmap fst . alsaGetAll +getMuteChannels = liftIO . fmap snd . alsaGetAll +getVolumeMuteChannels = liftIO . alsaGetAll + +setVolumeChannels :: MonadIO m => [String] -> Double -> m () +setMuteChannels :: MonadIO m => [String] -> Bool -> m () +setVolumeMuteChannels :: MonadIO m => [String] -> Double -> Bool -> m () +setVolumeChannels cs v = liftIO (alsaSetVolumeAll v cs) +setMuteChannels cs m = liftIO (alsaSetMuteAll m cs) +setVolumeMuteChannels cs v m = liftIO (alsaSetAll v m cs) + +modifyVolumeChannels :: MonadIO m => [String] -> (Double -> Double) -> m Double +modifyMuteChannels :: MonadIO m => [String] -> (Bool -> Bool) -> m Bool +modifyVolumeMuteChannels :: MonadIO m => [String] -> (Double -> Bool -> (Double, Bool)) -> m (Double, Bool) +modifyVolumeChannels = modify getVolumeChannels setVolumeChannels +modifyMuteChannels = modify getMuteChannels setMuteChannels +modifyVolumeMuteChannels cs = modify getVolumeMuteChannels (\cs' -> uncurry (setVolumeMuteChannels cs')) cs . uncurry + +geomMean :: Floating a => [a] -> a +geomMean xs = product xs ** (recip . fromIntegral . length $ xs) + +clip :: (Num t, Ord t) => t -> t +clip = min 100 . max 0 + +toRange :: (Integer, Integer) -> Double -> Integer +toRange (x, y) d = floor (d * (y' - x') / 100 + x') + where x' = fromIntegral x + y' = fromIntegral y + +fromRange :: (Integer, Integer) -> Integer -> Double +fromRange (x, y) z = fromIntegral (z - x) / fromIntegral (y - x) * 100 + +modify :: Monad m => (arg -> m value) -> (arg -> value -> m ()) -> arg -> (value -> value) -> m value +modify get set cs f = do + v <- liftM f $ get cs + set cs v + return v + +withControl :: (Control -> IO a) -> [String] -> IO a +withControl f cs = withMixer "default" $ \mixer -> do + (control:_) <- catMaybes <$> mapM (getControlByName mixer) cs + f control + +alsaGetAll :: [String] -> IO (Double, Bool) +alsaGetAll = withControl $ \control -> (,) <$> alsaGetVolume control <*> alsaGetMute control + +alsaGetVolume :: Control -> IO Double +alsaGetVolume control = do + let Just playbackVolume = playback $ volume control + volChans = value playbackVolume + range <- getRange playbackVolume + vals <- mapM (\chan -> getChannel chan volChans) (channels volChans) + return $ geomMean $ map (fromRange range . fromJust) vals + +alsaGetMute :: Control -> IO Bool +alsaGetMute control = do + let Just muteChans = playback $ switch control + all id . map fromJust <$> mapM (\chan -> getChannel chan muteChans) (channels muteChans) + +alsaSetVolumeAll :: Double -> [String] -> IO () +alsaSetVolumeAll v = withControl (alsaSetVolume v) + +alsaSetVolume :: Double -> Control -> IO () +alsaSetVolume v control = do + let Just playbackVolume = playback $ volume control + volChans = value playbackVolume + range <- getRange playbackVolume + forM_ (channels volChans) $ \chan -> do + setChannel chan volChans (toRange range (clip v)) + +alsaSetMuteAll :: Bool -> [String] -> IO () +alsaSetMuteAll m = withControl (alsaSetMute m) + +alsaSetMute :: Bool -> Control -> IO () +alsaSetMute m control = do + let Just muteChans = playback $ switch control + forM_ (channels muteChans) $ \chan -> setChannel chan muteChans m + +alsaSetAll :: Double -> Bool -> [String] -> IO () +alsaSetAll v m = withControl $ \control -> do + alsaSetVolume v control + alsaSetMute m control |