module MixerQuery ( mixerDevices, mixerChannels, setVol ) where import Data.List (isInfixOf, sort) import Data.List.Split (splitOn) import System.IO (FilePath) import System.Directory (getDirectoryContents) import System.Process (runInteractiveCommand) import GHC.IO.Handle (hGetContents) -- | Gets all available mixer devices on this system. mixerDevices :: IO [FilePath] mixerDevices = fmap (("Default" :) . map ((++) "/dev/") . sort . filter (isInfixOf "mixer")) $ getDirectoryContents "/dev" -- | Gets the channels from a mixer device. mixerChannels :: FilePath -> IO [(String, (Int, Int))] mixerChannels mixer = fmap (parseMixerLines . lines) ((runInteractiveCommand $ command mixer) >>= (\(_, stdout, _, _) -> hGetContents stdout)) where command "Default" = "mixer" command mixer' = "mixer -f " ++ mixer' -- | Parses out the channel names and volumes from the output -- of the mixer command. parseMixerLines :: [String] -> [(String, (Int, Int))] parseMixerLines lines = [(line !! 1, parseLevels $ last line) | line <- map words $ filter (isInfixOf "Mixer ") lines] where parseLevels str = (\(x:y:_) -> (read x, read y)) $ splitOn ":" str -- | Sets the volume of a channel. setVol :: String -> String -> Int -> Int -> IO () setVol mixer channel left right | mixer == "Default" = (runInteractiveCommand (unwords ["mixer", channel, (show left) ++ ":" ++ (show right)])) >> return () | otherwise = (runInteractiveCommand (unwords ["mixer", "-f", mixer, channel, (show left) ++ ":" ++ (show right)])) >> return ()