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))