alsa-midi-0.3.2: examples/PlayMIDI.hs
module Main where
import qualified Sound.ALSA.Sequencer as SndSeq
import qualified Sound.ALSA.Sequencer.FFI as SndSeqFFI
import qualified Sound.ALSA.Sequencer.Play as SndSeqPlay
import qualified Sound.MIDI.File.Load as MIDILoad
-- import Control.Exception (bracket)
-- import Control.Monad.Error () -- Monad instance for Either
import Control.Monad (when)
import System.Console.GetOpt (getOpt, ArgOrder(..), OptDescr(..), ArgDescr(..), usageInfo)
import System.Environment (getArgs)
import System.Exit (exitWith, ExitCode(..))
play :: SndSeqFFI.Address -> FilePath -> IO ()
play dstAddress fileName =
MIDILoad.fromFile fileName >>= SndSeqPlay.run dstAddress
parseAddress :: String -> Either String SndSeqFFI.Address
parseAddress str0 =
let addrs =
do (client, ':':str1) <- reads str0
(port, []) <- reads str1
return $ SndSeq.numAddressEither client port
in case addrs of
[addr] -> addr
_ -> Left "address must be a string like '128:0'"
{-
parseAddressNaive :: String -> SndSeqFFI.Address
parseAddressNaive str =
let (client, ':':port) = break (':'==) str
in SndSeqFFI.Address (read client) (read port)
-}
data Flags =
Flags {
optHelp :: Bool,
optPort :: Either String SndSeqFFI.Address
}
options :: [OptDescr (Flags -> Flags)]
options =
Option ['h'] ["help"] (NoArg (\ flags -> flags{optHelp = True})) "show options" :
Option ['p'] ["port"] (ReqArg (\str flags -> flags{optPort = parseAddress str}) "PORT") "destination PORT" :
[]
main :: IO ()
main =
do argv <- getArgs
let (opts, files, errors) = getOpt RequireOrder options argv
when (not (null errors))
(ioError . userError . concat $ errors)
let flags = foldr ($)
(Flags {optHelp = False,
optPort = Left "no port specified"}) opts
when (optHelp flags)
(putStrLn (usageInfo "Usage: playmidi [OPTIONS] FILES ..." options) >>
exitWith ExitSuccess)
port <-
either
(ioError . userError)
return
(optPort flags)
mapM_ (play port) files