    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Sound.ALSA.Mixer
    -- Copyright   :  (c) Thomas Tuegel 2011
    -- License     :  BSD
    --
    -- Maintainer  :  Thomas Tuegel <ttuegel@gmail.com>
    -- Stability   :  experimental
    -- Portability :  non-portable (Linux only)
    --
    -- This library provides bindings to the Advanced Linux Sound Architecture
    -- (ALSA) library API. The portability of this library is limited to
    -- systems with ALSA (i.e., Linux systems). The functions in this library
    -- throw errors of type 'Sound.ALSA.Exception.T' on failure.
    --
    -----------------------------------------------------------------------------

    module Sound.ALSA.Mixer
        ( -- * Types
          Control(..)
        , Mixer()
        , Channel(..)
        , PerChannel(..)
        , Volume(..)
        , Switch()
        , CUInt
        , CLong
          -- * Functions
          -- ** Mixers
        , controls
        , withMixer
          -- ** Controls
        , getControlByName
        , common
        , playback
        , capture
          -- ** PerChannels
        , channels
        , allChannels
        , joined
        , perChannel
        , getChannel
        , setChannel
          -- * Examples

          -- ** Getting and setting the volume of a Control
          -- $exampleVolume

          -- ** Getting and setting the switch of a Control
          -- $exampleSwitch
        ) where

    import Control.Monad ( forM, liftM, when )
    import Data.Maybe ( catMaybes )
    import Foreign.C.Error ( Errno(..) )
    import Foreign.C.Types
    import Sound.ALSA.Exception ( catchErrno )
    import Sound.ALSA.Mixer.Internal

    -- | 'Control' represents one of the controls belonging to an ALSA mixer
    -- element. Each control has a number of playback and capture channels.
    -- The control may also have a switch and/or a volume capability associated
    -- with it. The capability can be common to both playback and capture, or
    -- there can be separate capabilities for each.
    data Control = Control { Control -> CUInt
    index :: CUInt
                           , Control -> String
    name :: String
                           , Control -> Either Switch (Maybe Switch, Maybe Switch)
    switch :: Either Switch (Maybe Switch, Maybe Switch)
                           , Control -> Either Volume (Maybe Volume, Maybe Volume)
    volume :: Either Volume (Maybe Volume, Maybe Volume)
                           }

    -- | 'PerChannel' represents a capability that with either a separate value for
    -- each channel or with a common value for all channels.
    data PerChannel e = Joined { PerChannel e -> IO e
    getJoined :: IO e
                               , PerChannel e -> e -> IO ()
    setJoined :: e -> IO ()
                               , PerChannel e -> [Channel]
    joinedChannels :: [Channel]
                               }
                      | PerChannel { PerChannel e -> IO [(Channel, e)]
    getPerChannel :: IO [(Channel, e)]
                                   , PerChannel e -> [(Channel, e)] -> IO ()
    setPerChannel :: [(Channel, e)] -> IO ()
                                   , PerChannel e -> [Channel]
    perChannels :: [Channel]
                                   }

    -- | True if the 'PerChannel' object has a common value for all channels.
    joined :: PerChannel e -> Bool
    joined :: PerChannel e -> Bool
    joined j :: PerChannel e
    j@(Joined _ _ _) = Bool
    True
    joined _ = Bool
    False

    -- | True if the 'PerChannel' object has a separate value for each channel.
    perChannel :: PerChannel e -> Bool
    perChannel :: PerChannel e -> Bool
    perChannel p :: PerChannel e
    p@(PerChannel _ _ _) = Bool
    True
    perChannel _ = Bool
    False

    -- | All channels supported by a 'PerChannel' object.
    channels :: PerChannel e -> [Channel]
    channels :: PerChannel e -> [Channel]
    channels p :: PerChannel e
    p | PerChannel e -> Bool
    forall e. PerChannel e -> Bool
    joined PerChannel e
    p = PerChannel e -> [Channel]
    forall e. PerChannel e -> [Channel]
    joinedChannels PerChannel e
    p
               | Bool
    otherwise = PerChannel e -> [Channel]
    forall e. PerChannel e -> [Channel]
    perChannels PerChannel e
    p

    -- | 'Switch' represents a switch capability for controls and channels that can
    -- be muted and unmuted.
    type Switch = PerChannel Bool

    -- | 'Volume' represents a volume capability. There may be a separate value per
    -- channel, but each capability has only one range.
    data Volume = Volume { Volume -> IO (CLong, CLong)
    getRange :: IO (CLong, CLong)
                           -- ^ Returns the minimum and maximum volumes (unitless).
                         , Volume -> (CLong, CLong) -> IO ()
    setRange :: (CLong, CLong) -> IO ()
                           -- ^ Sets the minimum and maximum volumes (unitless).
                         , Volume -> IO (CLong, CLong)
    getRangeDb :: IO (CLong, CLong)
                           -- ^ Returns the minimum and maximum volumes in
                           -- hundredths of a decibel.
                         , Volume -> PerChannel CLong
    value :: PerChannel CLong
                           -- ^ Volume values for each channel.
                         , Volume -> PerChannel CLong
    dB :: PerChannel CLong
                           -- ^ Volume values for each channel in hundredths of
                           -- a decibel.
                         }

    -- | Get the value associated with a particular channel, if that channel exists.
    getChannel :: Channel -> PerChannel x -> IO (Maybe x)
    getChannel :: Channel -> PerChannel x -> IO (Maybe x)
    getChannel c :: Channel
    c p :: PerChannel x
    p | PerChannel x -> Bool
    forall e. PerChannel e -> Bool
    joined PerChannel x
    p = let r :: IO (Maybe x)
    r | Channel
    c Channel -> [Channel] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` PerChannel x -> [Channel]
    forall e. PerChannel e -> [Channel]
    channels PerChannel x
    p =
                                          (x -> Maybe x) -> IO x -> IO (Maybe x)
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM x -> Maybe x
    forall a. a -> Maybe a
    Just (IO x -> IO (Maybe x)) -> IO x -> IO (Maybe x)
    forall a b. (a -> b) -> a -> b
    $ PerChannel x -> IO x
    forall e. PerChannel e -> IO e
    getJoined PerChannel x
    p
                                      | Bool
    otherwise = Maybe x -> IO (Maybe x)
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe x
    forall a. Maybe a
    Nothing
                                in IO (Maybe x)
    r
                   | Bool
    otherwise = ([(Channel, x)] -> Maybe x) -> IO [(Channel, x)] -> IO (Maybe x)
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM (Channel -> [(Channel, x)] -> Maybe x
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup Channel
    c) (IO [(Channel, x)] -> IO (Maybe x))
    -> IO [(Channel, x)] -> IO (Maybe x)
    forall a b. (a -> b) -> a -> b
    $ PerChannel x -> IO [(Channel, x)]
    forall e. PerChannel e -> IO [(Channel, e)]
    getPerChannel PerChannel x
    p

    -- | Set the value associated with a particular channel, if that channel exists.
    setChannel :: Channel -> PerChannel x -> x -> IO ()
    setChannel :: Channel -> PerChannel x -> x -> IO ()
    setChannel c :: Channel
    c p :: PerChannel x
    p v :: x
    v | PerChannel x -> Bool
    forall e. PerChannel e -> Bool
    joined PerChannel x
    p = Bool -> IO () -> IO ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when (Channel
    c Channel -> [Channel] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `elem` PerChannel x -> [Channel]
    forall e. PerChannel e -> [Channel]
    channels PerChannel x
    p) (IO () -> IO ()) -> IO () -> IO ()
    forall a b. (a -> b) -> a -> b
    $ PerChannel x -> x -> IO ()
    forall e. PerChannel e -> e -> IO ()
    setJoined PerChannel x
    p x
    v
                     | Bool
    otherwise = PerChannel x -> [(Channel, x)] -> IO ()
    forall e. PerChannel e -> [(Channel, e)] -> IO ()
    setPerChannel PerChannel x
    p [(Channel
    c, x
    v)]

    -- | For a given capability, which may be for either playback or capture, or
    -- common to both, return the playback capability if it exists.
    playback :: Either a (Maybe a, Maybe a) -> Maybe a
    playback :: Either a (Maybe a, Maybe a) -> Maybe a
    playback (Left _) = Maybe a
    forall a. Maybe a
    Nothing
    playback (Right (x :: Maybe a
    x, _)) = Maybe a
    x

    -- | For a given capability, which may be for either playback or capture, or
    -- common to both, return the capture capability if it exists.
    capture :: Either a (Maybe a, Maybe a) -> Maybe a
    capture :: Either a (Maybe a, Maybe a) -> Maybe a
    capture (Left _) = Maybe a
    forall a. Maybe a
    Nothing
    capture (Right (_, x :: Maybe a
    x)) = Maybe a
    x

    -- | For a given capability, which may be for either playback or capture, or
    -- common to both, return the common capability if it exists.
    common :: Either a (Maybe a, Maybe a) -> Maybe a
    common :: Either a (Maybe a, Maybe a) -> Maybe a
    common (Left x :: a
    x) = a -> Maybe a
    forall a. a -> Maybe a
    Just a
    x
    common (Right _) = Maybe a
    forall a. Maybe a
    Nothing

    mkSwitch :: SimpleElement -> IO (Either Switch (Maybe Switch, Maybe Switch))
    mkSwitch :: SimpleElement -> IO (Either Switch (Maybe Switch, Maybe Switch))
    mkSwitch se :: SimpleElement
    se = do
        [Bool]
    hasPlayChan <- (Channel -> IO Bool) -> [Channel] -> IO [Bool]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    mapM (SimpleElement -> Channel -> IO Bool
    hasPlaybackChannel SimpleElement
    se) [Channel]
    allChannels
        [Bool]
    hasCaptChan <- (Channel -> IO Bool) -> [Channel] -> IO [Bool]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    mapM (SimpleElement -> Channel -> IO Bool
    hasCaptureChannel SimpleElement
    se) [Channel]
    allChannels
        let pChans :: [Channel]
    pChans = ((Channel, Bool) -> Channel) -> [(Channel, Bool)] -> [Channel]
    forall a b. (a -> b) -> [a] -> [b]
    map (Channel, Bool) -> Channel
    forall a b. (a, b) -> a
    fst ([(Channel, Bool)] -> [Channel]) -> [(Channel, Bool)] -> [Channel]
    forall a b. (a -> b) -> a -> b
    $ ((Channel, Bool) -> Bool) -> [(Channel, Bool)] -> [(Channel, Bool)]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Channel, Bool) -> Bool
    forall a b. (a, b) -> b
    snd ([(Channel, Bool)] -> [(Channel, Bool)])
    -> [(Channel, Bool)] -> [(Channel, Bool)]
    forall a b. (a -> b) -> a -> b
    $ [Channel] -> [Bool] -> [(Channel, Bool)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [Channel]
    allChannels [Bool]
    hasPlayChan
            cChans :: [Channel]
    cChans = ((Channel, Bool) -> Channel) -> [(Channel, Bool)] -> [Channel]
    forall a b. (a -> b) -> [a] -> [b]
    map (Channel, Bool) -> Channel
    forall a b. (a, b) -> a
    fst ([(Channel, Bool)] -> [Channel]) -> [(Channel, Bool)] -> [Channel]
    forall a b. (a -> b) -> a -> b
    $ ((Channel, Bool) -> Bool) -> [(Channel, Bool)] -> [(Channel, Bool)]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Channel, Bool) -> Bool
    forall a b. (a, b) -> b
    snd ([(Channel, Bool)] -> [(Channel, Bool)])
    -> [(Channel, Bool)] -> [(Channel, Bool)]
    forall a b. (a -> b) -> a -> b
    $ [Channel] -> [Bool] -> [(Channel, Bool)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [Channel]
    allChannels [Bool]
    hasCaptChan
        Bool
    hasComSw <- SimpleElement -> IO Bool
    hasCommonSwitch SimpleElement
    se
        Bool
    hasPlaySw <- SimpleElement -> IO Bool
    hasPlaybackSwitch SimpleElement
    se
        Bool
    hasPlaySwJ <- SimpleElement -> IO Bool
    hasPlaybackSwitchJoined SimpleElement
    se
        Bool
    hasCaptSw <- SimpleElement -> IO Bool
    hasCaptureSwitch SimpleElement
    se
        Bool
    hasCaptSwJ <- SimpleElement -> IO Bool
    hasCaptureSwitchJoined SimpleElement
    se
        Either Switch (Maybe Switch, Maybe Switch)
    -> IO (Either Switch (Maybe Switch, Maybe Switch))
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Either Switch (Maybe Switch, Maybe Switch)
     -> IO (Either Switch (Maybe Switch, Maybe Switch)))
    -> Either Switch (Maybe Switch, Maybe Switch)
    -> IO (Either Switch (Maybe Switch, Maybe Switch))
    forall a b. (a -> b) -> a -> b
    $ if Bool
    hasComSw
                    then Switch -> Either Switch (Maybe Switch, Maybe Switch)
    forall a b. a -> Either a b
    Left (Switch -> Either Switch (Maybe Switch, Maybe Switch))
    -> Switch -> Either Switch (Maybe Switch, Maybe Switch)
    forall a b. (a -> b) -> a -> b
    $ if Bool
    hasPlaySwJ
                                  then [Channel] -> Switch
    comJoinedSwitch [Channel]
    pChans
                                  else [Channel] -> Switch
    comPerChannelSwitch [Channel]
    pChans
                    else let playSw :: Maybe Switch
    playSw | Bool -> Bool
    not Bool
    hasPlaySw = Maybe Switch
    forall a. Maybe a
    Nothing
                                    | Bool
    otherwise = Switch -> Maybe Switch
    forall a. a -> Maybe a
    Just
                                        (Switch -> Maybe Switch) -> Switch -> Maybe Switch
    forall a b. (a -> b) -> a -> b
    $ if Bool
    hasPlaySwJ
                                            then [Channel] -> Switch
    playJoinedSwitch [Channel]
    pChans
                                            else [Channel] -> Switch
    playPerChannelSwitch [Channel]
    pChans
                             captSw :: Maybe Switch
    captSw | Bool -> Bool
    not Bool
    hasCaptSw = Maybe Switch
    forall a. Maybe a
    Nothing
                                    | Bool
    otherwise = Switch -> Maybe Switch
    forall a. a -> Maybe a
    Just
                                        (Switch -> Maybe Switch) -> Switch -> Maybe Switch
    forall a b. (a -> b) -> a -> b
    $ if Bool
    hasCaptSwJ
                                            then [Channel] -> Switch
    captJoinedSwitch [Channel]
    cChans
                                            else [Channel] -> Switch
    captPerChannelSwitch [Channel]
    cChans
                         in (Maybe Switch, Maybe Switch)
    -> Either Switch (Maybe Switch, Maybe Switch)
    forall a b. b -> Either a b
    Right (Maybe Switch
    playSw, Maybe Switch
    captSw)
      where joined :: (SimpleElement -> Channel -> IO e)
    -> (SimpleElement -> Channel -> e -> IO ())
    -> [Channel]
    -> PerChannel e
    joined fGet :: SimpleElement -> Channel -> IO e
    fGet fSet :: SimpleElement -> Channel -> e -> IO ()
    fSet chans :: [Channel]
    chans =
                Joined :: forall e. IO e -> (e -> IO ()) -> [Channel] -> PerChannel e
    Joined { getJoined :: IO e
    getJoined = SimpleElement -> Channel -> IO e
    fGet SimpleElement
    se ([Channel] -> Channel
    forall a. [a] -> a
    head [Channel]
    chans)
                       , setJoined :: e -> IO ()
    setJoined = SimpleElement -> Channel -> e -> IO ()
    fSet SimpleElement
    se ([Channel] -> Channel
    forall a. [a] -> a
    head [Channel]
    chans)
                       , joinedChannels :: [Channel]
    joinedChannels = [Channel]
    chans
                       }
            perChannel :: (SimpleElement -> Channel -> IO b)
    -> (SimpleElement -> Channel -> b -> IO b)
    -> [Channel]
    -> PerChannel b
    perChannel fGet :: SimpleElement -> Channel -> IO b
    fGet fSet :: SimpleElement -> Channel -> b -> IO b
    fSet chans :: [Channel]
    chans =
                PerChannel :: forall e.
    IO [(Channel, e)]
    -> ([(Channel, e)] -> IO ()) -> [Channel] -> PerChannel e
    PerChannel { getPerChannel :: IO [(Channel, b)]
    getPerChannel = ([b] -> [(Channel, b)]) -> IO [b] -> IO [(Channel, b)]
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM ([Channel] -> [b] -> [(Channel, b)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [Channel]
    chans)
                                (IO [b] -> IO [(Channel, b)]) -> IO [b] -> IO [(Channel, b)]
    forall a b. (a -> b) -> a -> b
    $ (Channel -> IO b) -> [Channel] -> IO [b]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    mapM (SimpleElement -> Channel -> IO b
    fGet SimpleElement
    se) [Channel]
    chans
                           , setPerChannel :: [(Channel, b)] -> IO ()
    setPerChannel = ((Channel, b) -> IO b) -> [(Channel, b)] -> IO ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ ((Channel -> b -> IO b) -> (Channel, b) -> IO b
    forall a b c. (a -> b -> c) -> (a, b) -> c
    uncurry (SimpleElement -> Channel -> b -> IO b
    fSet SimpleElement
    se))
                           , perChannels :: [Channel]
    perChannels = [Channel]
    chans
                           }
            comJoinedSwitch :: [Channel] -> Switch
    comJoinedSwitch = (SimpleElement -> Channel -> IO Bool)
    -> (SimpleElement -> Channel -> Bool -> IO ())
    -> [Channel]
    -> Switch
    forall e.
    (SimpleElement -> Channel -> IO e)
    -> (SimpleElement -> Channel -> e -> IO ())
    -> [Channel]
    -> PerChannel e
    joined SimpleElement -> Channel -> IO Bool
    getPlaybackSwitch SimpleElement -> Channel -> Bool -> IO ()
    setPlaybackSwitch
            comPerChannelSwitch :: [Channel] -> Switch
    comPerChannelSwitch = (SimpleElement -> Channel -> IO Bool)
    -> (SimpleElement -> Channel -> Bool -> IO ())
    -> [Channel]
    -> Switch
    forall b b.
    (SimpleElement -> Channel -> IO b)
    -> (SimpleElement -> Channel -> b -> IO b)
    -> [Channel]
    -> PerChannel b
    perChannel SimpleElement -> Channel -> IO Bool
    getPlaybackSwitch SimpleElement -> Channel -> Bool -> IO ()
    setPlaybackSwitch
            playJoinedSwitch :: [Channel] -> Switch
    playJoinedSwitch = [Channel] -> Switch
    comJoinedSwitch
            playPerChannelSwitch :: [Channel] -> Switch
    playPerChannelSwitch = [Channel] -> Switch
    comPerChannelSwitch
            captJoinedSwitch :: [Channel] -> Switch
    captJoinedSwitch = (SimpleElement -> Channel -> IO Bool)
    -> (SimpleElement -> Channel -> Bool -> IO ())
    -> [Channel]
    -> Switch
    forall e.
    (SimpleElement -> Channel -> IO e)
    -> (SimpleElement -> Channel -> e -> IO ())
    -> [Channel]
    -> PerChannel e
    joined SimpleElement -> Channel -> IO Bool
    getCaptureSwitch SimpleElement -> Channel -> Bool -> IO ()
    setCaptureSwitch
            captPerChannelSwitch :: [Channel] -> Switch
    captPerChannelSwitch = (SimpleElement -> Channel -> IO Bool)
    -> (SimpleElement -> Channel -> Bool -> IO ())
    -> [Channel]
    -> Switch
    forall b b.
    (SimpleElement -> Channel -> IO b)
    -> (SimpleElement -> Channel -> b -> IO b)
    -> [Channel]
    -> PerChannel b
    perChannel SimpleElement -> Channel -> IO Bool
    getCaptureSwitch SimpleElement -> Channel -> Bool -> IO ()
    setCaptureSwitch

    mkVolume :: SimpleElement -> IO (Either Volume (Maybe Volume, Maybe Volume))
    mkVolume :: SimpleElement -> IO (Either Volume (Maybe Volume, Maybe Volume))
    mkVolume se :: SimpleElement
    se = do
        [Bool]
    hasPlayChan <- (Channel -> IO Bool) -> [Channel] -> IO [Bool]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    mapM (SimpleElement -> Channel -> IO Bool
    hasPlaybackChannel SimpleElement
    se) [Channel]
    allChannels
        [Bool]
    hasCaptChan <- (Channel -> IO Bool) -> [Channel] -> IO [Bool]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    mapM (SimpleElement -> Channel -> IO Bool
    hasCaptureChannel SimpleElement
    se) [Channel]
    allChannels
        let pChans :: [Channel]
    pChans = ((Channel, Bool) -> Channel) -> [(Channel, Bool)] -> [Channel]
    forall a b. (a -> b) -> [a] -> [b]
    map (Channel, Bool) -> Channel
    forall a b. (a, b) -> a
    fst ([(Channel, Bool)] -> [Channel]) -> [(Channel, Bool)] -> [Channel]
    forall a b. (a -> b) -> a -> b
    $ ((Channel, Bool) -> Bool) -> [(Channel, Bool)] -> [(Channel, Bool)]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Channel, Bool) -> Bool
    forall a b. (a, b) -> b
    snd ([(Channel, Bool)] -> [(Channel, Bool)])
    -> [(Channel, Bool)] -> [(Channel, Bool)]
    forall a b. (a -> b) -> a -> b
    $ [Channel] -> [Bool] -> [(Channel, Bool)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [Channel]
    allChannels [Bool]
    hasPlayChan
            cChans :: [Channel]
    cChans = ((Channel, Bool) -> Channel) -> [(Channel, Bool)] -> [Channel]
    forall a b. (a -> b) -> [a] -> [b]
    map (Channel, Bool) -> Channel
    forall a b. (a, b) -> a
    fst ([(Channel, Bool)] -> [Channel]) -> [(Channel, Bool)] -> [Channel]
    forall a b. (a -> b) -> a -> b
    $ ((Channel, Bool) -> Bool) -> [(Channel, Bool)] -> [(Channel, Bool)]
    forall a. (a -> Bool) -> [a] -> [a]
    filter (Channel, Bool) -> Bool
    forall a b. (a, b) -> b
    snd ([(Channel, Bool)] -> [(Channel, Bool)])
    -> [(Channel, Bool)] -> [(Channel, Bool)]
    forall a b. (a -> b) -> a -> b
    $ [Channel] -> [Bool] -> [(Channel, Bool)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [Channel]
    allChannels [Bool]
    hasCaptChan
        Bool
    hasComV <- SimpleElement -> IO Bool
    hasCommonVolume SimpleElement
    se
        Bool
    hasPlayV <- SimpleElement -> IO Bool
    hasPlaybackVolume SimpleElement
    se
        Bool
    hasPlayVJ <- SimpleElement -> IO Bool
    hasPlaybackVolumeJoined SimpleElement
    se
        Bool
    hasCaptV <- SimpleElement -> IO Bool
    hasCaptureVolume SimpleElement
    se
        Bool
    hasCaptVJ <- SimpleElement -> IO Bool
    hasCaptureVolumeJoined SimpleElement
    se
        Either Volume (Maybe Volume, Maybe Volume)
    -> IO (Either Volume (Maybe Volume, Maybe Volume))
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Either Volume (Maybe Volume, Maybe Volume)
     -> IO (Either Volume (Maybe Volume, Maybe Volume)))
    -> Either Volume (Maybe Volume, Maybe Volume)
    -> IO (Either Volume (Maybe Volume, Maybe Volume))
    forall a b. (a -> b) -> a -> b
    $
            if Bool
    hasComV
               then let (v :: PerChannel CLong
    v, d :: PerChannel CLong
    d) | Bool
    hasPlayVJ = ( [Channel] -> PerChannel CLong
    comJoinedVol [Channel]
    pChans
                                             , [Channel] -> PerChannel CLong
    comJoinedDb [Channel]
    pChans
                                             )
                               | Bool
    otherwise = ( [Channel] -> PerChannel CLong
    comPerChannelVol [Channel]
    pChans
                                             , [Channel] -> PerChannel CLong
    comPerChannelDb [Channel]
    pChans
                                             )
                    in Volume -> Either Volume (Maybe Volume, Maybe Volume)
    forall a b. a -> Either a b
    Left (Volume -> Either Volume (Maybe Volume, Maybe Volume))
    -> Volume -> Either Volume (Maybe Volume, Maybe Volume)
    forall a b. (a -> b) -> a -> b
    $ Volume
    playVolume { value :: PerChannel CLong
    value = PerChannel CLong
    v, dB :: PerChannel CLong
    dB = PerChannel CLong
    d }
               else let playVol :: Maybe Volume
    playVol | Bool -> Bool
    not Bool
    hasPlayV = Maybe Volume
    forall a. Maybe a
    Nothing
                                | Bool
    otherwise =
                                    let (v :: PerChannel CLong
    v, d :: PerChannel CLong
    d) | Bool
    hasPlayVJ =
                                                   ( [Channel] -> PerChannel CLong
    playJoinedVol [Channel]
    pChans
                                                   , [Channel] -> PerChannel CLong
    playJoinedDb [Channel]
    pChans
                                                   )
                                               | Bool
    otherwise =
                                                   ( [Channel] -> PerChannel CLong
    playPerChannelVol [Channel]
    pChans
                                                   , [Channel] -> PerChannel CLong
    playPerChannelDb [Channel]
    pChans
                                                   )
                                    in Volume -> Maybe Volume
    forall a. a -> Maybe a
    Just Volume
    playVolume { value :: PerChannel CLong
    value = PerChannel CLong
    v, dB :: PerChannel CLong
    dB = PerChannel CLong
    d }
                        captVol :: Maybe Volume
    captVol | Bool -> Bool
    not Bool
    hasCaptV = Maybe Volume
    forall a. Maybe a
    Nothing
                                | Bool
    otherwise =
                                    let (v :: PerChannel CLong
    v, d :: PerChannel CLong
    d) | Bool
    hasCaptVJ =
                                                   ( [Channel] -> PerChannel CLong
    captJoinedVol [Channel]
    cChans
                                                   , [Channel] -> PerChannel CLong
    captJoinedDb [Channel]
    cChans
                                                   )
                                               | Bool
    otherwise =
                                                   ( [Channel] -> PerChannel CLong
    captPerChannelVol [Channel]
    cChans
                                                   , [Channel] -> PerChannel CLong
    captPerChannelDb [Channel]
    cChans
                                                   )
                                    in Volume -> Maybe Volume
    forall a. a -> Maybe a
    Just (Volume -> Maybe Volume) -> Volume -> Maybe Volume
    forall a b. (a -> b) -> a -> b
    $ Volume
    captVolume { value :: PerChannel CLong
    value = PerChannel CLong
    v, dB :: PerChannel CLong
    dB = PerChannel CLong
    d }
                    in (Maybe Volume, Maybe Volume)
    -> Either Volume (Maybe Volume, Maybe Volume)
    forall a b. b -> Either a b
    Right (Maybe Volume
    playVol, Maybe Volume
    captVol)
      where j :: (SimpleElement -> Channel -> IO e)
    -> (SimpleElement -> Channel -> e -> IO ())
    -> [Channel]
    -> PerChannel e
    j fGet :: SimpleElement -> Channel -> IO e
    fGet fSet :: SimpleElement -> Channel -> e -> IO ()
    fSet chans :: [Channel]
    chans =
                Joined :: forall e. IO e -> (e -> IO ()) -> [Channel] -> PerChannel e
    Joined { getJoined :: IO e
    getJoined = SimpleElement -> Channel -> IO e
    fGet SimpleElement
    se ([Channel] -> Channel
    forall a. [a] -> a
    head [Channel]
    chans)
                       , setJoined :: e -> IO ()
    setJoined = SimpleElement -> Channel -> e -> IO ()
    fSet SimpleElement
    se ([Channel] -> Channel
    forall a. [a] -> a
    head [Channel]
    chans)
                       , joinedChannels :: [Channel]
    joinedChannels = [Channel]
    chans
                       }
            pc :: (SimpleElement -> Channel -> IO b)
    -> (SimpleElement -> Channel -> b -> IO b)
    -> [Channel]
    -> PerChannel b
    pc fGet :: SimpleElement -> Channel -> IO b
    fGet fSet :: SimpleElement -> Channel -> b -> IO b
    fSet chans :: [Channel]
    chans =
                PerChannel :: forall e.
    IO [(Channel, e)]
    -> ([(Channel, e)] -> IO ()) -> [Channel] -> PerChannel e
    PerChannel { getPerChannel :: IO [(Channel, b)]
    getPerChannel = ([b] -> [(Channel, b)]) -> IO [b] -> IO [(Channel, b)]
    forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
    liftM ([Channel] -> [b] -> [(Channel, b)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip [Channel]
    chans)
                                (IO [b] -> IO [(Channel, b)]) -> IO [b] -> IO [(Channel, b)]
    forall a b. (a -> b) -> a -> b
    $ (Channel -> IO b) -> [Channel] -> IO [b]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    mapM (SimpleElement -> Channel -> IO b
    fGet SimpleElement
    se) [Channel]
    chans
                           , setPerChannel :: [(Channel, b)] -> IO ()
    setPerChannel = ((Channel, b) -> IO b) -> [(Channel, b)] -> IO ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ ((Channel -> b -> IO b) -> (Channel, b) -> IO b
    forall a b c. (a -> b -> c) -> (a, b) -> c
    uncurry (SimpleElement -> Channel -> b -> IO b
    fSet SimpleElement
    se))
                           , perChannels :: [Channel]
    perChannels = [Channel]
    chans
                           }
            playVolume :: Volume
    playVolume = Volume :: IO (CLong, CLong)
    -> ((CLong, CLong) -> IO ())
    -> IO (CLong, CLong)
    -> PerChannel CLong
    -> PerChannel CLong
    -> Volume
    Volume { getRange :: IO (CLong, CLong)
    getRange = SimpleElement -> IO (CLong, CLong)
    getPlaybackVolumeRange SimpleElement
    se
                                , setRange :: (CLong, CLong) -> IO ()
    setRange = SimpleElement -> (CLong, CLong) -> IO ()
    setPlaybackVolumeRange SimpleElement
    se
                                , getRangeDb :: IO (CLong, CLong)
    getRangeDb = SimpleElement -> IO (CLong, CLong)
    getPlaybackDbRange SimpleElement
    se
                                , value :: PerChannel CLong
    value = PerChannel CLong
    forall a. HasCallStack => a
    undefined
                                , dB :: PerChannel CLong
    dB = PerChannel CLong
    forall a. HasCallStack => a
    undefined
                                }
            captVolume :: Volume
    captVolume = Volume :: IO (CLong, CLong)
    -> ((CLong, CLong) -> IO ())
    -> IO (CLong, CLong)
    -> PerChannel CLong
    -> PerChannel CLong
    -> Volume
    Volume { getRange :: IO (CLong, CLong)
    getRange = SimpleElement -> IO (CLong, CLong)
    getCaptureVolumeRange SimpleElement
    se
                                , setRange :: (CLong, CLong) -> IO ()
    setRange = SimpleElement -> (CLong, CLong) -> IO ()
    setCaptureVolumeRange SimpleElement
    se
                                , getRangeDb :: IO (CLong, CLong)
    getRangeDb = SimpleElement -> IO (CLong, CLong)
    getCaptureDbRange SimpleElement
    se
                                , value :: PerChannel CLong
    value = PerChannel CLong
    forall a. HasCallStack => a
    undefined
                                , dB :: PerChannel CLong
    dB = PerChannel CLong
    forall a. HasCallStack => a
    undefined
                                }
            comJoinedVol :: [Channel] -> PerChannel CLong
    comJoinedVol = (SimpleElement -> Channel -> IO CLong)
    -> (SimpleElement -> Channel -> CLong -> IO ())
    -> [Channel]
    -> PerChannel CLong
    forall e.
    (SimpleElement -> Channel -> IO e)
    -> (SimpleElement -> Channel -> e -> IO ())
    -> [Channel]
    -> PerChannel e
    j SimpleElement -> Channel -> IO CLong
    getPlaybackVolume SimpleElement -> Channel -> CLong -> IO ()
    setPlaybackVolume
            comJoinedDb :: [Channel] -> PerChannel CLong
    comJoinedDb = (SimpleElement -> Channel -> IO CLong)
    -> (SimpleElement -> Channel -> CLong -> IO ())
    -> [Channel]
    -> PerChannel CLong
    forall e.
    (SimpleElement -> Channel -> IO e)
    -> (SimpleElement -> Channel -> e -> IO ())
    -> [Channel]
    -> PerChannel e
    j SimpleElement -> Channel -> IO CLong
    getPlaybackDb SimpleElement -> Channel -> CLong -> IO ()
    setPlaybackDb
            comPerChannelVol :: [Channel] -> PerChannel CLong
    comPerChannelVol = (SimpleElement -> Channel -> IO CLong)
    -> (SimpleElement -> Channel -> CLong -> IO ())
    -> [Channel]
    -> PerChannel CLong
    forall b b.
    (SimpleElement -> Channel -> IO b)
    -> (SimpleElement -> Channel -> b -> IO b)
    -> [Channel]
    -> PerChannel b
    pc SimpleElement -> Channel -> IO CLong
    getPlaybackVolume SimpleElement -> Channel -> CLong -> IO ()
    setPlaybackVolume
            comPerChannelDb :: [Channel] -> PerChannel CLong
    comPerChannelDb = (SimpleElement -> Channel -> IO CLong)
    -> (SimpleElement -> Channel -> CLong -> IO ())
    -> [Channel]
    -> PerChannel CLong
    forall b b.
    (SimpleElement -> Channel -> IO b)
    -> (SimpleElement -> Channel -> b -> IO b)
    -> [Channel]
    -> PerChannel b
    pc SimpleElement -> Channel -> IO CLong
    getPlaybackDb SimpleElement -> Channel -> CLong -> IO ()
    setPlaybackDb
            playJoinedVol :: [Channel] -> PerChannel CLong
    playJoinedVol = [Channel] -> PerChannel CLong
    comJoinedVol
            playPerChannelVol :: [Channel] -> PerChannel CLong
    playPerChannelVol = [Channel] -> PerChannel CLong
    comPerChannelVol
            playJoinedDb :: [Channel] -> PerChannel CLong
    playJoinedDb = [Channel] -> PerChannel CLong
    comJoinedDb
            playPerChannelDb :: [Channel] -> PerChannel CLong
    playPerChannelDb = [Channel] -> PerChannel CLong
    comPerChannelDb
            captJoinedVol :: [Channel] -> PerChannel CLong
    captJoinedVol = (SimpleElement -> Channel -> IO CLong)
    -> (SimpleElement -> Channel -> CLong -> IO ())
    -> [Channel]
    -> PerChannel CLong
    forall e.
    (SimpleElement -> Channel -> IO e)
    -> (SimpleElement -> Channel -> e -> IO ())
    -> [Channel]
    -> PerChannel e
    j SimpleElement -> Channel -> IO CLong
    getCaptureVolume SimpleElement -> Channel -> CLong -> IO ()
    setCaptureVolume
            captPerChannelVol :: [Channel] -> PerChannel CLong
    captPerChannelVol = (SimpleElement -> Channel -> IO CLong)
    -> (SimpleElement -> Channel -> CLong -> IO ())
    -> [Channel]
    -> PerChannel CLong
    forall b b.
    (SimpleElement -> Channel -> IO b)
    -> (SimpleElement -> Channel -> b -> IO b)
    -> [Channel]
    -> PerChannel b
    pc SimpleElement -> Channel -> IO CLong
    getCaptureVolume SimpleElement -> Channel -> CLong -> IO ()
    setCaptureVolume
            captJoinedDb :: [Channel] -> PerChannel CLong
    captJoinedDb = (SimpleElement -> Channel -> IO CLong)
    -> (SimpleElement -> Channel -> CLong -> IO ())
    -> [Channel]
    -> PerChannel CLong
    forall e.
    (SimpleElement -> Channel -> IO e)
    -> (SimpleElement -> Channel -> e -> IO ())
    -> [Channel]
    -> PerChannel e
    j SimpleElement -> Channel -> IO CLong
    getCaptureDb SimpleElement -> Channel -> CLong -> IO ()
    setCaptureDb
            captPerChannelDb :: [Channel] -> PerChannel CLong
    captPerChannelDb = (SimpleElement -> Channel -> IO CLong)
    -> (SimpleElement -> Channel -> CLong -> IO ())
    -> [Channel]
    -> PerChannel CLong
    forall b b.
    (SimpleElement -> Channel -> IO b)
    -> (SimpleElement -> Channel -> b -> IO b)
    -> [Channel]
    -> PerChannel b
    pc SimpleElement -> Channel -> IO CLong
    getCaptureDb SimpleElement -> Channel -> CLong -> IO ()
    setCaptureDb

    -- | All the 'Control' objects associated with a particular 'Mixer'.
    controls :: Mixer -> IO [Control]
    controls :: Mixer -> IO [Control]
    controls mix :: Mixer
    mix = do
        [(SimpleElementId, SimpleElement)]
    es <- Mixer -> IO [(SimpleElementId, SimpleElement)]
    elements Mixer
    mix
        [(SimpleElementId, SimpleElement)]
    -> ((SimpleElementId, SimpleElement) -> IO Control) -> IO [Control]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    t a -> (a -> m b) -> m (t b)
    forM [(SimpleElementId, SimpleElement)]
    es (((SimpleElementId, SimpleElement) -> IO Control) -> IO [Control])
    -> ((SimpleElementId, SimpleElement) -> IO Control) -> IO [Control]
    forall a b. (a -> b) -> a -> b
    $ \(idN :: SimpleElementId
    idN, se :: SimpleElement
    se) -> do
            String
    n <- SimpleElementId -> IO String
    getName SimpleElementId
    idN
            CUInt
    i <- SimpleElementId -> IO CUInt
    getIndex SimpleElementId
    idN
            Either Switch (Maybe Switch, Maybe Switch)
    sw <- SimpleElement -> IO (Either Switch (Maybe Switch, Maybe Switch))
    mkSwitch SimpleElement
    se
            Either Volume (Maybe Volume, Maybe Volume)
    v <- SimpleElement -> IO (Either Volume (Maybe Volume, Maybe Volume))
    mkVolume SimpleElement
    se
            Control -> IO Control
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Control -> IO Control) -> Control -> IO Control
    forall a b. (a -> b) -> a -> b
    $! Control :: CUInt
    -> String
    -> Either Switch (Maybe Switch, Maybe Switch)
    -> Either Volume (Maybe Volume, Maybe Volume)
    -> Control
    Control { name :: String
    name = String
    n
                              , index :: CUInt
    index = CUInt
    i
                              , switch :: Either Switch (Maybe Switch, Maybe Switch)
    switch = Either Switch (Maybe Switch, Maybe Switch)
    sw
                              , volume :: Either Volume (Maybe Volume, Maybe Volume)
    volume = Either Volume (Maybe Volume, Maybe Volume)
    v
                              }

    -- | Get the named 'Control', if it exists, from the named 'Mixer'.
    getControlByName :: Mixer   -- ^ Mixer
                     -> String  -- ^ Control name
                     -> IO (Maybe Control)
    getControlByName :: Mixer -> String -> IO (Maybe Control)
    getControlByName mix :: Mixer
    mix controlName :: String
    controlName = do
        [Control]
    cs <- Mixer -> IO [Control]
    controls Mixer
    mix
        Maybe Control -> IO (Maybe Control)
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Maybe Control -> IO (Maybe Control))
    -> Maybe Control -> IO (Maybe Control)
    forall a b. (a -> b) -> a -> b
    $ String -> [(String, Control)] -> Maybe Control
    forall a b. Eq a => a -> [(a, b)] -> Maybe b
    lookup String
    controlName ([(String, Control)] -> Maybe Control)
    -> [(String, Control)] -> Maybe Control
    forall a b. (a -> b) -> a -> b
    $ [String] -> [Control] -> [(String, Control)]
    forall a b. [a] -> [b] -> [(a, b)]
    zip ((Control -> String) -> [Control] -> [String]
    forall a b. (a -> b) -> [a] -> [b]
    map Control -> String
    name [Control]
    cs) [Control]
    cs

    {- $exampleVolume
    This example demonstrates the method of accessing the volume of a Control.
    The example function reads the volume and increases it by the value supplied.

    >   changeVolumeBy :: CLong -> IO ()
    >   changeVolumeBy i =
    >       withMixer "default" $ \mixer ->
    >         do Just control <- getControlByName mixer "Master"
    >            let Just playbackVolume = playback $ volume control
    >            (min, max) <- getRange playbackVolume
    >            Just vol <- getChannel FrontLeft $ value $ playbackVolume
    >            when ((i > 0 && vol < max) || (i < 0 && vol > min))
    >              $ setChannel FrontLeft (value $ playbackVolume) $ vol + i

    -}

    {- $exampleSwitch
    This example demonstrates the method of accessing the switch of a Control.
    The example function reads the value of the switch and toggles it.

    >   toggleMute :: IO ()
    >   toggleMute =
    >       withMixer "default" $ \mixer ->
    >         do Just control <- getControlByName mixer "Master"
    >            let Just playbackSwitch = playback $ switch control
    >            Just sw <- getChannel FrontLeft playbackSwitch
    >            setChannel FrontLeft playbackSwitch $ not sw

    -}