packages feed

synthesizer-llvm-0.8: server/Synthesizer/LLVM/Server/OptionCommon.hs

{-
Guide for common Linux/Unix command-line options:
  http://www.faqs.org/docs/artu/ch10s05.html
-}
module Synthesizer.LLVM.Server.OptionCommon (
   module Synthesizer.LLVM.Server.OptionCommon,
   ClientName(ClientName),
   ) where

import qualified Synthesizer.LLVM.Server.Default as Default
import Synthesizer.LLVM.Server.Default (ClientName(ClientName), )
import Synthesizer.LLVM.Server.Common (SampleRate(SampleRate), )

import qualified Sound.MIDI.Message.Channel as ChannelMsg
import qualified Data.StorableVector.Lazy as SVL

import qualified System.Path.PartClass as PathClass
import qualified System.Path as Path

import qualified Options.Applicative as OP
import Control.Applicative ((<$>), (<*>), )
import Data.Monoid ((<>), )

import Prelude hiding (Real, )


clientName :: String -> OP.Parser ClientName
clientName help =
   OP.option (fmap ClientName OP.str)
      (OP.long "clientname" <>
       OP.metavar "NAME" <>
       OP.help help <>
       OP.value Default.clientName)


parseChannel :: OP.ReadM ChannelMsg.Channel
parseChannel =
   OP.eitherReader $ \str ->
   case reads str of
      [(chan, "")] ->
         if 0<=chan && chan<16
           then return $ ChannelMsg.toChannel chan
           else Left "MIDI channel must a number from 0..15"
      _ -> Left $ "channel must be a number, but is '" ++ str ++ "'"

channel, extraChannel :: OP.Parser ChannelMsg.Channel
channel =
   OP.option parseChannel
      (OP.short 'c' <>
       OP.long "channel" <>
       OP.metavar "CHANNEL" <>
       OP.help "Select MIDI input channel (0-based)" <>
       OP.value Default.channel)

extraChannel =
   OP.option parseChannel
      (OP.long "extra-channel" <>
       OP.metavar "CHANNEL" <>
       OP.help "Select MIDI channel with effects" <>
       OP.value (ChannelMsg.toChannel 1))

path :: (PathClass.FileDir fd) => OP.ReadM (Path.AbsRel fd)
path = OP.eitherReader Path.parse

sampleDirectory :: OP.Parser Path.AbsRelDir
sampleDirectory =
   OP.option path
      (OP.short 'I' <>
       OP.long "sample-directory" <>
       OP.metavar "DIR" <>
       OP.help "Directory for sound samples" <>
       OP.value Default.sampleDirectory)


maxInt :: Integer
maxInt = fromIntegral (maxBound :: Int)

parseNumber ::
   (Read a) =>
   String -> (a -> Bool) -> String -> OP.ReadM a
parseNumber name constraint constraintName =
   OP.eitherReader $ \str ->
   case reads str of
      [(n, "")] ->
         if constraint n
           then return n
           else Left $ name ++ " must be a " ++ constraintName ++ " number"
      _ -> Left $ name ++ " must be a number, but is '" ++ str ++ "'"

sampleRate :: OP.Parser (Maybe (SampleRate Int))
sampleRate =
   OP.option
      (Just . SampleRate . fromInteger <$>
       parseNumber "sample-rate" (\n -> 0<n && n<=maxInt) "positive")
      (OP.short 'r' <>
       OP.long "samplerate" <>
       OP.metavar "RATE" <>
       OP.value Nothing <>
       OP.help "Sample-rate in samples per second")

blockSize :: SVL.ChunkSize -> OP.Parser SVL.ChunkSize
blockSize deflt =
   OP.option
      (SVL.ChunkSize . fromInteger <$>
       parseNumber "blocksize" (\n -> 0<n && n<=maxInt) "positive")
      (OP.short 'b' <>
       OP.long "blocksize" <>
       OP.metavar "SIZE" <>
       OP.value deflt <>
       OP.help "Block size as number of sample-frames")


get :: OP.Parser a -> String -> IO a
get parser descr =
   OP.execParser $
   OP.info
      (OP.helper <*> parser)
      (OP.fullDesc <> OP.progDesc descr)