hsc3-lisp-0.15: hs/hsc3-lisp.hs
import Control.Monad.Except {- mtl -}
import Data.Char {- base -}
import qualified Data.Map as M {- containers -}
import Data.Maybe {- base -}
import Safe {- safe -}
import System.Environment {- base -}
import Sound.OSC {- hsc3 -}
import Sound.SC3 {- hsc3 -}
import Sound.SC3.UGen.Plain {- hsc3 -}
import Sound.SC3.UGen.PP {- hsc3 -}
import Sound.SC3.UGen.Dot {- hsc3-dot -}
import Lisp
ugen_to_int :: String -> UGen -> Int
ugen_to_int c u =
let err = error ("UGEN_TO_INT: " ++ c ++ ": " ++ show u)
f = floor . fromMaybe err . u_constant
in f u
instance Lisp_Ty UGen where
ty_show = ugen_concise_pp
ty_to_int = ugen_to_int "TY_TO_INT"
ty_from_bool t = if t then 1 else 0
lift_io :: IO () -> VM a (Cell a)
lift_io f = liftIO f >> return Nil
constant_err :: Cell UGen -> Double
constant_err c =
case fmap constant_opt (atom c) of
Just (Just n) -> n
_ -> error "NOT CONSTANT?"
ugen_to_double :: String -> UGen -> Double
ugen_to_double c u =
let err = error ("UGEN_TO_DOUBLE: " ++ c ++ ": " ++ show u)
f = fromMaybe err . u_constant
in f u
l_mk_ugen :: Cell UGen -> VM UGen (Cell UGen)
l_mk_ugen c = do
let l = to_list c
[nm,rt,inp,inp_mce,outp,sp,k] <- if length l == 7 then return l else throwError ("MK-UGEN: INCORRECT INPUT: " ++ show c)
inp_mce' <- case inp_mce of
Atom u -> return (mceChannels u)
Nil -> return []
_ -> throwError ("MK-UGEN: MCE-INPUT: " ++ show inp_mce)
sp' <- case sp of
Atom u -> return (Special (ugen_to_int "SPECIAL" u))
Nil -> return (Special 0)
_ -> throwError "MK-UGEN: SPECIAL?"
k' <- case k of
Atom u -> return (UId (ugen_to_int "UID" u))
Nil -> return NoId
_ -> throwError "MK-UGEN: UID?"
inp' <- fmap (++ inp_mce') (mapM atom_err (to_list inp))
rt' <- case rt of
Symbol sym -> return (fromJust (rate_parse (map toUpper sym)))
Cons _ _ -> do
let f = rateOf . atNote ("MK-UGEN: RATE: " ++ show c) inp' . ugen_to_int "RATE"
fmap maximum (mapM (fmap f . atom_err) (to_list rt))
_ -> throwError ("MK-UGEN: RATE: " ++ show rt)
nm' <- case nm of
String str -> return str
_ -> throwError ("MK-UGEN: NAME NOT STRING: " ++ show nm)
let outp' = floor (constant_err outp)
return (Atom (ugen_optimise_const_operator (mk_plain rt' nm' inp' outp' sp' k')))
l_is_number :: Cell UGen -> Cell UGen
l_is_number c =
case c of
Atom u -> if isConstant u then l_true else l_false
_ -> l_false
l_is_procedure :: Cell UGen -> Cell UGen
l_is_procedure c =
case c of
Fun _ -> l_true
Proc _ -> l_true
Lambda _ _ _ -> l_true
Macro _ -> l_true
_ -> l_false
l_clone_star :: Cell UGen -> VM UGen (Cell UGen)
l_clone_star c =
case to_list c of
[Atom k,Atom n,Atom u] ->
let k' = ugen_to_int "CLONE-K" k
n' = ugen_to_int "CLONE-N" n
in return (Atom (uclone k' n' u))
_ -> throwError ("clone*: " ++ show c)
l_play_at_star :: Cell UGen -> VM UGen (Cell UGen)
l_play_at_star c =
case to_list c of
[_,Atom u,Atom nid,Atom act,Atom grp] ->
let nid' = ugen_to_int "PLAY-AT: NID" nid
act' = ugen_to_int "PLAY-AT: ACT" act
grp' = ugen_to_int "PLAY-AT: GRP" grp
in lift_io (withSC3 (play_at (nid',toEnum act',grp') u)) >>
return Nil
_ -> throwError ("play-at*: " ++ show c)
l_thread_sleep :: Cell UGen -> VM UGen (Cell UGen)
l_thread_sleep c = do
u <- atom_err c
liftIO (pauseThread (ugen_to_double "pause" u))
return Nil
cell_to_datum :: Cell UGen -> VM a Datum
cell_to_datum c =
case c of
Symbol str -> return (string str)
String str -> return (string str)
Atom (Constant_U (Constant n)) -> return (float n)
_ -> throwError ("CELL-TO-DATUM: " ++ show c)
cell_to_message :: Cell UGen -> VM a Message
cell_to_message c =
case to_list' c of
Just (String addr : l) -> mapM cell_to_datum l >>= \l' -> return (Message addr l')
_ -> throwError ("CELL-TO-MESSAGE: " ++ show c)
l_async_star :: Cell UGen -> VM a (Cell a)
l_async_star c = cell_to_message c >>= \c' -> lift_io (withSC3 (void (async c')))
l_send_star :: Cell UGen -> VM a (Cell a)
l_send_star c = cell_to_message c >>= \c' -> lift_io (withSC3 (void (send c')))
ugen_dict :: Dict UGen
ugen_dict =
M.fromList
[("number?",Fun l_is_number)
,("string?",Fun (\c -> case c of {String _ -> l_true; _ -> l_false}))
,("symbol?",Fun (\c -> case c of {Symbol _ -> l_true; _ -> l_false}))
,("procedure?",Fun l_is_procedure)
,("mk-ugen",Proc l_mk_ugen)
,("clone*",Proc l_clone_star)
,("make-mce",Proc (\c -> fmap (Atom . mce) (mapM atom_err (to_list c))))
,("mce-channels",Proc (\c -> fmap (from_list . map Atom . mceChannels) (atom_err c)))
,("make-mrg*",Proc (\c -> fmap (Atom . mrg) (mapM atom_err (to_list c))))
,("show-graph",Proc (\c -> atom_err c >>= \u -> lift_io (draw (out 0 u))))
,("play-at*",Proc l_play_at_star)
,("reset*",Proc (\_ -> lift_io (withSC3 reset)))
,("thread-sleep",Proc l_thread_sleep)
,("utcr",Proc (\_ -> liftIO time >>= return . Atom . constant))
,("display-server-status",Proc (\_ -> lift_io (withSC3 serverStatus >>= mapM_ putStrLn)))
,("async*",Proc l_async_star)
,("send*",Proc l_send_star)
,("unrand",Proc (\c -> atom_err c >>= \u -> return (Atom (ugen_optimise_ir_rand u))))]
main :: IO ()
main = do
putStrLn "HSC3-LISP"
env <- gen_toplevel (M.unions [core_dict,ugen_dict]) :: IO (Env UGen)
let lib = ["stdlib.lisp"
,"scheme.lisp"
,"rhs.lisp" -- sw/rhs
,"rhs.syntax.lisp"
,"rsc3.prereq.lisp"
,"ugen.lisp" -- sw/rsc3
,"hsc3.lisp"
,"rsc3.lisp" -- sw/rsc3
]
a <- getArgs
repl env (load_files (lib ++ a))