-----------------------------------------------------------------------------
-- |
-- Module      :  Plugins.Monitors.Volume
-- Copyright   :  (c) 2011, 2013, 2015, 2018, 2020 Thomas Tuegel
-- License     :  BSD-style (see LICENSE)
--
-- Maintainer  :  Jose A. Ortega Ruiz <jao@gnu.org>
-- Stability   :  unstable
-- Portability :  unportable
--
-- A monitor for ALSA soundcards
--
-----------------------------------------------------------------------------

module Xmobar.Plugins.Monitors.Volume
  ( runVolume
  , runVolumeWith
  , volumeConfig
  , options
  , defaultOpts
  , VolumeOpts
  ) where

import Control.Applicative ( liftA3 )
import Control.Monad ( liftM2, liftM3, mplus )
import Xmobar.Plugins.Monitors.Common
import Sound.ALSA.Mixer
import qualified Sound.ALSA.Exception as AE
import System.Console.GetOpt


volumeConfig :: IO MConfig
volumeConfig :: IO MConfig
volumeConfig =
    String -> [String] -> IO MConfig
mkMConfig
        String
"Vol: <volume>% <status>"
        [ String
"volume"
        , String
"volumebar"
        , String
"volumevbar"
        , String
"dB"
        , String
"status"
        , String
"volumeipat"
        , String
"volumestatus"
        ]

data VolumeOpts = VolumeOpts
    { VolumeOpts -> String
onString :: String
    , VolumeOpts -> String
offString :: String
    , VolumeOpts -> Maybe String
onColor :: Maybe String
    , VolumeOpts -> Maybe String
offColor :: Maybe String
    , VolumeOpts -> Float
highDbThresh :: Float
    , VolumeOpts -> Float
lowDbThresh :: Float
    , VolumeOpts -> Maybe IconPattern
volumeIconPattern :: Maybe IconPattern
    , VolumeOpts -> Maybe Float
lowVolThresh :: Maybe Float
    , VolumeOpts -> Maybe Float
highVolThresh :: Maybe Float
    , VolumeOpts -> String
lowString :: String
    , VolumeOpts -> String
mediumString :: String
    , VolumeOpts -> String
highString :: String
    }

defaultOpts :: VolumeOpts
defaultOpts :: VolumeOpts
defaultOpts = VolumeOpts
    { onString :: String
onString = String
"[on] "
    , offString :: String
offString = String
"[off]"
    , onColor :: Maybe String
onColor = String -> Maybe String
forall a. a -> Maybe a
Just String
"green"
    , offColor :: Maybe String
offColor = String -> Maybe String
forall a. a -> Maybe a
Just String
"red"
    , highDbThresh :: Float
highDbThresh = -Float
5.0
    , lowDbThresh :: Float
lowDbThresh = -Float
30.0
    , volumeIconPattern :: Maybe IconPattern
volumeIconPattern = Maybe IconPattern
forall a. Maybe a
Nothing
    , lowVolThresh :: Maybe Float
lowVolThresh = Float -> Maybe Float
forall a. a -> Maybe a
Just Float
20.0
    , highVolThresh :: Maybe Float
highVolThresh = Float -> Maybe Float
forall a. a -> Maybe a
Just Float
60.0
    , lowString :: String
lowString = String
""
    , mediumString :: String
mediumString = String
""
    , highString :: String
highString = String
""
    }

data VolumeStatus
    = VolLow
    | VolMedium
    | VolHigh
    | VolOff

-- | Set the volume status according to user set thresholds and the current
-- volume
getVolStatus :: Float -- ^ Low volume threshold, in [0,100]
             -> Float -- ^ High volume threshold, in  [0,100]
             -> Float -- ^ Current volume, in [0,1]
             -> VolumeStatus
getVolStatus :: Float -> Float -> Float -> VolumeStatus
getVolStatus Float
lo Float
hi Float
val'
    | Float
val Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
>= Float
hi = VolumeStatus
VolHigh
    | Float
val Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
>= Float
lo = VolumeStatus
VolMedium
    | Bool
otherwise = VolumeStatus
VolLow
  where
    val :: Float
val = Float
val' Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
100

