packages feed

alga-0.1.0: src/Main.hs

-- -*- Mode: Haskell; -*-
--
-- Main module of ALGA describes logic of the program on top level.
--
-- Copyright © 2015 Mark Karpov
--
-- ALGA is free software: you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
-- Foundation, either version 3 of the License, or (at your option) any
-- later version.
--
-- ALGA is distributed in the hope that it will be useful, but WITHOUT ANY
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
-- details.
--
-- You should have received a copy of the GNU General Public License along
-- with this program. If not, see <http://www.gnu.org/licenses/>.

module Main (main) where

import Alga.Configuration
import Alga.Interaction
import Alga.Translation (toBackend)
import Control.Monad
import Data.Text.Lazy (Text)
import Data.Version (showVersion)
import Formatting
import Numeric.Natural
import Options.Applicative
import Path
import Paths_alga (version)
import System.Directory (getHomeDirectory, doesFileExist, getCurrentDirectory)
import qualified Data.Map as M
import qualified Data.Text.Lazy.IO as T

-- | ALGA application command line options.

data Opts = Opts
  { opInterac :: Bool  -- ^ Do we run in interactive mode?
  , opBackend :: String -- ^ Which backend to use?
  , opSeed    :: Natural -- ^ Seed for random number generator
  , opBeats   :: Double -- ^ Duration as number of whole notes
  , opTarget  :: String -- ^ XML file for patching
  , opLicense :: Bool  -- ^ Whether to show license
  , opVersion :: Bool  -- ^ Whether to show program's version
  , opFiles   :: [FilePath] -- ^ Source files to load
  }

-- | Entry point for the whole thing.

main :: IO ()
main = execParser opts >>= f
  where f Opts { opLicense = True } = T.putStr license
        f Opts { opVersion = True } = fprint ("ALGA " % string % "\n") ver
        f Opts { opFiles   = []
               , opBackend = β    } = g β interaction
        f Opts { opInterac = True
               , opBackend = β
               , opFiles   = ns   } = g β $ cmdLoad ns >> interaction
        f Opts { opBackend = β
               , opSeed    = s
               , opBeats   = b
               , opTarget  = trg
               , opFiles   = ns   } = g β $ cmdLoad ns >> cmdMake s b trg
        g β x   = T.putStrLn notice >> runAlga' (ξ β >> x)
        ξ β = unless (null β) (cmdBackend β)
        ver = showVersion version

-- | Shortish copyright notice.

notice :: Text
notice =
  "ALGA Copyright © 2015 Mark Karpov\n\n\
  \This program comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
  \and you are welcome to redistribute it under certain conditions; see\n\
  \GNU General Public License for details.\n"

-- | Longer copyright notice.

license :: Text
license =
  "ALGA — algorithmic automation for various DAWs.\n\
  \Copyright © 2015 Mark Karpov\n\
  \\n\
  \ALGA is free software: you can redistribute it and/or modify it under the\n\
  \terms of the GNU General Public License as published by the Free Software\n\
  \Foundation, either version 3 of the License, or (at your option) any\n\
  \later version.\n\
  \\n\
  \ALGA is distributed in the hope that it will be useful, but WITHOUT ANY\n\
  \WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n\
  \FOR A PARTICULAR PURPOSE. See the GNU General Public License for more\n\
  \details.\n\
  \\n\
  \You should have received a copy of the GNU General Public License along\n\
  \with this program. If not, see <http://www.gnu.org/licenses/>.\n"

-- | Read configuration file if present and run ALGA monad.

runAlga' :: Alga () -> IO ()
runAlga' e = do
  params <- loadConfig
  wdir   <- getCurrentDirectory >>= parseAbsDir
  dfname <- parseRelFile "foo.da"
  let dfltSrcFile = fromAbsFile (wdir </> dfname)
  srcFile <- parseAbsFile (lookupCfg params "src" dfltSrcFile)
  void $ runAlga e
    AlgaSt { stBackend = toBackend $ lookupCfg params "backend" "default"
           , stPrevLen = lookupCfg params "prvlen" 18
           , stSrcFile = srcFile }
    AlgaCfg { cfgPrecision = lookupCfg params "precision" 0.01
            , cfgPrompt    = lookupCfg params "prompt"    "> "
            , cfgVerbose   = lookupCfg params "verbose"   True }

-- | Read configuration file.

loadConfig :: IO Params
loadConfig = do
  home <- getHomeDirectory >>= parseAbsDir
  cfn  <- parseRelFile ".alga"
  let file = fromAbsFile (home </> cfn)
  exist <- doesFileExist file
  if exist
  then do params <- parseConfig file <$> T.readFile file
          case params of
            Right x -> return x
            Left  _ -> return M.empty
  else return M.empty

-- | Some information about the program.

opts :: ParserInfo Opts
opts =  info (helper <*> options)
      ( fullDesc
     <> progDesc "starts ALGA interpreter or patches given XML file"
     <> header "alga — algorithmic automation for various DAWs" )

-- | Description of command line options.

options :: Parser Opts
options = Opts
  <$> switch
  ( long "interactive"
  <> short 'i'
  <> help "Start ALGA in interactive mode" )
  <*> strOption
  ( long "backend"
  <> short 'B'
  <> metavar "DAW"
  <> value ""
  <> help "Specify which backend to use" )
  <*> option auto
  ( long "seed"
  <> short 's'
  <> metavar "SEED"
  <> value defaultSeed
  <> help ("Set seed for random numbers, default is " ++ show defaultSeed) )
  <*> option auto
  ( long "beats"
  <> short 'b'
  <> metavar "BEATS"
  <> value defaultBeats
  <> help ("Set total time in whole notes, default is " ++ show defaultBeats) )
  <*> strOption
  ( long "target"
  <> short 't'
  <> metavar "TARGET"
  <> value ""
  <> help "Specify target XML file for patching" )
  <*> switch
  ( long "license"
  <> help "Show license of the program" )
  <*> switch
  ( long "version"
  <> help "Show version of the program" )
  <*> many (strArgument $ metavar "FILES")