{-# Language FlexibleInstances, UndecidableInstances, CPP #-}
-- | Rendering of Csound files and playing the music in real time.
--
-- How are we going to get the sound out of Haskell code?
-- Instruments are ready and we have written all the scores for them.
-- Now, it's time to use the rendering functions. We can render haskell expressions
-- to Csound code. A rendering function takes a value that represents a sound (it's a tuple of signals)
-- and produces a string with Csound code. It can take a value that represents
-- the flags for the csound compiler and global settings ('Csound.Options').
-- Then we can save this string to file and convert it to sound with csound compiler
--
-- > csound -o music.wav music.csd
--
-- Or we can play it in real time with -odac flag. It sends the sound directly to
-- soundcard. It's usefull when we are using midi or tweek the parameters in real time
-- with sliders or knobs.
--
-- > csound -odac music.csd
--
-- The main function of this module is 'Csound.IO.renderCsdBy'. Other function are nothing but
-- wrappers that produce the Csound code and make something useful with it (saving to file,
-- playing with specific player or in real time).
module Csound.IO (
    -- * Rendering
    RenderCsd(..),
    CsdArity(..),
    renderCsd,
    writeCsd, writeCsdBy,
    writeSnd, writeSndBy,

    -- * Playing the sound
    playCsd, playCsdBy,
    mplayer, mplayerBy, totem, totemBy,

    -- * Live performance
    dac, dacBy, vdac, vdacBy,

    -- * Render and run
    csd, csdBy,

    -- * Save user options
    saveUserOptions,

    -- * Render and run with cabbage
    runCabbage, runCabbageBy,

    -- * Aliases for type inference
    -- | Sometimes the type class @RenderCsd@ is too whide for us.
    -- It cn be hard to use in the interpreter without explicit signatures.
    -- There are functions to help the type inference.
    -- ** For processing inputs
    onCard1, onCard2, onCard4, onCard6, onCard8,

    -- * Config with command line arguments
    -- | With the functions we can add global config parameters to the rendered file.
    -- We can supply different parameters with @--omacro@ flag.
    --
    -- An example:
    --
    -- > dac $ osc (sig $ readMacrosDouble "FREQ" 440)
    --
    -- Here we define frequency as a global parameter. It's available by name @"FREQ"@.
    -- If we run the program with no flags it would play the default 440 Hz. But we can change that like this:
    --
    -- > csound tmp.csd --omacro:FREQ=330
    --
    -- We can update the macro-arguments with flag @--omacro:NAME=VALUE@.
    readMacrosString, readMacrosDouble, readMacrosInt
) where

--import Control.Concurrent
import Control.Monad

import System.Process
import qualified Control.Exception as E

import Data.Default
import Csound.Typed
import Csound.Control.Gui

import Csound.Options(setSilent, setDac, setAdc, setDacBy, setAdcBy, setCabbage)
import Temporal.Class(Harmony(..))

import qualified Data.List as L

render :: Sigs a => Options -> SE a -> IO String
render :: Options -> SE a -> IO String
render = Options -> SE a -> IO String
forall a. Sigs a => Options -> SE a -> IO String
renderOutBy

render_ :: Options -> SE () -> IO String
render_ :: Options -> SE () -> IO String
render_ = Options -> SE () -> IO String
renderOutBy_

data CsdArity = CsdArity
  { CsdArity -> Int
csdArity'inputs  :: Int
  , CsdArity -> Int
csdArity'outputs :: Int
  } deriving (Int -> CsdArity -> ShowS
[CsdArity] -> ShowS
CsdArity -> String
(Int -> CsdArity -> ShowS)
-> (CsdArity -> String) -> ([CsdArity] -> ShowS) -> Show CsdArity
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [CsdArity] -> ShowS
$cshowList :: [CsdArity] -> ShowS
show :: CsdArity -> String
$cshow :: CsdArity -> String
showsPrec :: Int -> CsdArity -> ShowS
$cshowsPrec :: Int -> CsdArity -> ShowS
Show, CsdArity -> CsdArity -> Bool
(CsdArity -> CsdArity -> Bool)
-> (CsdArity -> CsdArity -> Bool) -> Eq CsdArity
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CsdArity -> CsdArity -> Bool
$c/= :: CsdArity -> CsdArity -> Bool
== :: CsdArity -> CsdArity -> Bool
$c== :: CsdArity -> CsdArity -> Bool
Eq)

class RenderCsd a where
    renderCsdBy :: Options -> a -> IO String
    csdArity :: a -> CsdArity

hasInputs :: RenderCsd a => a -> Bool
hasInputs :: a -> Bool
hasInputs = ( Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0) (Int -> Bool) -> (a -> Int) -> a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CsdArity -> Int
csdArity'inputs (CsdArity -> Int) -> (a -> CsdArity) -> a -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> CsdArity
forall a. RenderCsd a => a -> CsdArity
csdArity

hasOutputs :: RenderCsd a => a -> Bool
hasOutputs :: a -> Bool
hasOutputs = ( Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0) (Int -> Bool) -> (a -> Int) -> a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CsdArity -> Int
csdArity'outputs (CsdArity -> Int) -> (a -> CsdArity) -> a -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> CsdArity
forall a. RenderCsd a => a -> CsdArity
csdArity

instance {-# OVERLAPPING #-} RenderCsd (SE ()) where
    renderCsdBy :: Options -> SE () -> IO String
renderCsdBy = Options -> SE () -> IO String
render_
    csdArity :: SE () -> CsdArity
csdArity SE ()
_ = Int -> Int -> CsdArity
CsdArity Int
0 Int
0

#if __GLASGOW_HASKELL__ >= 710
instance {-# OVERLAPPABLE #-} Sigs a => RenderCsd a where
  renderCsdBy :: Options -> a -> IO String
renderCsdBy Options
opt a
a = Options -> SE a -> IO String
forall a. Sigs a => Options -> SE a -> IO String
render Options
opt (a -> SE a
forall (m :: * -> *) a. Monad m => a -> m a
return a
a)
  csdArity :: a -> CsdArity
csdArity a
a = Int -> Int -> CsdArity
CsdArity Int
0 (a -> Int
forall a. Tuple a => a -> Int
tupleArity a
a)

instance {-# OVERLAPPABLE #-} Sigs a => RenderCsd (SE a) where
  renderCsdBy :: Options -> SE a -> IO String
renderCsdBy Options
opt SE a
a = Options -> SE a -> IO String
forall a. Sigs a => Options -> SE a -> IO String
render Options
opt SE a
a
  csdArity :: SE a -> CsdArity
csdArity SE a
a = Int -> Int -> CsdArity
CsdArity Int
0 (SE a -> Int
forall a. Tuple a => SE a -> Int
outArity SE a
a)

instance {-# OVERLAPPABLE #-} Sigs a => RenderCsd (Source a) where
  renderCsdBy :: Options -> Source a -> IO String
renderCsdBy Options
opt Source a
a = Options -> SE a -> IO String
forall a. RenderCsd a => Options -> a -> IO String
renderCsdBy Options
opt (Source a -> SE a
forall a. Source a -> SE a
fromSource Source a
a)
  csdArity :: Source a -> CsdArity
csdArity Source a
a = Int -> Int -> CsdArity
CsdArity Int
0 (a -> Int
forall a. Tuple a => a -> Int
tupleArity (a -> Int) -> a -> Int
forall a b. (a -> b) -> a -> b
$ Source a -> a
forall a. Source a -> a
proxySource Source a
a)
      where

instance {-# OVERLAPPABLE #-} Sigs a => RenderCsd (Source (SE a)) where
  renderCsdBy :: Options -> Source (SE a) -> IO String
renderCsdBy Options
opt Source (SE a)
a = Options -> SE a -> IO String
forall a. RenderCsd a => Options -> a -> IO String
renderCsdBy Options
opt (Source (SE a) -> SE a
forall a. Source (SE a) -> SE a
fromSourceSE Source (SE a)
a)
  csdArity :: Source (SE a) -> CsdArity
csdArity Source (SE a)
a = Int -> Int -> CsdArity
CsdArity Int
0 (a -> Int
forall a. Tuple a => a -> Int
tupleArity (a -> Int) -> a -> Int
forall a b. (a -> b) -> a -> b
$ SE a -> a
forall a. SE a -> a
proxySE (SE a -> a) -> SE a -> a
forall a b. (a -> b) -> a -> b
$ Source (SE a) -> SE a
forall a. Source a -> a
proxySource Source (SE a)
a)

instance {-# OVERLAPPABLE #-} Sigs a => RenderCsd (Sco (Mix a)) where
  renderCsdBy :: Options -> Sco (Mix a) -> IO String
renderCsdBy Options
opt Sco (Mix a)
a = Options -> a -> IO String
forall a. RenderCsd a => Options -> a -> IO String
renderCsdBy Options
opt (Sco (Mix a) -> a
forall a. Sigs a => Sco (Mix a) -> a
mix Sco (Mix a)
a)
  csdArity :: Sco (Mix a) -> CsdArity
csdArity Sco (Mix a)
a = Int -> Int -> CsdArity
CsdArity Int
0 (a -> Int
forall a. Tuple a => a -> Int
tupleArity (a -> Int) -> a -> Int
forall a b. (a -> b) -> a -> b
$ Sco (Mix a) -> a
forall a. Sco (Mix a) -> a
proxy Sco (Mix a)
a)
    where
      proxy :: Sco (Mix a) -> a
      proxy :: Sco (Mix a) -> a
proxy = a -> Sco (Mix a) -> a
forall a b. a -> b -> a
const a
forall a. HasCallStack => a
undefined

instance {-# OVERLAPPABLE #-} Sigs a => RenderCsd [Sco (Mix a)] where
  renderCsdBy :: Options -> [Sco (Mix a)] -> IO String
renderCsdBy Options
opt [Sco (Mix a)]
a = Options -> a -> IO String
forall a. RenderCsd a => Options -> a -> IO String
renderCsdBy Options
opt (Sco (Mix a) -> a
forall a. Sigs a => Sco (Mix a) -> a
mix (Sco (Mix a) -> a) -> Sco (Mix a) -> a
forall a b. (a -> b) -> a -> b
$ [Sco (Mix a)] -> Sco (Mix a)
forall a. Harmony a => [a] -> a
har [Sco (Mix a)]
a)
  csdArity :: [Sco (Mix a)] -> CsdArity
csdArity [Sco (Mix a)]
a = Int -> Int -> CsdArity
CsdArity Int
0 (a -> Int
forall a. Tuple a => a -> Int
tupleArity (a -> Int) -> a -> Int
forall a b. (a -> b) -> a -> b
$ [Sco (Mix a)] -> a
forall a. [Sco (Mix a)] -> a
proxy [Sco (Mix a)]
a)
    where
      proxy :: [Sco (Mix a)] -> a
      proxy :: [Sco (Mix a)] -> a
proxy = a -> [Sco (Mix a)] -> a
forall a b. a -> b -> a
const a
forall a. HasCallStack => a
undefined

#endif

proxySource :: Source a -> a
proxySource :: Source a -> a
proxySource = a -> Source a -> a
forall a b. a -> b -> a
const a
forall a. HasCallStack => a
undefined

proxySE :: SE a -> a
proxySE :: SE a -> a
proxySE = a -> SE a -> a
forall a b. a -> b -> a
const a
forall a. HasCallStack => a
undefined

proxyFun :: (a -> b) -> (a, b)
proxyFun :: (a -> b) -> (a, b)
proxyFun = (a, b) -> (a -> b) -> (a, b)
forall a b. a -> b -> a
const (a, b)
forall a. HasCallStack => a
undefined

proxyIn :: (a -> b) -> a
proxyIn :: (a -> b) -> a
proxyIn = (a, b) -> a
forall a b. (a, b) -> a
fst ((a, b) -> a) -> ((a -> b) -> (a, b)) -> (a -> b) -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b) -> (a, b)
forall a b. (a -> b) -> (a, b)
proxyFun

proxyOut :: (a -> b) -> b
proxyOut :: (a -> b) -> b
proxyOut = (a, b) -> b
forall a b. (a, b) -> b
snd ((a, b) -> b) -> ((a -> b) -> (a, b)) -> (a -> b) -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> b) -> (a, b)
forall a b. (a -> b) -> (a, b)
proxyFun

instance {-# OVERLAPPABLE #-} (Sigs a, Sigs b) => RenderCsd (a -> b) where
    renderCsdBy :: Options -> (a -> b) -> IO String
renderCsdBy Options
opt a -> b
f = Options -> (a -> SE b) -> IO String
forall a b. (Sigs a, Sigs b) => Options -> (a -> SE b) -> IO String
renderEffBy Options
opt (b -> SE b
forall (m :: * -> *) a. Monad m => a -> m a
return (b -> SE b) -> (a -> b) -> a -> SE b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> b
f)
    csdArity :: (a -> b) -> CsdArity
csdArity a -> b
a = Int -> Int -> CsdArity
CsdArity (a -> Int
forall a. Tuple a => a -> Int
tupleArity (a -> Int) -> a -> Int
forall a b. (a -> b) -> a -> b
$ (a -> b) -> a
forall a b. (a -> b) -> a
proxyIn a -> b
a) (b -> Int
forall a. Tuple a => a -> Int
tupleArity (b -> Int) -> b -> Int
forall a b. (a -> b) -> a -> b
$ (a -> b) -> b
forall a b. (a -> b) -> b
proxyOut a -> b
a)

instance {-# OVERLAPPABLE #-} (Sigs a, Sigs b) => RenderCsd (a -> SE b) where
    renderCsdBy :: Options -> (a -> SE b) -> IO String
renderCsdBy Options
opt a -> SE b
f = Options -> (a -> SE b) -> IO String
forall a b. (Sigs a, Sigs b) => Options -> (a -> SE b) -> IO String
renderEffBy Options
opt a -> SE b
f
    csdArity :: (a -> SE b) -> CsdArity
csdArity a -> SE b
a = Int -> Int -> CsdArity
CsdArity (a -> Int
forall a. Tuple a => a -> Int
tupleArity (a -> Int) -> a -> Int
forall a b. (a -> b) -> a -> b
$ (a -> SE b) -> a
forall a b. (a -> b) -> a
proxyIn a -> SE b
a) (b -> Int
forall a. Tuple a => a -> Int
tupleArity (b -> Int) -> b -> Int
forall a b. (a -> b) -> a -> b
$ SE b -> b
forall a. SE a -> a
proxySE (SE b -> b) -> SE b -> b
forall a b. (a -> b) -> a -> b
$ (a -> SE b) -> SE b
forall a b. (a -> b) -> b
proxyOut a -> SE b
a)

instance {-# OVERLAPPABLE #-} (Sigs a, Sigs b) => RenderCsd (a -> Source b) where
    renderCsdBy :: Options -> (a -> Source b) -> IO String
renderCsdBy Options
opt a -> Source b
f = Options -> (a -> SE b) -> IO String
forall a b. (Sigs a, Sigs b) => Options -> (a -> SE b) -> IO String
renderEffBy Options
opt (Source b -> SE b
forall a. Source a -> SE a
fromSource (Source b -> SE b) -> (a -> Source b) -> a -> SE b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Source b
f)
    csdArity :: (a -> Source b) -> CsdArity
csdArity a -> Source b
a = Int -> Int -> CsdArity
CsdArity (a -> Int
forall a. Tuple a => a -> Int
tupleArity (a -> Int) -> a -> Int
forall a b. (a -> b) -> a -> b
$ (a -> Source b) -> a
forall a b. (a -> b) -> a
proxyIn a -> Source b
a) (b -> Int
forall a. Tuple a => a -> Int
tupleArity (b -> Int) -> b -> Int
forall a b. (a -> b) -> a -> b
$ Source b -> b
forall a. Source a -> a
proxySource (Source b -> b) -> Source b -> b
forall a b. (a -> b) -> a -> b
$ (a -> Source b) -> Source b
forall a b. (a -> b) -> b
proxyOut a -> Source b
a)

instance (Sigs a, Sigs b) => RenderCsd (a -> Source (SE b)) where
    renderCsdBy :: Options -> (a -> Source (SE b)) -> IO String
renderCsdBy Options
opt a -> Source (SE b)
f = Options -> (a -> SE b) -> IO String
forall a b. (Sigs a, Sigs b) => Options -> (a -> SE b) -> IO String
renderEffBy Options
opt (Source (SE b) -> SE b
forall a. Source (SE a) -> SE a
fromSourceSE (Source (SE b) -> SE b) -> (a -> Source (SE b)) -> a -> SE b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Source (SE b)
f)
    csdArity :: (a -> Source (SE b)) -> CsdArity
csdArity a -> Source (SE b)
a = Int -> Int -> CsdArity
CsdArity (a -> Int
forall a. Tuple a => a -> Int
tupleArity (a -> Int) -> a -> Int
forall a b. (a -> b) -> a -> b
$ (a -> Source (SE b)) -> a
forall a b. (a -> b) -> a
proxyIn a -> Source (SE b)
a) (b -> Int
forall a. Tuple a => a -> Int
tupleArity (b -> Int) -> b -> Int
forall a b. (a -> b) -> a -> b
$ SE b -> b
forall a. SE a -> a
proxySE (SE b -> b) -> SE b -> b
forall a b. (a -> b) -> a -> b
$ Source (SE b) -> SE b
forall a. Source a -> a
proxySource (Source (SE b) -> SE b) -> Source (SE b) -> SE b
forall a b. (a -> b) -> a -> b
$ (a -> Source (SE b)) -> Source (SE b)
forall a b. (a -> b) -> b
proxyOut a -> Source (SE b)
a)

instance {-# OVERLAPPING #-} (Sigs a) => RenderCsd (a -> Source (SE Sig2)) where
    renderCsdBy :: Options -> (a -> Source (SE Sig2)) -> IO String
renderCsdBy Options
opt a -> Source (SE Sig2)
f = Options -> (a -> SE Sig2) -> IO String
forall a b. (Sigs a, Sigs b) => Options -> (a -> SE b) -> IO String
renderEffBy Options
opt (Source (SE Sig2) -> SE Sig2
forall a. Source (SE a) -> SE a
fromSourceSE (Source (SE Sig2) -> SE Sig2)
-> (a -> Source (SE Sig2)) -> a -> SE Sig2
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Source (SE Sig2)
f)
    csdArity :: (a -> Source (SE Sig2)) -> CsdArity
csdArity a -> Source (SE Sig2)
a = Int -> Int -> CsdArity
CsdArity (a -> Int
forall a. Tuple a => a -> Int
tupleArity (a -> Int) -> a -> Int
forall a b. (a -> b) -> a -> b
$ (a -> Source (SE Sig2)) -> a
forall a b. (a -> b) -> a
proxyIn a -> Source (SE Sig2)
a) (Sig2 -> Int
forall a. Tuple a => a -> Int
tupleArity (Sig2 -> Int) -> Sig2 -> Int
forall a b. (a -> b) -> a -> b
$ SE Sig2 -> Sig2
forall a. SE a -> a
proxySE (SE Sig2 -> Sig2) -> SE Sig2 -> Sig2
forall a b. (a -> b) -> a -> b
$ Source (SE Sig2) -> SE Sig2
forall a. Source a -> a
proxySource (Source (SE Sig2) -> SE Sig2) -> Source (SE Sig2) -> SE Sig2
forall a b. (a -> b) -> a -> b
$ (a -> Source (SE Sig2)) -> Source (SE Sig2)
forall a b. (a -> b) -> b
proxyOut a -> Source (SE Sig2)
a)

instance {-# OVERLAPPING #-} RenderCsd (Source ()) where
    renderCsdBy :: Options -> Source () -> IO String
renderCsdBy Options
opt Source ()
src = Options -> SE () -> IO String
forall a. RenderCsd a => Options -> a -> IO String
renderCsdBy Options
opt (SE () -> IO String) -> SE () -> IO String
forall a b. (a -> b) -> a -> b
$ do
        (Gui
ui, ()
_) <- Source ()
src
        Gui -> SE ()
panel Gui
ui
    csdArity :: Source () -> CsdArity
csdArity Source ()
_ = Int -> Int -> CsdArity
CsdArity Int
0 Int
0

instance {-# OVERLAPPING #-} RenderCsd (Source (SE ())) where
    renderCsdBy :: Options -> Source (SE ()) -> IO String
renderCsdBy Options
opt Source (SE ())
src = Options -> Source () -> IO String
forall a. RenderCsd a => Options -> a -> IO String
renderCsdBy Options
opt (Source (SE ()) -> Source ()
forall a. Source (SE a) -> Source a
joinSource Source (SE ())
src)
    csdArity :: Source (SE ()) -> CsdArity
csdArity Source (SE ())
_ = Int -> Int -> CsdArity
CsdArity Int
0 Int
0

-- | Renders Csound file.
renderCsd :: RenderCsd a => a -> IO String
renderCsd :: a -> IO String
renderCsd = Options -> a -> IO String
forall a. RenderCsd a => Options -> a -> IO String
renderCsdBy Options
forall a. Default a => a
def

-- | Render Csound file and save it to the give file.
writeCsd :: RenderCsd a => String -> a -> IO ()
writeCsd :: String -> a -> IO ()
writeCsd String
file a
a = String -> String -> IO ()
writeFile String
file (String -> IO ()) -> IO String -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< a -> IO String
forall a. RenderCsd a => a -> IO String
renderCsd a
a

-- | Render Csound file with options and save it to the give file.
writeCsdBy :: RenderCsd a => Options -> String -> a -> IO ()
writeCsdBy :: Options -> String -> a -> IO ()
writeCsdBy Options
opt String
file a
a = String -> String -> IO ()
writeFile String
file (String -> IO ()) -> IO String -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Options -> a -> IO String
forall a. RenderCsd a => Options -> a -> IO String
renderCsdBy Options
opt a
a

-- | Render Csound file and save result sound to the wav-file.
writeSnd :: RenderCsd a => String -> a -> IO ()
writeSnd :: String -> a -> IO ()
writeSnd = Options -> String -> a -> IO ()
forall a. RenderCsd a => Options -> String -> a -> IO ()
writeSndBy Options
forall a. Default a => a
def

-- | Render Csound file with options and save result sound to the wav-file.
writeSndBy :: RenderCsd a => Options -> String -> a -> IO ()
writeSndBy :: Options -> String -> a -> IO ()
writeSndBy Options
opt String
file a
a = do
    Options -> String -> a -> IO ()
forall a. RenderCsd a => Options -> String -> a -> IO ()
writeCsdBy Options
opt String
fileCsd a
a
    IO () -> String -> IO ()
runWithUserInterrupt (Options -> IO ()
postSetup Options
opt) (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords [String
"csound -o", String
file, String
fileCsd, Options -> String
logTrace Options
opt]
    where fileCsd :: String
fileCsd = String
"tmp.csd"

logTrace :: Options -> String
logTrace :: Options -> String
logTrace Options
opt
  | Options -> Bool
csdNeedTrace Options
opt = String
""
  | Bool
otherwise        = String
"--logfile=null"

-- | Renders Csound file, saves it to the given file, renders with csound command and plays it with the given program.
--
-- > playCsd program file csd
--
-- Produces files @file.csd@ (with 'Csound.Render.Mix.renderCsd') and @file.wav@ (with @csound@) and then invokes:
--
-- > program "file.wav"
playCsd :: (RenderCsd a) => (String -> IO ()) -> String -> a -> IO ()
playCsd :: (String -> IO ()) -> String -> a -> IO ()
playCsd = Options -> (String -> IO ()) -> String -> a -> IO ()
forall a.
RenderCsd a =>
Options -> (String -> IO ()) -> String -> a -> IO ()
playCsdBy Options
forall a. Default a => a
def

-- | Works just like 'Csound.Render.Mix.playCsd' but you can supply csound options.
playCsdBy :: (RenderCsd a) => Options -> (String -> IO ()) -> String -> a -> IO ()
playCsdBy :: Options -> (String -> IO ()) -> String -> a -> IO ()
playCsdBy Options
opt String -> IO ()
player String
file a
a = do
    Options -> String -> a -> IO ()
forall a. RenderCsd a => Options -> String -> a -> IO ()
writeCsdBy Options
opt String
fileCsd a
a
    IO () -> String -> IO ()
runWithUserInterrupt (Options -> IO ()
postSetup Options
opt) (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords [String
"csound -o", String
fileWav, String
fileCsd, Options -> String
logTrace Options
opt]
    String -> IO ()
player String
fileWav
    () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
    where fileCsd :: String
fileCsd = String
file String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
".csd"
          fileWav :: String
fileWav = String
file String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
".wav"

simplePlayCsdBy :: (RenderCsd a) => Options -> String -> String -> a -> IO ()
simplePlayCsdBy :: Options -> String -> String -> a -> IO ()
simplePlayCsdBy Options
opt String
player = Options -> (String -> IO ()) -> String -> a -> IO ()
forall a.
RenderCsd a =>
Options -> (String -> IO ()) -> String -> a -> IO ()
playCsdBy Options
opt String -> IO ()
phi
    where phi :: String -> IO ()
phi String
file = do
            IO () -> String -> IO ()
runWithUserInterrupt (() -> IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()) (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords [String
player, String
file]

-- | Renders csound code to file @tmp.csd@ with flags set to @-odac@, @-iadc@ and @-Ma@
-- (sound output goes to soundcard in real time).
dac :: (RenderCsd a) => a -> IO ()
dac :: a -> IO ()
dac = Options -> a -> IO ()
forall a. RenderCsd a => Options -> a -> IO ()
dacBy Options
forall a. Default a => a
def

-- | 'Csound.Base.dac' with options.
dacBy :: (RenderCsd a) => Options -> a -> IO ()
dacBy :: Options -> a -> IO ()
dacBy Options
opt' a
a = do
    Options -> String -> a -> IO ()
forall a. RenderCsd a => Options -> String -> a -> IO ()
writeCsdBy Options
opt String
"tmp.csd" a
a
    IO () -> String -> IO ()
runWithUserInterrupt (Options -> IO ()
postSetup Options
opt') (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords [String
"csound tmp.csd", Options -> String
logTrace Options
opt']
    where
      opt :: Options
opt = [Options] -> Options
forall a. Monoid a => [a] -> a
mconcat [Options
opt', Options
withDac, Options
withAdc]

      withDac :: Options
withDac
        | Options -> Bool
hasJackConnections Options
opt' = String -> Options
setDacBy String
"null"
        | a -> Bool
forall a. RenderCsd a => a -> Bool
hasOutputs a
a            = Options
setDac
        | Bool
otherwise               = Options
forall a. Monoid a => a
mempty

      withAdc :: Options
withAdc
        | Options -> Bool
hasJackConnections Options
opt' = String -> Options
setAdcBy String
"null"
        | a -> Bool
forall a. RenderCsd a => a -> Bool
hasInputs a
a             = Options
setAdc
        | Bool
otherwise               = Options
forall a. Monoid a => a
mempty

-- | Output to dac with virtual midi keyboard.
vdac :: (RenderCsd a) => a -> IO ()
vdac :: a -> IO ()
vdac = Options -> a -> IO ()
forall a. RenderCsd a => Options -> a -> IO ()
dacBy (Options -> Options
setVirtual Options
forall a. Default a => a
def)

-- | Output to dac with virtual midi keyboard with specified options.
vdacBy :: (RenderCsd a) => Options -> a -> IO ()
vdacBy :: Options -> a -> IO ()
vdacBy Options
opt = Options -> a -> IO ()
forall a. RenderCsd a => Options -> a -> IO ()
dacBy (Options -> Options
setVirtual Options
opt)

setVirtual :: Options -> Options
setVirtual :: Options -> Options
setVirtual Options
a = Options
a { csdFlags :: Flags
csdFlags = (Options -> Flags
csdFlags Options
a) { rtmidi :: Maybe Rtmidi
rtmidi = Rtmidi -> Maybe Rtmidi
forall a. a -> Maybe a
Just Rtmidi
VirtualMidi, midiRT :: MidiRT
midiRT = MidiRT
m { midiDevice :: Maybe String
midiDevice = String -> Maybe String
forall a. a -> Maybe a
Just String
"0" } } }
    where m :: MidiRT
m = Flags -> MidiRT
midiRT (Flags -> MidiRT) -> Flags -> MidiRT
forall a b. (a -> b) -> a -> b
$ Options -> Flags
csdFlags Options
a

-- | Renders to file @tmp.csd@ and invokes the csound on it.
csd :: (RenderCsd a) => a -> IO ()
csd :: a -> IO ()
csd = Options -> a -> IO ()
forall a. RenderCsd a => Options -> a -> IO ()
csdBy Options
setSilent

-- | Renders to file @tmp.csd@ and invokes the csound on it.
csdBy :: (RenderCsd a) => Options -> a -> IO ()
csdBy :: Options -> a -> IO ()
csdBy Options
options a
a = do
    Options -> String -> a -> IO ()
forall a. RenderCsd a => Options -> String -> a -> IO ()
writeCsdBy (Options
setSilent Options -> Options -> Options
forall a. Monoid a => a -> a -> a
`mappend` Options
options) String
"tmp.csd" a
a
    IO () -> String -> IO ()
runWithUserInterrupt (Options -> IO ()
postSetup Options
options) (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ [String] -> String
unwords [String
"csound tmp.csd", Options -> String
logTrace Options
options]

postSetup :: Options -> IO ()
postSetup :: Options -> IO ()
postSetup Options
opt = Options -> IO ()
jackConnect Options
opt

jackConnect :: Options -> IO ()
jackConnect :: Options -> IO ()
jackConnect Options
opt
  | Just [(String, String)]
conns <- Options -> Maybe [(String, String)]
csdJackConnect Options
opt = case [(String, String)]
conns of
                                         [] -> () -> IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
                                         [(String, String)]
_  -> IO ProcessHandle -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO ProcessHandle -> IO ()) -> IO ProcessHandle -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> IO ProcessHandle
runCommand (String -> IO ProcessHandle) -> String -> IO ProcessHandle
forall a b. (a -> b) -> a -> b
$ [(String, String)] -> String
jackCmd [(String, String)]
conns
  | Bool
otherwise                        = () -> IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
  where
    addSleep :: ShowS
addSleep = (String
"sleep 0.1; " String -> ShowS
forall a. Monoid a => a -> a -> a
`mappend` )

    jackCmd :: [(String, String)] -> String
jackCmd = ShowS
addSleep ShowS
-> ([(String, String)] -> String) -> [(String, String)] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
L.intercalate String
";" ([String] -> String)
-> ([(String, String)] -> [String]) -> [(String, String)] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((String, String) -> String) -> [(String, String)] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (String, String) -> String
jackConn
    jackConn :: (String, String) -> String
jackConn (String
port1, String
port2) = [String] -> String
unwords [String
"jack_connect", String
port1, String
port2]

hasJackConnections :: Options -> Bool
hasJackConnections :: Options -> Bool
hasJackConnections Options
opt
  | Just [(String, String)]
conns <- Options -> Maybe [(String, String)]
csdJackConnect Options
opt = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ [(String, String)] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(String, String)]
conns
  | Bool
otherwise                        = Bool
False

----------------------------------------------------------
-- players

-- | Renders to tmp.csd and tmp.wav and plays with mplayer.
mplayer :: (RenderCsd a) => a -> IO ()
mplayer :: a -> IO ()
mplayer = Options -> a -> IO ()
forall a. RenderCsd a => Options -> a -> IO ()
mplayerBy Options
forall a. Default a => a
def

-- | Renders to tmp.csd and tmp.wav and plays with mplayer.
mplayerBy :: (RenderCsd a) => Options -> a -> IO ()
mplayerBy :: Options -> a -> IO ()
mplayerBy Options
opt = Options -> String -> String -> a -> IO ()
forall a. RenderCsd a => Options -> String -> String -> a -> IO ()
simplePlayCsdBy Options
opt String
"mplayer" String
"tmp"

-- | Renders to tmp.csd and tmp.wav and plays with totem player.
totem :: (RenderCsd a) => a -> IO ()
totem :: a -> IO ()
totem = Options -> a -> IO ()
forall a. RenderCsd a => Options -> a -> IO ()
totemBy Options
forall a. Default a => a
def

-- | Renders to tmp.csd and tmp.wav and plays with totem player.
totemBy :: (RenderCsd a) => Options -> a -> IO ()
totemBy :: Options -> a -> IO ()
totemBy Options
opt = Options -> String -> String -> a -> IO ()
forall a. RenderCsd a => Options -> String -> String -> a -> IO ()
simplePlayCsdBy Options
opt String
"totem" String
"tmp"

----------------------------------------------------------
-- handle user interrupts

runWithUserInterrupt :: IO () -> String -> IO ()
runWithUserInterrupt :: IO () -> String -> IO ()
runWithUserInterrupt IO ()
setup String
cmd = do
    ProcessHandle
pid <- String -> IO ProcessHandle
runCommand String
cmd
    IO ()
setup
    IO () -> (AsyncException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
E.catch (ProcessHandle -> IO ExitCode
waitForProcess ProcessHandle
pid IO ExitCode -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) (ProcessHandle -> AsyncException -> IO ()
onUserInterrupt ProcessHandle
pid)
    where
        onUserInterrupt :: ProcessHandle -> E.AsyncException -> IO ()
        onUserInterrupt :: ProcessHandle -> AsyncException -> IO ()
onUserInterrupt ProcessHandle
pid AsyncException
x = case AsyncException
x of
            AsyncException
E.UserInterrupt -> ProcessHandle -> IO ()
terminateProcess ProcessHandle
pid
            AsyncException
e               -> AsyncException -> IO ()
forall a e. Exception e => e -> a
E.throw AsyncException
e

----------------------------------------------------------

-- | Runs the csound files with cabbage engine.
-- It invokes the Cabbage command line utility and setts all default cabbage flags.
runCabbage :: (RenderCsd a) => a -> IO ()
runCabbage :: a -> IO ()
runCabbage = Options -> a -> IO ()
forall a. RenderCsd a => Options -> a -> IO ()
runCabbageBy Options
forall a. Default a => a
def

-- | Runs the csound files with cabbage engine with user defined options.
-- It invokes the Cabbage command line utility and setts all default cabbage flags.
runCabbageBy :: (RenderCsd a) => Options -> a -> IO ()
runCabbageBy :: Options -> a -> IO ()
runCabbageBy Options
opt' a
a = do
    Options -> String -> a -> IO ()
forall a. RenderCsd a => Options -> String -> a -> IO ()
writeCsdBy Options
opt String
"tmp.csd" a
a
    IO () -> String -> IO ()
runWithUserInterrupt (() -> IO ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()) (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Cabbage tmp.csd"
    where opt :: Options
opt = Options
opt' Options -> Options -> Options
forall a. Monoid a => a -> a -> a
`mappend` Options
setCabbage

------------------------------

-- | Alias to process inputs of single input audio-card.
onCard1 :: (Sig -> a) -> (Sig -> a)
onCard1 :: (Sig -> a) -> Sig -> a
onCard1= (Sig -> a) -> Sig -> a
forall a. a -> a
id

-- | Alias to process inputs of stereo input audio-card.
onCard2 :: (Sig2 -> a) -> (Sig2 -> a)
onCard2 :: (Sig2 -> a) -> Sig2 -> a
onCard2= (Sig2 -> a) -> Sig2 -> a
forall a. a -> a
id

-- | Alias to process inputs of audio-card with 4 inputs.
onCard4 :: (Sig4 -> a) -> (Sig4 -> a)
onCard4 :: (Sig4 -> a) -> Sig4 -> a
onCard4= (Sig4 -> a) -> Sig4 -> a
forall a. a -> a
id

-- | Alias to process inputs of audio-card with 6 inputs.
onCard6 :: (Sig6 -> a) -> (Sig6 -> a)
onCard6 :: (Sig6 -> a) -> Sig6 -> a
onCard6= (Sig6 -> a) -> Sig6 -> a
forall a. a -> a
id

-- | Alias to process inputs of audio-card with 8 inputs.
onCard8 :: (Sig8 -> a) -> (Sig8 -> a)
onCard8 :: (Sig8 -> a) -> Sig8 -> a
onCard8= (Sig8 -> a) -> Sig8 -> a
forall a. a -> a
id


#if __GLASGOW_HASKELL__ < 710

-- Sig
setArity n a = CsdArity 0 n

instance RenderCsd Sig                  where { renderCsdBy opt a = render opt (return a)             , csdArity = setArity 1 }
instance RenderCsd (SE Sig)             where { renderCsdBy opt a = render opt a }                    , csdArity = setArity 1 }
instance RenderCsd (Source Sig)         where { renderCsdBy opt a = renderCsdBy opt (fromSource a)    , csdArity = setArity 1 }
instance RenderCsd (Source (SE Sig))    where { renderCsdBy opt a = renderCsdBy opt (fromSourceSE a)  , csdArity = setArity 1 }

-- Sig2

instance RenderCsd Sig2                  where { renderCsdBy opt a = render opt (return a)            , csdArity = setArity 2 }
instance RenderCsd (SE Sig2)             where { renderCsdBy opt a = render opt a                     , csdArity = setArity 2 }
instance RenderCsd (Source Sig2)         where { renderCsdBy opt a = renderCsdBy opt (fromSource a)   , csdArity = setArity 2 }
instance RenderCsd (Source (SE Sig2))    where { renderCsdBy opt a = renderCsdBy opt (fromSourceSE a) , csdArity = setArity 2 }

-- Sig3

instance RenderCsd Sig3                  where { renderCsdBy opt a = render opt (return a)            , csdArity = setArity 3 }
instance RenderCsd (SE Sig3)             where { renderCsdBy opt a = render opt a                     , csdArity = setArity 3 }
instance RenderCsd (Source Sig3)         where { renderCsdBy opt a = renderCsdBy opt (fromSource a)   , csdArity = setArity 3 }
instance RenderCsd (Source (SE Sig3))    where { renderCsdBy opt a = renderCsdBy opt (fromSourceSE a) , csdArity = setArity 3 }

-- Sig4

instance RenderCsd Sig4                  where { renderCsdBy opt a = render opt (return a)            , csdArity = setArity 4 }
instance RenderCsd (SE Sig4)             where { renderCsdBy opt a = render opt a                     , csdArity = setArity 4 }
instance RenderCsd (Source Sig4)         where { renderCsdBy opt a = renderCsdBy opt (fromSource a)   , csdArity = setArity 4 }
instance RenderCsd (Source (SE Sig4))    where { renderCsdBy opt a = renderCsdBy opt (fromSourceSE a) , csdArity = setArity 4 }

-- Sig5

instance RenderCsd Sig5                  where { renderCsdBy opt a = render opt (return a)            , csdArity = setArity 5 }
instance RenderCsd (SE Sig5)             where { renderCsdBy opt a = render opt a                     , csdArity = setArity 5 }
instance RenderCsd (Source Sig5)         where { renderCsdBy opt a = renderCsdBy opt (fromSource a)   , csdArity = setArity 5 }
instance RenderCsd (Source (SE Sig5))    where { renderCsdBy opt a = renderCsdBy opt (fromSourceSE a) , csdArity = setArity 5 }

-- Sig6

instance RenderCsd Sig6                  where { renderCsdBy opt a = render opt (return a)            , csdArity = setArity 6 }
instance RenderCsd (SE Sig6)             where { renderCsdBy opt a = render opt a                     , csdArity = setArity 6 }
instance RenderCsd (Source Sig6)         where { renderCsdBy opt a = renderCsdBy opt (fromSource a)   , csdArity = setArity 6 }
instance RenderCsd (Source (SE Sig6))    where { renderCsdBy opt a = renderCsdBy opt (fromSourceSE a) , csdArity = setArity 6 }

-- Sig7

instance RenderCsd Sig7                  where { renderCsdBy opt a = render opt (return a)            , csdArity = setArity 7 }
instance RenderCsd (SE Sig7)             where { renderCsdBy opt a = render opt a                     , csdArity = setArity 7 }
instance RenderCsd (Source Sig7)         where { renderCsdBy opt a = renderCsdBy opt (fromSource a)   , csdArity = setArity 7 }
instance RenderCsd (Source (SE Sig7))    where { renderCsdBy opt a = renderCsdBy opt (fromSourceSE a) , csdArity = setArity 7 }


-- Sig8

instance RenderCsd Sig8                  where { renderCsdBy opt a = render opt (return a)            , csdArity = setArity 8 }
instance RenderCsd (SE Sig8)             where { renderCsdBy opt a = render opt a                     , csdArity = setArity 8 }
instance RenderCsd (Source Sig8)         where { renderCsdBy opt a = renderCsdBy opt (fromSource a)   , csdArity = setArity 8 }
instance RenderCsd (Source (SE Sig8))    where { renderCsdBy opt a = renderCsdBy opt (fromSourceSE a) , csdArity = setArity 8 }


instance RenderCsd (Sco (Mix Sig))       where { renderCsdBy opt a = renderCsdBy opt $ mix a , csdArity = setArity 1 }
instance RenderCsd (Sco (Mix Sig2))      where { renderCsdBy opt a = renderCsdBy opt $ mix a , csdArity = setArity 2 }
instance RenderCsd (Sco (Mix Sig3))      where { renderCsdBy opt a = renderCsdBy opt $ mix a , csdArity = setArity 3 }
instance RenderCsd (Sco (Mix Sig4))      where { renderCsdBy opt a = renderCsdBy opt $ mix a , csdArity = setArity 4 }
instance RenderCsd (Sco (Mix Sig5))      where { renderCsdBy opt a = renderCsdBy opt $ mix a , csdArity = setArity 5 }

instance RenderCsd [Sco (Mix Sig)]       where { renderCsdBy opt a = renderCsdBy opt $ mix $ har a , csdArity = setArity 1 }
instance RenderCsd [Sco (Mix Sig2)]      where { renderCsdBy opt a = renderCsdBy opt $ mix $ har a , csdArity = setArity 2 }
instance RenderCsd [Sco (Mix Sig3)]      where { renderCsdBy opt a = renderCsdBy opt $ mix $ har a , csdArity = setArity 3 }
instance RenderCsd [Sco (Mix Sig4)]      where { renderCsdBy opt a = renderCsdBy opt $ mix $ har a , csdArity = setArity 4 }
instance RenderCsd [Sco (Mix Sig5)]      where { renderCsdBy opt a = renderCsdBy opt $ mix $ har a , csdArity = setArity 5 }

#endif