{-# Language DeriveFunctor #-} module Csound.Typed.GlobalState.Elements( -- * Identifiers IdMap(..), saveId, newIdMapId, -- ** Gens GenMap, newGen, newGenId, -- ** Band-limited waveforms BandLimited(..), BandLimitedMap, saveBandLimited, renderBandLimited, readBandLimited, readBandLimitedConstCps, -- ** String arguments StringMap, newString, -- * Global variables Globals(..), newPersistentGlobalVar, newClearableGlobalVar, renderGlobals, -- * Instruments Instrs(..), saveInstr, CacheName, makeCacheName, saveCachedInstr, -- * Src InstrBody, getIn, sendOut, sendChn, sendGlobal, Event(..), ChnRef(..), chnRefFromParg, chnRefAlloc, readChn, writeChn, chnUpdateUdo, subinstr, subinstr_, event_i, event, safeOut, autoOff, changed ) where import Control.Monad.Trans.State.Strict import Control.Monad(zipWithM_) import Data.Default import qualified Data.Map as M import qualified System.Mem.StableName.Dynamic as DM import qualified System.Mem.StableName.Dynamic.Map as DM import Csound.Dynamic.Types import Csound.Dynamic.Build import Csound.Dynamic.Build.Numeric() import Csound.Typed.GlobalState.Opcodes -- tables of identifiers data IdMap a = IdMap { idMapContent :: M.Map a Int , idMapNewId :: Int } instance Default (IdMap a) where def = IdMap def 1 saveId :: Ord a => a -> State (IdMap a) Int saveId a = state $ \s -> case M.lookup a (idMapContent s) of Nothing -> let newId = idMapNewId s s1 = s{ idMapContent = M.insert a newId (idMapContent s) , idMapNewId = succ newId } in (newId, s1) Just n -> (n, s) newIdMapId :: State (IdMap a) Int newIdMapId = state $ \s -> let newId = idMapNewId s s1 = s { idMapNewId = succ newId } in (newId, s1) -- gens type GenMap = IdMap Gen newGen :: Gen -> State GenMap E newGen = fmap int . saveId newGenId :: State GenMap Int newGenId = newIdMapId -- strings type StringMap = IdMap String newString :: String -> State StringMap Prim newString = fmap PrimInt . saveId -- band-limited waveforms (used with vco2init) data BandLimited = Saw | Pulse | Square | Triangle | IntegratedSaw | UserGen Gen deriving (Eq, Ord) type BandLimitedMap = M.Map BandLimited Int saveBandLimited :: BandLimited -> State (GenMap, BandLimitedMap) Int saveBandLimited x = case x of Saw -> simpleWave 1 0 IntegratedSaw -> simpleWave 2 1 Pulse -> simpleWave 4 2 Square -> simpleWave 8 3 Triangle -> simpleWave 16 4 UserGen _ -> userGen where simpleWave writeId readId = state $ \s@(genMap, blMap) -> if (M.member x blMap) then (readId, s) else (readId, (genMap, M.insert x writeId blMap)) userGen = state $ \s@(genMap, blMap) -> case M.lookup x blMap of Just n -> (n, s) Nothing -> let (newId, genMap1) = runState newGenId genMap blMap1 = M.insert x newId blMap in (negate newId, (genMap1, blMap1)) renderBandLimited :: Monad m => GenMap -> BandLimitedMap -> DepT m () renderBandLimited genMap blMap = case M.toList blMap of [] -> return () as -> render (idMapNewId genMap) (getUserGens as) as where render n gens vcos = do mapM_ renderGen gens renderFirstVco n (head vcos) mapM_ renderTailVco (tail vcos) getUserGens as = phi =<< as where phi (x, gId) = case x of UserGen g -> [(g, gId)] _ -> [] renderGen (g, n) = toDummy $ ftgen (int n) g renderFirstVco n x = renderVco (int n) x renderTailVco x = renderVco (readOnlyVar vcoVar) x renderVco ftId (wave, waveId) = toVcoVar $ vco2init $ case wave of UserGen _ -> [ int waveId, ftId, 1.05, -1, -1, int $ negate waveId ] _ -> [ int waveId, ftId ] vcoVar = dummyVar toVcoVar = toDummy dummyVar = Var LocalVar Ir "ft" toDummy = writeVar dummyVar readBandLimited :: Int -> E -> E readBandLimited n cps = oscilikt 1 cps (vco2ft cps (int n)) readBandLimitedConstCps :: Int -> E -> E readBandLimitedConstCps n cps = oscili 1 cps (vco2ift cps (int n)) -- global variables data Globals = Globals { globalsNewId :: Int , globalsVars :: [AllocVar] } data AllocVar = AllocVar { allocVarType :: GlobalVarType , allocVar :: Var , allocVarInit :: E } deriving (Show) data GlobalVarType = PersistentGlobalVar | ClearableGlobalVar deriving (Eq, Show) instance Default Globals where def = Globals def def newGlobalVar :: GlobalVarType -> Rate -> E -> State Globals Var newGlobalVar ty rate initVal = state $ \s -> let newId = globalsNewId s var = Var GlobalVar rate ('g' : show newId) s1 = s { globalsNewId = succ newId , globalsVars = AllocVar ty var initVal : globalsVars s } in (var, s1) newPersistentGlobalVar :: Rate -> E -> State Globals Var newPersistentGlobalVar = newGlobalVar PersistentGlobalVar newClearableGlobalVar :: Rate -> E -> State Globals Var newClearableGlobalVar = newGlobalVar ClearableGlobalVar renderGlobals :: Monad m => Globals -> (DepT m (), DepT m ()) renderGlobals a = (initAll, clear) where initAll = mapM_ (\x -> initVar (allocVar x) (allocVarInit x)) gs clear = mapM_ (\x -> writeVar (allocVar x) (allocVarInit x)) clearable clearable = filter ((== ClearableGlobalVar) . allocVarType) gs gs = globalsVars a ----------------------------------------------------------------- -- instrs data Instrs = Instrs { instrsCache :: DM.Map InstrId , instrsNewId :: Int , instrsContent :: [(InstrId, InstrBody)] } instance Default Instrs where def = Instrs DM.empty 18 [] type CacheName = DM.DynamicStableName makeCacheName :: a -> IO CacheName makeCacheName = DM.makeDynamicStableName ----------------------------------------------------------------- -- saveCachedInstr :: CacheName -> InstrBody -> State Instrs InstrId saveCachedInstr name body = state $ \s -> case DM.lookup name $ instrsCache s of Just n -> (n, s) Nothing -> let newId = instrsNewId s s1 = s { instrsCache = DM.insert name (intInstrId newId) $ instrsCache s , instrsNewId = succ newId , instrsContent = (intInstrId newId, body) : instrsContent s } in (intInstrId newId, s1) saveInstr :: InstrBody -> State Instrs InstrId saveInstr body = state $ \s -> let newId = instrsNewId s s1 = s { instrsNewId = succ newId , instrsContent = (intInstrId newId, body) : instrsContent s } in (intInstrId newId, s1) ----------------------------------------------------------------- -- sound sources getIn :: Monad m => Int -> DepT m [E] getIn arity | arity == 0 = return [] | otherwise = ($ arity ) $ mdepT $ mopcs name (replicate arity Ar, []) [] where name | arity == 1 = "in" | arity == 2 = "ins" | arity == 4 = "inq" | arity == 6 = "inh" | arity == 8 = "ino" | arity == 16 = "inx" | arity == 32 = "in32" | otherwise = "ins" sendOut :: Monad m => Int -> [E] -> DepT m () sendOut arity sigs | arity == 0 = return () | otherwise = do vars <- newLocalVars (replicate arity Ar) (return $ replicate arity 0) zipWithM_ writeVar vars sigs vals <- mapM readVar vars depT_ $ opcsNoInlineArgs name [(Xr, replicate arity Ar)] vals where name | arity == 1 = "out" | arity == 2 = "outs" | arity == 4 = "outq" | arity == 6 = "outh" | arity == 8 = "outo" | arity == 16 = "outx" | arity == 32 = "out32" | otherwise = "outc" sendGlobal :: Monad m => Int -> [E] -> State Globals ([E], DepT m ()) sendGlobal arityOuts sigs = do vars <- mapM (uncurry newClearableGlobalVar) $ replicate arityOuts (Ar, 0) return (fmap readOnlyVar vars, zipWithM_ (appendVarBy (+)) vars sigs) sendChn :: Monad m => Int -> Int -> [E] -> DepT m () sendChn arityIns arityOuts sigs = writeChn (chnRefFromParg (4 + arityIns) arityOuts) sigs -- guis