options :: [OptDescr (VolumeOpts -> VolumeOpts)]
options :: [OptDescr (VolumeOpts -> VolumeOpts)]
options =
    [ String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"O" [String
"on"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { onString = x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"o" [String
"off"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { offString = x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"" [String
"lowd"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { lowDbThresh = read x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"" [String
"highd"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { highDbThresh = read x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"C" [String
"onc"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { onColor = Just x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"c" [String
"offc"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { offColor = Just x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"" [String
"volume-icon-pattern"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o ->
       VolumeOpts
o { volumeIconPattern = Just $ parseIconPattern x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"L" [String
"lowv"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { lowVolThresh = Just $ read x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"H" [String
"highv"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { highVolThresh = Just $ read x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"l" [String
"lows"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { lowString = x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"m" [String
"mediums"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { mediumString = x }) String
"") String
""
    , String
-> [String]
-> ArgDescr (VolumeOpts -> VolumeOpts)
-> String
-> OptDescr (VolumeOpts -> VolumeOpts)
forall a. String -> [String] -> ArgDescr a -> String -> OptDescr a
Option String
"h" [String
"highs"] ((String -> VolumeOpts -> VolumeOpts)
-> String -> ArgDescr (VolumeOpts -> VolumeOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x VolumeOpts
o -> VolumeOpts
o { highString = x }) String
"") String
""
    ]

percent :: Integer -> Integer -> Integer -> Float
percent :: Integer -> Integer -> Integer -> Float
percent Integer
v' Integer
lo' Integer
hi' = (Float
v Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float
lo) Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ (Float
hi Float -> Float -> Float
forall a. Num a => a -> a -> a
- Float
lo)
  where v :: Float
v = Integer -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
v'
        lo :: Float
lo = Integer -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
lo'
        hi :: Float
hi = Integer -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
hi'

formatVol :: Integer -> Integer -> Integer -> Monitor String
formatVol :: Integer -> Integer -> Integer -> Monitor String
formatVol Integer
lo Integer
hi Integer
v =
    Float -> Monitor String
showPercentWithColors (Float -> Monitor String) -> Float -> Monitor String
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Integer -> Float
percent Integer
v Integer
lo Integer
hi

formatVolBar :: Integer -> Integer -> Integer -> Monitor String
formatVolBar :: Integer -> Integer -> Integer -> Monitor String
formatVolBar Integer
lo Integer
hi Integer
v =
    Float -> Float -> Monitor String
showPercentBar (Float
100 Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
x) Float
x where x :: Float
x = Integer -> Integer -> Integer -> Float
percent Integer
v Integer
lo Integer
hi

formatVolVBar :: Integer -> Integer -> Integer -> Monitor String
formatVolVBar :: Integer -> Integer -> Integer -> Monitor String
formatVolVBar Integer
lo Integer
hi Integer
v =
    Float -> Float -> Monitor String
showVerticalBar (Float
100 Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
x) Float
x where x :: Float
x = Integer -> Integer -> Integer -> Float
percent Integer
v Integer
lo Integer
hi

formatVolDStr :: Maybe IconPattern -> Integer -> Integer -> Integer -> Monitor String
formatVolDStr :: Maybe IconPattern
-> Integer -> Integer -> Integer -> Monitor String
formatVolDStr Maybe IconPattern
ipat Integer
lo Integer
hi Integer
v =
    Maybe IconPattern -> Float -> Monitor String
showIconPattern Maybe IconPattern
ipat (Float -> Monitor String) -> Float -> Monitor String
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Integer -> Float
percent Integer
v Integer
lo Integer
hi

switchHelper :: VolumeOpts
             -> (VolumeOpts -> Maybe String)
             -> (VolumeOpts -> String)
             -> VolumeStatus
             -> Monitor String
switchHelper :: VolumeOpts
-> (VolumeOpts -> Maybe String)
-> (VolumeOpts -> String)
-> VolumeStatus
-> Monitor String
switchHelper VolumeOpts
opts VolumeOpts -> Maybe String
cHelp VolumeOpts -> String
strHelp VolumeStatus
vs = String -> Monitor String
forall a. a -> ReaderT MConfig IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> Monitor String) -> String -> Monitor String
forall a b. (a -> b) -> a -> b
$
    Maybe String -> String
colorHelper (VolumeOpts -> Maybe String
cHelp VolumeOpts
opts)
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ VolumeStatus -> VolumeOpts -> String
volHelper VolumeStatus
vs VolumeOpts
opts
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ VolumeOpts -> String
strHelp VolumeOpts
opts
    String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> (String -> String) -> Maybe String -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"" (String -> String -> String
forall a b. a -> b -> a
const String
"</fc>") (VolumeOpts -> Maybe String
cHelp VolumeOpts
opts)

formatSwitch :: VolumeOpts -> Bool -> VolumeStatus -> Monitor String
formatSwitch :: VolumeOpts -> Bool -> VolumeStatus -> Monitor String
formatSwitch VolumeOpts
opts Bool
True  VolumeStatus
vs = VolumeOpts
-> (VolumeOpts -> Maybe String)
-> (VolumeOpts -> String)
-> VolumeStatus
-> Monitor String
switchHelper VolumeOpts
opts VolumeOpts -> Maybe String
onColor  VolumeOpts -> String
onString  VolumeStatus
vs
formatSwitch VolumeOpts
opts Bool
False VolumeStatus
_  = VolumeOpts
-> (VolumeOpts -> Maybe String)
-> (VolumeOpts -> String)
-> VolumeStatus
-> Monitor String
switchHelper VolumeOpts
opts VolumeOpts -> Maybe String
offColor VolumeOpts -> String
offString VolumeStatus
VolOff

-- | Convert the current volume status into user defined strings
volHelper :: VolumeStatus -> VolumeOpts -> String
volHelper :: VolumeStatus -> VolumeOpts -> String
volHelper VolumeStatus
volStatus VolumeOpts
opts =
    case VolumeStatus
volStatus of
        VolumeStatus
VolHigh -> VolumeOpts -> String
highString VolumeOpts
opts
        VolumeStatus
VolMedium -> VolumeOpts -> String
mediumString VolumeOpts
opts
        VolumeStatus
VolLow -> VolumeOpts -> String
lowString VolumeOpts
opts
        VolumeStatus
VolOff -> String
""

colorHelper :: Maybe String -> String
colorHelper :: Maybe String -> String
colorHelper = String -> (String -> String) -> Maybe String -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"" (\String
c -> String
"<fc=" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
c String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
">")

formatDb :: VolumeOpts -> Integer -> Monitor String
formatDb :: VolumeOpts -> Integer -> Monitor String
formatDb VolumeOpts
opts Integer
dbi = do
    h <- Selector (Maybe String) -> Monitor (Maybe String)
forall a. Selector a -> Monitor a
getConfigValue Selector (Maybe String)
highColor
    m <- getConfigValue normalColor
    l <- getConfigValue lowColor
    d <- getConfigValue decDigits
    let db = Integer -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
dbi Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
100.0
        digits = Int -> Float -> String
forall a. RealFloat a => Int -> a -> String
showDigits Int
d Float
db
        startColor | Float
db Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
>= VolumeOpts -> Float
highDbThresh VolumeOpts
opts = Maybe String -> String
colorHelper Maybe String
h
                   | Float
db Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< VolumeOpts -> Float
lowDbThresh VolumeOpts
opts = Maybe String -> String
colorHelper Maybe String
l
                   | Bool
otherwise = Maybe String -> String
colorHelper Maybe String
m
        stopColor | String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
startColor = String
""
                  | Bool
otherwise = String
"</fc>"
    return $ startColor ++ digits ++ stopColor

runVolume :: String -> String -> [String] -> Monitor String
runVolume :: String -> String -> [String] -> Monitor String
runVolume String
mixerName String
controlName [String]
argv = do
    opts <- IO VolumeOpts -> Monitor VolumeOpts
forall a. IO a -> Monitor a
io (IO VolumeOpts -> Monitor VolumeOpts)
-> IO VolumeOpts -> Monitor VolumeOpts
forall a b. (a -> b) -> a -> b
$ [OptDescr (VolumeOpts -> VolumeOpts)]
-> VolumeOpts -> [String] -> IO VolumeOpts
forall opts.
[OptDescr (opts -> opts)] -> opts -> [String] -> IO opts
parseOptsWith [OptDescr (VolumeOpts -> VolumeOpts)]
options VolumeOpts
defaultOpts [String]
argv
    runVolumeWith opts mixerName controlName

runVolumeWith :: VolumeOpts -> String -> String -> Monitor String
runVolumeWith :: VolumeOpts -> String -> String -> Monitor String
runVolumeWith VolumeOpts
opts String
mixerName String
controlName = do
    (lo, hi, val, db, sw) <- IO
  (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
   Maybe Bool)
-> Monitor
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
forall a. IO a -> Monitor a
io IO
  (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
   Maybe Bool)
readMixer
    p <- liftMonitor $ liftM3 formatVol lo hi val
    b <- liftMonitor $ liftM3 formatVolBar lo hi val
    v <- liftMonitor $ liftM3 formatVolVBar lo hi val
    d <- getFormatDB opts db
    let volStat = (Float -> Float -> Float -> VolumeStatus)
-> Maybe Float -> Maybe Float -> Maybe Float -> Maybe VolumeStatus
forall (f :: * -> *) a b c d.
Applicative f =>
(a -> b -> c -> d) -> f a -> f b -> f c -> f d
liftA3 Float -> Float -> Float -> VolumeStatus
getVolStatus
                         (VolumeOpts -> Maybe Float
lowVolThresh VolumeOpts
opts)
                         (VolumeOpts -> Maybe Float
highVolThresh VolumeOpts
opts)
                         ((Integer -> Integer -> Integer -> Float)
-> Maybe Integer -> Maybe Integer -> Maybe Integer -> Maybe Float
forall (f :: * -> *) a b c d.
Applicative f =>
(a -> b -> c -> d) -> f a -> f b -> f c -> f d
liftA3 Integer -> Integer -> Integer -> Float
percent Maybe Integer
val Maybe Integer
lo Maybe Integer
hi) -- current volume in %
    s <- getFormatSwitch opts sw volStat
    ipat <- liftMonitor $ liftM3 (formatVolDStr $ volumeIconPattern opts) lo hi val

    -- Volume and status in one.
    let vs = if Maybe Bool -> Bool
isVolOff Maybe Bool
sw
            then VolumeOpts -> String
offString VolumeOpts
opts -- User defined off string
            else String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
p         -- Status string, current volume in %

    parseTemplate [p, b, v, d, s, ipat, vs]

  where

    readMixer :: IO
  (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
   Maybe Bool)
readMixer =
      IO
  (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
   Maybe Bool)
-> (T
    -> IO
         (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
          Maybe Bool))
-> IO
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
forall a. IO a -> (T -> IO a) -> IO a
AE.catch (String
-> (Mixer
    -> IO
         (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
          Maybe Bool))
-> IO
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
forall a. String -> (Mixer -> IO a) -> IO a
withMixer String
mixerName ((Mixer
  -> IO
       (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
        Maybe Bool))
 -> IO
      (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
       Maybe Bool))
-> (Mixer
    -> IO
         (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
          Maybe Bool))
-> IO
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
forall a b. (a -> b) -> a -> b
$ \Mixer
mixer -> do
                   control <- Mixer -> String -> IO (Maybe Control)
getControlByName Mixer
mixer String
controlName
                   (lo, hi) <- liftMaybe $ getRange <$> volumeControl control
                   val <- getVal $ volumeControl control
                   db <- getDB $ volumeControl control
                   sw <- getSw $ switchControl control
                   return (fmap toInteger lo, fmap toInteger hi, val, db, sw))
                (IO
  (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
   Maybe Bool)
-> T
-> IO
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
forall a b. a -> b -> a
const (IO
   (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
    Maybe Bool)
 -> T
 -> IO
      (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
       Maybe Bool))
-> IO
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
-> T
-> IO
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
forall a b. (a -> b) -> a -> b
$ (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
 Maybe Bool)
-> IO
     (Maybe Integer, Maybe Integer, Maybe Integer, Maybe Integer,
      Maybe Bool)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe Integer
forall a. Maybe a
Nothing, Maybe Integer
forall a. Maybe a
Nothing, Maybe Integer
forall a. Maybe a
Nothing, Maybe Integer
forall a. Maybe a
Nothing, Maybe Bool
forall a. Maybe a
Nothing))

    volumeControl :: Maybe Control -> Maybe Volume
    volumeControl :: Maybe Control -> Maybe Volume
volumeControl Maybe Control
c = (Either Volume (Maybe Volume, Maybe Volume) -> Maybe Volume
forall a. Either a (Maybe a, Maybe a) -> Maybe a
playback (Either Volume (Maybe Volume, Maybe Volume) -> Maybe Volume)
-> (Control -> Either Volume (Maybe Volume, Maybe Volume))
-> Control
-> Maybe Volume
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Control -> Either Volume (Maybe Volume, Maybe Volume)
volume (Control -> Maybe Volume) -> Maybe Control -> Maybe Volume
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Maybe Control
c)
              Maybe Volume -> Maybe Volume -> Maybe Volume
forall a. Maybe a -> Maybe a -> Maybe a
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` (Either Volume (Maybe Volume, Maybe Volume) -> Maybe Volume
forall a. Either a (Maybe a, Maybe a) -> Maybe a
capture (Either Volume (Maybe Volume, Maybe Volume) -> Maybe Volume)
-> (Control -> Either Volume (Maybe Volume, Maybe Volume))
-> Control
-> Maybe Volume
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Control -> Either Volume (Maybe Volume, Maybe Volume)
volume (Control -> Maybe Volume) -> Maybe Control -> Maybe Volume
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Maybe Control
c)
              Maybe Volume -> Maybe Volume -> Maybe Volume
forall a. Maybe a -> Maybe a -> Maybe a
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` (Either Volume (Maybe Volume, Maybe Volume) -> Maybe Volume
forall a. Either a (Maybe a, Maybe a) -> Maybe a
common (Either Volume (Maybe Volume, Maybe Volume) -> Maybe Volume)
-> (Control -> Either Volume (Maybe Volume, Maybe Volume))
-> Control
-> Maybe Volume
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Control -> Either Volume (Maybe Volume, Maybe Volume)
volume (Control -> Maybe Volume) -> Maybe Control -> Maybe Volume
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Maybe Control
c)

    switchControl :: Maybe Control -> Maybe Switch
    switchControl :: Maybe Control -> Maybe Switch
switchControl Maybe Control
c = (Either Switch (Maybe Switch, Maybe Switch) -> Maybe Switch
forall a. Either a (Maybe a, Maybe a) -> Maybe a
playback (Either Switch (Maybe Switch, Maybe Switch) -> Maybe Switch)
-> (Control -> Either Switch (Maybe Switch, Maybe Switch))
-> Control
-> Maybe Switch
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Control -> Either Switch (Maybe Switch, Maybe Switch)
switch (Control -> Maybe Switch) -> Maybe Control -> Maybe Switch
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Maybe Control
c)
              Maybe Switch -> Maybe Switch -> Maybe Switch
forall a. Maybe a -> Maybe a -> Maybe a
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` (Either Switch (Maybe Switch, Maybe Switch) -> Maybe Switch
forall a. Either a (Maybe a, Maybe a) -> Maybe a
capture (Either Switch (Maybe Switch, Maybe Switch) -> Maybe Switch)
-> (Control -> Either Switch (Maybe Switch, Maybe Switch))
-> Control
-> Maybe Switch
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Control -> Either Switch (Maybe Switch, Maybe Switch)
switch (Control -> Maybe Switch) -> Maybe Control -> Maybe Switch
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Maybe Control
c)
              Maybe Switch -> Maybe Switch -> Maybe Switch
forall a. Maybe a -> Maybe a -> Maybe a
forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` (Either Switch (Maybe Switch, Maybe Switch) -> Maybe Switch
forall a. Either a (Maybe a, Maybe a) -> Maybe a
common (Either Switch (Maybe Switch, Maybe Switch) -> Maybe Switch)
-> (Control -> Either Switch (Maybe Switch, Maybe Switch))
-> Control
-> Maybe Switch
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Control -> Either Switch (Maybe Switch, Maybe Switch)
switch (Control -> Maybe Switch) -> Maybe Control -> Maybe Switch
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Maybe Control
c)

    liftMaybe :: Maybe (IO (a,b)) -> IO (Maybe a, Maybe b)
    liftMaybe :: forall a b. Maybe (IO (a, b)) -> IO (Maybe a, Maybe b)
liftMaybe = (Maybe (a, b) -> (Maybe a, Maybe b))
-> IO (Maybe (a, b)) -> IO (Maybe a, Maybe b)
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Maybe a -> Maybe b -> (Maybe a, Maybe b))
-> (Maybe (a, b) -> Maybe a)
-> (Maybe (a, b) -> Maybe b)
-> Maybe (a, b)
-> (Maybe a, Maybe b)
forall (m :: * -> *) a1 a2 r.
Monad m =>
(a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 (,) (((a, b) -> a) -> Maybe (a, b) -> Maybe a
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a, b) -> a
forall a b. (a, b) -> a
fst) (((a, b) -> b) -> Maybe (a, b) -> Maybe b
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a, b) -> b
forall a b. (a, b) -> b
snd)) (IO (Maybe (a, b)) -> IO (Maybe a, Maybe b))
-> (Maybe (IO (a, b)) -> IO (Maybe (a, b)))
-> Maybe (IO (a, b))
-> IO (Maybe a, Maybe b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Maybe (IO (a, b)) -> IO (Maybe (a, b))
forall (t :: * -> *) (f :: * -> *) a.
(Traversable t, Applicative f) =>
t (f a) -> f (t a)
forall (f :: * -> *) a. Applicative f => Maybe (f a) -> f (Maybe a)
sequenceA

    liftMonitor :: Maybe (Monitor String) -> Monitor String
    liftMonitor :: Maybe (Monitor String) -> Monitor String
liftMonitor Maybe (Monitor String)
Nothing = Monitor String
unavailable
    liftMonitor (Just Monitor String
m) = Monitor String
m

    channel' :: PerChannel a -> IO (Maybe a)
    channel' :: forall a. PerChannel a -> IO (Maybe a)
channel' PerChannel a
v = IO (Maybe a) -> (T -> IO (Maybe a)) -> IO (Maybe a)
forall a. IO a -> (T -> IO a) -> IO a
AE.catch (Channel -> PerChannel a -> IO (Maybe a)
forall x. Channel -> PerChannel x -> IO (Maybe x)
getChannel Channel
FrontLeft PerChannel a
v) (IO (Maybe a) -> T -> IO (Maybe a)
forall a b. a -> b -> a
const (Maybe a -> IO (Maybe a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe a
forall a. Maybe a
Nothing))

    channel :: PerChannel CLong -> IO (Maybe Integer)
    channel :: PerChannel CLong -> IO (Maybe Integer)
channel PerChannel CLong
v = (Maybe CLong -> Maybe Integer)
-> IO (Maybe CLong) -> IO (Maybe Integer)
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((CLong -> Integer) -> Maybe CLong -> Maybe Integer
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap CLong -> Integer
forall a. Integral a => a -> Integer
toInteger) (PerChannel CLong -> IO (Maybe CLong)
forall a. PerChannel a -> IO (Maybe a)
channel' PerChannel CLong
v)

    getDB :: Maybe Volume -> IO (Maybe Integer)
    getDB :: Maybe Volume -> IO (Maybe Integer)
getDB Maybe Volume
Nothing = Maybe Integer -> IO (Maybe Integer)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Integer
forall a. Maybe a
Nothing
    getDB (Just Volume
v) = PerChannel CLong -> IO (Maybe Integer)
channel (Volume -> PerChannel CLong
dB Volume
v)

    getVal :: Maybe Volume -> IO (Maybe Integer)
    getVal :: Maybe Volume -> IO (Maybe Integer)
getVal Maybe Volume
Nothing = Maybe Integer -> IO (Maybe Integer)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Integer
forall a. Maybe a
Nothing
    getVal (Just Volume
v) = PerChannel CLong -> IO (Maybe Integer)
channel (Volume -> PerChannel CLong
value Volume
v)

    getSw :: Maybe Switch -> IO (Maybe Bool)
    getSw :: Maybe Switch -> IO (Maybe Bool)
getSw Maybe Switch
Nothing = Maybe Bool -> IO (Maybe Bool)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Bool
forall a. Maybe a
Nothing
    getSw (Just Switch
s) = Switch -> IO (Maybe Bool)
forall a. PerChannel a -> IO (Maybe a)
channel' Switch
s

    getFormatDB :: VolumeOpts -> Maybe Integer -> Monitor String
    getFormatDB :: VolumeOpts -> Maybe Integer -> Monitor String
getFormatDB VolumeOpts
_ Maybe Integer
Nothing = Monitor String
unavailable
    getFormatDB VolumeOpts
opts' (Just Integer
d) = VolumeOpts -> Integer -> Monitor String
formatDb VolumeOpts
opts' Integer
d

    getFormatSwitch :: VolumeOpts -> Maybe Bool -> Maybe VolumeStatus -> Monitor String
    getFormatSwitch :: VolumeOpts -> Maybe Bool -> Maybe VolumeStatus -> Monitor String
getFormatSwitch VolumeOpts
_ Maybe Bool
Nothing Maybe VolumeStatus
_ = Monitor String
unavailable
    getFormatSwitch VolumeOpts
_ Maybe Bool
_ Maybe VolumeStatus
Nothing = Monitor String
unavailable
    getFormatSwitch VolumeOpts
opts' (Just Bool
sw) (Just VolumeStatus
vs) = VolumeOpts -> Bool -> VolumeStatus -> Monitor String
formatSwitch VolumeOpts
opts' Bool
sw VolumeStatus
vs

    -- | Determine whether the volume is off based on the value of 'sw' from
    -- 'runVolumeWith'.
    isVolOff :: Maybe Bool -> Bool
isVolOff = (Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True Maybe Bool -> Maybe Bool -> Bool
forall a. Eq a => a -> a -> Bool
/=)
    unavailable :: Monitor String
unavailable = Selector String -> Monitor String
forall a. Selector a -> Monitor a
getConfigValue Selector String
naString