packages feed

csound-expression-typed 0.0.9.1 → 0.0.9.2

raw patch · 18 files changed

+702/−66 lines, 18 filesdep ~csound-expression-dynamicPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: csound-expression-dynamic

API changes (from Hackage documentation)

- Csound.Typed.Control: Ref :: [Var] -> Ref a
- Csound.Typed.Control: newtype Ref a
+ Csound.Typed.Control: data Ref a
+ Csound.Typed.Control: namedMonoMsg :: D -> D -> String -> SE (Sig, Sig)
+ Csound.Typed.Control: newClearableGlobalRef :: Tuple a => a -> SE (Ref a)
+ Csound.Typed.Control: newClearableGlobalVars :: [Rate] -> GE [E] -> SE [Var]
+ Csound.Typed.Control: newCtrlRef :: Tuple a => a -> SE (Ref a)
+ Csound.Typed.Control: newGlobalCtrlRef :: Tuple a => a -> SE (Ref a)
+ Csound.Typed.Control: newGlobalTab :: Int -> SE Tab
+ Csound.Typed.Control: newTab :: D -> SE Tab
+ Csound.Typed.Control: trigByName :: (Arg a, Sigs b) => String -> (a -> SE b) -> SE b
+ Csound.Typed.Control: trigByNameMidi :: (Arg a, Sigs b) => String -> ((D, D, a) -> SE b) -> SE b
+ Csound.Typed.Control: trigByNameMidi_ :: forall a. Arg a => String -> ((D, D, a) -> SE ()) -> SE ()
+ Csound.Typed.Control: trigByName_ :: Arg a => String -> (a -> SE ()) -> SE ()
+ Csound.Typed.Render: [tabNamedFiGens] :: TabFi -> Map String Int
+ Csound.Typed.Render: idExp :: String
+ Csound.Typed.Render: idFarey :: String
+ Csound.Typed.Render: idPadsynth :: String
+ Csound.Typed.Render: idSone :: String
+ Csound.Typed.Render: idTanh :: String
+ Csound.Typed.Render: idWave :: String
+ Csound.Typed.Types.Prim: infix 4 `greaterThanEquals`
+ Csound.Typed.Types.Prim: instance Data.Default.Class.Default Csound.Typed.Types.Prim.TabList
+ Csound.Typed.Types.Prim: preStringTab :: TabSize -> String -> TabArgs -> Tab
+ Csound.Typed.Types.Prim: untilBeginD :: BoolD -> SE ()
+ Csound.Typed.Types.Prim: untilDoD :: BoolD -> SE () -> SE ()
+ Csound.Typed.Types.Prim: whenD1 :: BoolD -> SE () -> SE ()
+ Csound.Typed.Types.Prim: whenDs :: [(BoolD, SE ())] -> SE () -> SE ()
+ Csound.Typed.Types.Prim: whileDoD :: BoolD -> SE () -> SE ()
+ Csound.Typed.Types.Tuple: instance Csound.Typed.Types.Tuple.Arg Csound.Typed.Types.Prim.TabList
+ Csound.Typed.Types.Tuple: instance Csound.Typed.Types.Tuple.Tuple Csound.Typed.Types.Prim.TabList
- Csound.Typed.Control: listenOsc :: Tuple a => OscRef -> OscAddress -> OscType -> Evt a
+ Csound.Typed.Control: listenOsc :: forall a. Tuple a => OscRef -> OscAddress -> OscType -> Evt a
- Csound.Typed.Control: sendOsc :: Tuple a => OscHost -> OscPort -> OscAddress -> OscType -> Evt a -> SE ()
+ Csound.Typed.Control: sendOsc :: forall a. Tuple a => OscHost -> OscPort -> OscAddress -> OscType -> Evt a -> SE ()
- Csound.Typed.Render: TabFi :: Int -> IntMap Int -> TabFi
+ Csound.Typed.Render: TabFi :: Int -> IntMap Int -> Map String Int -> TabFi
- Csound.Typed.Render: fineFi :: Int -> [(Int, Int)] -> TabFi
+ Csound.Typed.Render: fineFi :: Int -> [(Int, Int)] -> [(String, Int)] -> TabFi

Files

csound-expression-typed.cabal view
@@ -1,5 +1,5 @@ Name:          csound-expression-typed-Version:       0.0.9.1+Version:       0.0.9.2 Cabal-Version: >= 1.22 License:       BSD3 License-file:  LICENSE@@ -23,7 +23,10 @@     data/hrtf-96000-left.dat     data/hrtf-96000-right.dat +    data/opcodes/tabQueue.udo+    data/opcodes/tabQueue2.udo + Homepage:        https://github.com/anton-k/csound-expression-typed Bug-Reports:     https://github.com/anton-k/csound-expression-typed/issues @@ -36,7 +39,7 @@   Ghc-Options:    -Wall   Build-Depends:         base >= 4, base < 5, ghc-prim, containers, transformers >= 0.3, Boolean >= 0.1.0, colour >= 2.0, data-default, deepseq,-        wl-pprint, csound-expression-dynamic >= 0.1.5, temporal-media >= 0.6.0, hashable+        wl-pprint, csound-expression-dynamic >= 0.1.6, temporal-media >= 0.6.0, hashable   Hs-Source-Dirs:      src/   Exposed-Modules:     Csound.Typed@@ -69,6 +72,7 @@     Csound.Typed.Control.Vco     Csound.Typed.Control.Mix     Csound.Typed.Control.Midi+    Csound.Typed.Control.Api     Csound.Typed.Control.Sf2     Csound.Typed.Control.Osc     Csound.Typed.Control.Channel@@ -84,6 +88,8 @@      Csound.Typed.Lib.StableMaps.Dynamic     Csound.Typed.Lib.StableMaps.Dynamic.Map++    Csound.Typed.Plugins.TabQueue      Paths_csound_expression_typed 
+ data/opcodes/tabQueue.udo view
@@ -0,0 +1,45 @@+opcode TabQueue_Append, 0, ii+itab, ival xin+ind = 0+ik tab_i ind, itab+tabw_i ival, (ik + 1), itab+tabw_i (ik + 1), ind, itab+endop++opcode TabQueue_Delete, 0,ii+itab, ival xin+ind = 0+iLast tab_i ind, itab+iCount = 1+iFound = 0+until iCount > iLast do+    iCur tab_i iCount, itab+    if (iCur == ival) then+        iFound = 1+        tabw_i (iLast - 1), ind, itab+    endif++    if (iFound == 1) then+        iNext tab_i (iCount + 1), itab+        tabw_i iNext, iCount, itab+    endif++    iCount = iCount + 1+od+endop++opcode TabQueue_HasElement, k, i+itab xin+knd = 0+kk tab knd, itab+kres = (kk == 0) ? 0 : 1+xout kres+endop++opcode TabQueue_ReadLastElement, k, i+itab xin+knd = 0+kk tab knd, itab+kres tab kk, itab+xout kres+endop
+ data/opcodes/tabQueue2.udo view
@@ -0,0 +1,50 @@++opcode TabQueue2_Append, 0, iii+itab, ival1, ival2 xin+ind = 0+ik tab_i ind, itab+tabw_i ival1, (2 * (ik + 1)    ), itab+tabw_i ival2, (2 * (ik + 1) + 1), itab+tabw_i (ik + 1), ind, itab+endop++opcode TabQueue2_Delete, 0,ii+itab, ival xin+ind = 0+iLast tab_i ind, itab+iCount = 1+iFound = 0+until iCount > iLast do+    iCur tab_i (2 * iCount), itab+    if (iCur == ival) then+        iFound = 1+        tabw_i (iLast - 1), ind, itab+    endif++    if (iFound == 1) then+        iNext1 tab_i (2 * (iCount + 1))    , itab+        iNext2 tab_i (2 * (iCount + 1) + 1), itab+        tabw_i iNext1, (2 * iCount)    , itab+        tabw_i iNext2, (2 * iCount + 1), itab+    endif++    iCount = iCount + 1+od+endop++opcode TabQueue2_HasElements, k, i+itab xin+knd = 0+kk tab knd, itab+kres = (kk == 0) ? 0 : 1+xout kres+endop++opcode TabQueue2_ReadLastElement, kk, i+itab xin+knd = 0+kk tab knd, itab+kres1 tab (2 * kk)    , itab+kres2 tab (2 * kk + 1), itab+xout kres1, kres2+endop
src/Csound/Typed/Control.hs view
@@ -11,6 +11,8 @@     module Csound.Typed.Control.Mix,     -- * Midi     module Csound.Typed.Control.Midi,+    -- * Named instruments (API)+    module Csound.Typed.Control.Api,     -- * OSC     module Csound.Typed.Control.Osc,     -- * Channel@@ -29,6 +31,7 @@ import Csound.Typed.Control.Evt import Csound.Typed.Control.Mix import Csound.Typed.Control.Midi+import Csound.Typed.Control.Api import Csound.Typed.Control.Osc import Csound.Typed.Control.Channel import Csound.Typed.Control.Sf2
+ src/Csound/Typed/Control/Api.hs view
@@ -0,0 +1,178 @@+{-# Language ScopedTypeVariables #-}+module Csound.Typed.Control.Api(+    trigByName, trigByName_,+    trigByNameMidi, trigByNameMidi_,+    namedMonoMsg+) where++import Data.Boolean+import Control.Monad.Trans.Class++import qualified Csound.Dynamic as D+import Csound.Dynamic(Rate(..), opcs, depT_)+import Data.Boolean((==*), (>*), ifB)++import Csound.Typed.Types+import Csound.Typed.Control.Ref+import Csound.Typed.GlobalState+import Csound.Typed.GlobalState.Opcodes(eventi, Event(..), turnoff, port, downsamp)++import Csound.Typed.Plugins.TabQueue++-- | Creates an instrument that can be triggered by name with Csound API.+-- The arguments are determined from the structure of the input for the instrument.+--+-- With Csound API we can send messages +--+-- > i "name" time duration arg1 arg2 arg3+trigByName_ :: Arg a => String -> (a -> SE ()) -> SE ()+trigByName_ name instr = geToSe $ saveNamedInstr name =<< (execSE $ instr toArg)++-- | Creates an instrument that can be triggered by name with Csound API.+-- The arguments are determined from the structure of the input for the instrument.+-- If we have a tuple of arguments: @(D, D, Tab)@+-- The would be rendered to instrument arguments that strts from @p4@.+-- @p1@ is the name of teh instrument, @p2@ is the start time of the note, +-- @p3@ is the duration of the note. Then @p4@ and @p5@ are going to be doubles and @p6@+-- is an integer that denotes a functional table.+trigByName  :: (Arg a, Sigs b) => String -> (a -> SE b) -> SE b+trigByName name instr = do+    ref <- newClearableGlobalRef 0+    trigByName_ name (go ref)+    readRef ref    +    where go ref x = mixRef ref =<< instr x+++-- | It behaves just like the function @trigByNameMidi@. Only it doesn't produce an audio+-- signal. It performs some procedure on note on and stops doing the precedure on note off.+trigByNameMidi_ :: forall a . Arg a => String -> ((D, D, a) -> SE ()) -> SE ()+trigByNameMidi_ name instr = do+    instrId <- geToSe $ saveInstr (instr toArg)+    trigByName_ name (go instrId)+    where+        go :: D.InstrId -> (D, D, D, a) -> SE ()+        go instrId (noteFlag, pch, vol, other) = fromDep_ $ hideGEinDep $ do+            pchExpr      <- toGE pch+            let instrIdExpr = D.instrIdE instrId + pchExpr / 1000+            noteFlagExpr <- toGE noteFlag+            args <- fromTuple (pch, vol, other)            +            return $ do+                    D.when1 (noteFlagExpr ==* 1) $ do+                        eventi (Event instrIdExpr 0 (-1) args)+                    D.when1 (noteFlagExpr ==* 0) $ do+                        eventi (Event (negate instrIdExpr) 0 0 args)+                    turnoff++-- | Creates an instrument that can be triggered by name with Csound API.+--+-- It's intended to be used like a midi instrument. It simulates a simplified midi protocol.+-- We can trigger notes:+--+-- > i "givenName" delay duration 1 pitchKey volumeKey auxParams     -- note on+-- > i "givenName" delay duration 0 pitchKey volumeKey auxParams     -- note off+--+-- The arguments are+--+-- > trigByNameMidi name instrument+--+-- The instrument takes a triplet of @(pitchKey, volumeKey, auxilliaryTuple)@.+-- The order does matter. Please don't pass the @volumeKey@ as the first argument.+-- The instrument expects the pitch key to be a first argument. ++-- Under the hood+-- it creates held notes that are indexed by pitch. If you know the Csound it creates+-- the notes with indexes:+--+-- > i 18.pitchKey+--+-- Here the 18 is some generated integer index. And then on receiving a note a note off message for the specific key the+-- Csound procedure invokes:+--+-- > turnoff 18.pitchKey+trigByNameMidi  :: (Arg a, Sigs b) => String -> ((D, D, a) -> SE b) -> SE b+trigByNameMidi name instr = do+    ref <- newClearableGlobalRef 0+    trigByNameMidi_ name (go ref)+    readRef ref    +    where go ref x = mixRef ref =<< instr x++namedMonoMsg :: D -> D -> String -> SE (Sig, Sig)+namedMonoMsg portTime relTime name = do+    refPch <- newGlobalRef 0+    refVol <- newGlobalRef 0+    tab <- newGlobalTab 24+    let onFlag = tabQueue2_hasElements tab+    trigByNameMidiCbk name (onNote tab) (offNote tab)+    when1 onFlag $ do+        let (pch, vol) = tabQueue2_readLastElement tab+        writeRef refPch pch+        writeRef refVol vol+    when1 (notB onFlag) $ do+        writeRef refVol 0+    pchKey <- readRef refPch+    volKey <- readRef refVol+    let resStatus = ifB onFlag 1 0+    return (port' (downsamp' volKey) portTime * port' resStatus relTime,  port' (downsamp' pchKey) portTime)+    where        +        onNote = tabQueue2_append        +        offNote tab (pch, vol) = tabQueue2_delete tab pch++trigByNameMidiCbk :: String -> ((D, D) -> SE ())  -> ((D, D) -> SE ()) -> SE ()+trigByNameMidiCbk name noteOn noteOff = +    trigByName_ name go+    where+        go :: (D, D, D) -> SE ()+        go (noteFlag, pch, vol) = do            +            whenD1 (noteFlag ==* 1) $ noteOn (pch, vol)+            whenD1 (noteFlag ==* 0) $ noteOff (pch, vol)+            SE turnoff++port' :: Sig -> D -> Sig+port' a b = fromGE $ do+    a' <- toGE a+    b' <- toGE b+    return $ port a' b'++downsamp' :: Sig -> Sig+downsamp' a = fromGE $ do+    a' <- toGE a    +    return $ downsamp a'++-- | +-- Fast table opcodes.+--+-- Fast table opcodes. Faster than+--     table and+--     tablew because don't+--     allow wrap-around and limit and don't check index validity. Have+--     been implemented in order to provide fast access to+--     arrays. Support non-power of two tables (can be generated by any+--     GEN function by giving a negative length value).+--+-- >  tabw  ksig, kndx, ifn [,ixmode]+-- >  tabw  asig, andx, ifn [,ixmode]+--+-- csound doc: <http://www.csounds.com/manual/html/tab.html>+tabw ::  Sig -> Sig -> Tab -> SE ()+tabw b1 b2 b3 = SE $ (depT_ =<<) $ lift $ f <$> unSig b1 <*> unSig b2 <*> unTab b3+    where f a1 a2 a3 = opcs "tabw" [(Xr,[Kr,Kr,Ir,Ir])] [a1,a2,a3]+++-- | +-- Fast table opcodes.+--+-- Fast table opcodes. Faster than+--     table and+--     tablew because don't+--     allow wrap-around and limit and don't check index validity. Have+--     been implemented in order to provide fast access to+--     arrays. Support non-power of two tables (can be generated by any+--     GEN function by giving a negative length value).+--+-- > kr  tab  kndx, ifn[, ixmode]+-- > ar  tab  xndx, ifn[, ixmode]+--+-- csound doc: <http://www.csounds.com/manual/html/tab.html>+tab ::  Sig -> Tab -> Sig+tab b1 b2 = Sig $ f <$> unSig b1 <*> unTab b2+    where f a1 a2 = opcs "tab" [(Kr,[Kr,Ir,Ir]),(Ar,[Xr,Ir,Ir])] [a1,a2]
src/Csound/Typed/Control/Evt.hs view
@@ -19,6 +19,7 @@  import Csound.Typed.Types import Csound.Typed.GlobalState+import Csound.Typed.GlobalState.Opcodes(primInstrId) import Csound.Typed.Control.Instr import Csound.Typed.Control.Mix(Sco) @@ -72,7 +73,7 @@              event :: Arg a => C.ChnRef -> (D, D, a) -> Dep ()         event chnId (start, dur, args) = hideGEinDep $ fmap C.event $ -            C.Event instrId <$> toGE start <*> toGE dur <*> (fmap (++ [C.chnRefId chnId]) $ toNote args) +            C.Event (primInstrId instrId) <$> toGE start <*> toGE dur <*> (fmap (++ [C.chnRefId chnId]) $ toNote args)               -- | Retriggers an instrument every time an event happens. The note -- is held until the next event happens.@@ -108,7 +109,7 @@         event :: Arg a => C.ChnRef -> D -> a -> Dep ()         event chnId currentRetrig args = hideGEinDep $ fmap C.event $ do             currentRetrigExp <- toGE currentRetrig-            C.Event instrId 0 infiniteDur <$> (fmap (++ [C.chnRefId chnId, currentRetrigExp]) $ toNote args) +            C.Event (primInstrId instrId) 0 infiniteDur <$> (fmap (++ [C.chnRefId chnId, currentRetrigExp]) $ toNote args)   evtLoop :: (Num a, Tuple a, Sigs a) => Maybe (Evt Unit) -> [SE a] -> [Evt Unit] -> a evtLoop = evtLoopGen True@@ -216,7 +217,7 @@         eventForAudioInstr = eventFor instrId          eventFor idx chnId currentRetrig = -            C.Event idx 0 infiniteDur [C.chnRefId chnId, currentRetrig] +            C.Event (primInstrId idx) 0 infiniteDur [C.chnRefId chnId, currentRetrig]           readServantEvt :: GE C.ChnRef -> SE Sig         readServantEvt chnId = SE $ fmap fromE $ hideGEinDep $ fmap readChnEvtLoop chnId@@ -249,7 +250,7 @@  saveEvtInstr_ :: Arg a => C.InstrId -> Evt [(D, D, a)] -> Dep () saveEvtInstr_ instrId evts = unSE $ runEvt evts $ \es -> fromDep_ $ mapM_ event es-    where event (start, dur, args) = hideGEinDep $ fmap C.event $ C.Event instrId <$> toGE start <*> toGE dur <*> toNote args+    where event (start, dur, args) = hideGEinDep $ fmap C.event $ C.Event (primInstrId instrId) <$> toGE start <*> toGE dur <*> toNote args  ------------------------------------------------------------------- 
src/Csound/Typed/Control/Ref.hs view
@@ -1,12 +1,19 @@-module Csound.Typed.Control.Ref where+module Csound.Typed.Control.Ref(+    Ref, writeRef, readRef, newRef, mixRef, modifyRef, sensorsSE, newGlobalRef,+    newCtrlRef, newGlobalCtrlRef,+    globalSensorsSE, newClearableGlobalRef, newTab, newGlobalTab+) where  import Control.DeepSeq(deepseq)  import Control.Monad+import Control.Monad.Trans.Class import Csound.Dynamic hiding (newLocalVars) +import Csound.Typed.Types.Prim import Csound.Typed.Types.Tuple import Csound.Typed.GlobalState.SE+import Csound.Typed.GlobalState.GE  -- | It describes a reference to mutable values. newtype Ref a = Ref [Var]@@ -32,6 +39,18 @@ newRef :: Tuple a => a -> SE (Ref a) newRef t = fmap Ref $ newLocalVars (tupleRates t) (fromTuple t)        +-- | Allocates a new local (it is visible within the instrument) mutable value and initializes it with value. +-- A reference can contain a tuple of variables.+-- It contains control signals (k-rate) and constants for numbers (i-rates).+newCtrlRef :: Tuple a => a -> SE (Ref a)+newCtrlRef t = fmap Ref $ newLocalVars (fmap toCtrlRate $ tupleRates t) (fromTuple t) +    where +        +toCtrlRate x = case x of +    Ar -> Kr+    Kr -> Ir+    _  -> x+ -- | Adds the given signal to the value that is contained in the -- reference. mixRef :: (Num a, Tuple a) => Ref a -> a -> SE ()@@ -55,9 +74,79 @@ newGlobalRef :: Tuple a => a -> SE (Ref a) newGlobalRef t = fmap Ref $ newGlobalVars (tupleRates t) (fromTuple t)     +-- | Allocates a new global mutable value and initializes it with value. +-- A reference can contain a tuple of variables.+-- It contains control signals (k-rate) and constants for numbers (i-rates).+newGlobalCtrlRef :: Tuple a => a -> SE (Ref a)+newGlobalCtrlRef t = fmap Ref $ newGlobalVars (fmap toCtrlRate $ tupleRates t) (fromTuple t)   + -- | An alias for the function @newRef@. It returns not the reference -- to mutable value but a pair of reader and writer functions. globalSensorsSE :: Tuple a => a -> SE (SE a, a -> SE ()) globalSensorsSE a = do     ref <- newRef a     return $ (readRef ref, writeRef ref)++-- | Allocates a new clearable global mutable value and initializes it with value. +-- A reference can contain a tuple of variables.+-- The variable is set to zero at the end of every iteration.+-- It's useful for accumulation of audio values from several instruments.+newClearableGlobalRef :: Tuple a => a -> SE (Ref a)+newClearableGlobalRef t = fmap Ref $ newClearableGlobalVars (tupleRates t) (fromTuple t) ++-------------------------------------------------------------------------------+-- writable tables++-- | Creates a new table. The Tab could be used while the instrument+-- is playing. When the instrument is retriggered the new tab is allocated.+--+-- > newTab size+newTab :: D -> SE Tab+newTab size = ftgentmp 0 0 size 7 0 [size, 0]++-- | Creates a new global table. +-- It's generated only once. It's persisted between instrument calls.+--+-- > newGlobalTab identifier size+newGlobalTab :: Int -> SE Tab+newGlobalTab size = do +    ref <- newGlobalCtrlRef ((fromGE $ saveWriteTab size) :: D)+    fmap (fromGE . toGE) $ readRef ref++{-+    identifier <- geToSe $ getNextGlobalGenId+    ref <- newGlobalRef (0 :: D)        +    tabId <- ftgenonce 0 (Csound.Typed.Types.Prim.int identifier) size 7 0 [size, 0]+    writeRef ref (fromGE $ toGE tabId)+    fmap (fromGE . toGE) $ readRef ref+-}++-----------------------------------------------------------------------+-- some opcodes that I have to define upfront+++-- | +-- Generate a function table from within an instrument definition, without duplication of data.+--+-- Enables the creation of function tables entirely inside +--       instrument definitions, without any duplication of data.+--+-- > ifno  ftgenonce  ip1, ip2dummy, isize, igen, iarga, iargb, ...+--+-- csound doc: <http://www.csounds.com/manual/html/ftgenonce.html>+ftgenonce ::  D -> D -> D -> D -> D -> [D] -> SE Tab+ftgenonce b1 b2 b3 b4 b5 b6 = fmap ( Tab . return) $ SE $ (depT =<<) $ lift $ f <$> unD b1 <*> unD b2 <*> unD b3 <*> unD b4 <*> unD b5 <*> mapM unD b6+    where f a1 a2 a3 a4 a5 a6 = opcs "ftgenonce" [(Ir,(repeat Ir))] ([a1,a2,a3,a4,a5] ++ a6)++-- | +-- Generate a score function table from within the orchestra, which is deleted at the end of the note.+--+-- Generate a score function table from within the orchestra,+--     which is optionally deleted at the end of the note.+--+-- > ifno  ftgentmp  ip1, ip2dummy, isize, igen, iarga, iargb, ...+--+-- csound doc: <http://www.csounds.com/manual/html/ftgentmp.html>+ftgentmp ::  D -> D -> D -> D -> D -> [D] -> SE Tab+ftgentmp b1 b2 b3 b4 b5 b6 = fmap ( Tab . return) $ SE $ (depT =<<) $ lift $ f <$> unD b1 <*> unD b2 <*> unD b3 <*> unD b4 <*> unD b5 <*> mapM unD b6+    where f a1 a2 a3 a4 a5 a6 = opcs "ftgentmp" [(Ir,(repeat Ir))] ([a1,a2,a3,a4,a5] ++ a6)
src/Csound/Typed/GlobalState/Elements.hs view
@@ -4,6 +4,7 @@     IdMap(..), saveId, newIdMapId,     -- ** Gens     GenMap, newGen, newGenId, nextGlobalGenCounter, newTabOfGens,+    WriteGenMap, newWriteGen, newWriteTab,     -- Sf2     SfFluid(..), SfSpec(..), SfMap, newSf, sfVar, renderSf,     -- ** Band-limited waveforms@@ -15,17 +16,23 @@     -- * Midi     MidiType(..), Channel, MidiMap, MidiKey(..), saveMidiInstr,     -- * Global variables-    Globals(..), newPersistentGlobalVar, newClearableGlobalVar, +    Globals(..), newPersistentGlobalVar, newClearableGlobalVar,          renderGlobals,     -- * Instruments     Instrs(..), saveInstr, getInstrIds, -- newInstrId, saveInstrById, saveInstr, CacheName, makeCacheName, saveCachedInstr, getInstrIds,+    -- * Named instruments+    NamedInstrs(..), saveNamedInstr,     -- * Src     InstrBody, getIn, sendOut, sendChn, sendGlobal, chnPargId,     Event(..),     ChnRef(..), chnRefFromParg, chnRefAlloc, readChn, writeChn, chnUpdateUdo,-    subinstr, subinstr_, event_i, event, safeOut, autoOff, changed+    subinstr, subinstr_, event_i, event, safeOut, autoOff, changed,+    -- * Udo plugins+    UdoPlugin, addUdoPlugin, getUdoPluginNames,+    tabQueuePlugin, tabQueue2Plugin     ) where +import Data.List import Data.Hashable  import Control.Monad.Trans.State.Strict@@ -34,8 +41,6 @@ import qualified Data.Map as M import qualified Data.IntMap as IM -import qualified Csound.Typed.GlobalState.Opcodes as C(midiVolumeFactor)- import Csound.Dynamic.Types import Csound.Dynamic.Build import Csound.Dynamic.Build.Numeric()@@ -72,15 +77,59 @@ type GenMap = IdMap Gen  newGen :: Gen -> State GenMap E-newGen = fmap int . saveId+newGen = fmap int . saveGenId  newTabOfGens :: [Gen] -> State GenMap E-newTabOfGens = fmap int . (saveId . intTab =<<) . mapM saveId-    where intTab ns = Gen (length ns) (-2) (fmap fromIntegral ns) Nothing+newTabOfGens = fmap int . (saveGenId . intTab =<<) . mapM saveGenId+    where intTab ns = Gen (length ns) (IntGenId (-2)) (fmap fromIntegral ns) Nothing +saveGenId :: Ord a => a -> State (IdMap a) Int+saveGenId a = state $ \s -> +    case M.lookup a (idMapContent s) of+        Nothing -> +            let newId = nextReadOnlyTableId $ idMapNewId s+                s1    = s{ idMapContent = M.insert a newId (idMapContent s)+                         , idMapNewId = nextReadOnlyTableId newId }    +            in  (newId, s1)+        Just n  -> (n, s)+ newGenId :: State GenMap Int-newGenId = newIdMapId+newGenId = state $ \s -> +    let newId = idMapNewId s+        s1 = s { idMapNewId = nextReadOnlyTableId newId } +    in  (newId, s1) +-- writeable gens++type WriteGenMap = [(Int, Gen)]++newWriteGen :: Gen -> State WriteGenMap E+newWriteGen = fmap int . saveWriteGenId++newWriteTab :: Int -> State WriteGenMap E+newWriteTab = newWriteGen . fromSize +    where fromSize n = Gen n (IntGenId 2) (replicate n 0) Nothing++saveWriteGenId :: Gen -> State WriteGenMap Int+saveWriteGenId a = state $ \s -> case s of+    []         -> (initId, [(initId, a)])+    (i,_):_    ->   let newId = nextWriteTableId i +                    in (newId, (newId, a) : s)+    where +        initId = tableWriteStep++tableWriteStep :: Int+tableWriteStep = 10++nextReadOnlyTableId :: Int -> Int+nextReadOnlyTableId x +    | y `mod` tableWriteStep == 0 = y + 1+    | otherwise                   = y  +    where y = x + 1++nextWriteTableId :: Int -> Int+nextWriteTableId x = tableWriteStep + x+ -- strings  type StringMap = IdMap String@@ -263,11 +312,6 @@ instance Default Instrs where     def = Instrs IM.empty 18 [] -type CacheName = Int--makeCacheName :: Hashable a => a -> CacheName-makeCacheName = hash- getInstrIds :: Instrs -> [InstrId] getInstrIds = fmap fst . instrsContent @@ -318,6 +362,17 @@ -}  -----------------------------------------------------------------+-- named instrs++newtype NamedInstrs = NamedInstrs { unNamedInstrs :: [(String, InstrBody)] }++instance Default NamedInstrs where+    def = NamedInstrs []++saveNamedInstr :: String -> InstrBody -> State NamedInstrs ()+saveNamedInstr name body = state $ \(NamedInstrs xs) -> ((), NamedInstrs $ (name, body) : xs)++----------------------------------------------------------------- -- sound sources  getIn :: Monad m => Int -> DepT m [E]@@ -369,3 +424,19 @@ -- scaleVolumeFactor = (setRate Ir (C.midiVolumeFactor (pn 1)) * )  -- guis+++--------------------------------------------------------+-- Udo plugins ++newtype UdoPlugin  = UdoPlugin { unUdoPlugin :: String }++tabQueuePlugin  = UdoPlugin "tabQueue"+tabQueue2Plugin = UdoPlugin "tabQueue2"++addUdoPlugin :: UdoPlugin -> State [UdoPlugin] ()+addUdoPlugin a = modify (a :)++getUdoPluginNames :: [UdoPlugin] -> [String]+getUdoPluginNames xs = nub (fmap unUdoPlugin xs)+
src/Csound/Typed/GlobalState/GE.hs view
@@ -9,6 +9,8 @@     MidiCtrl(..), saveMidiCtrl, renderMidiCtrl,     -- * Instruments     saveAlwaysOnInstr, onInstr, saveUserInstr0, getSysExpr,+    -- * Named instruments+    saveNamedInstr,     -- * Total duration     TotalDur(..), pureGetTotalDurForF0, getTotalDurForTerminator,      setDurationForce, setDuration, setDurationToInfinite,    @@ -16,6 +18,7 @@     addNote,     -- * GEN routines     saveGen, saveTabs, getNextGlobalGenId,+    saveWriteGen, saveWriteTab,     -- * Sf2     saveSf, sfTable,     -- * Band-limited waves@@ -31,7 +34,9 @@     listenKeyEvt, Key(..), KeyEvt(..), Guis(..),     getKeyEventListener,     -- * Hrtf pan-    simpleHrtfmove, simpleHrtfstat+    simpleHrtfmove, simpleHrtfstat,+    -- * Udo plugins+    addUdoPlugin, renderUdoPlugins     ) where  import Paths_csound_expression_typed@@ -52,12 +57,14 @@  import Csound.Typed.GlobalState.Options import Csound.Typed.GlobalState.Cache-import Csound.Typed.GlobalState.Elements+import Csound.Typed.GlobalState.Elements hiding(saveNamedInstr, addUdoPlugin) import Csound.Typed.Constants(infiniteDur)-import Csound.Typed.GlobalState.Opcodes(hrtfmove, hrtfstat)+import Csound.Typed.GlobalState.Opcodes(hrtfmove, hrtfstat, primInstrId)  import Csound.Typed.Gui.Gui(Panel(..), Win(..), GuiNode, GuiHandle(..), restoreTree, guiMap, mapGuiOnPanel, defText) +import qualified Csound.Typed.GlobalState.Elements as E(saveNamedInstr, addUdoPlugin)+ type Dep a = DepT GE a  -- global side effects@@ -88,12 +95,15 @@      data History = History     { genMap            :: GenMap-    , globalGenCounter  :: Int+    , writeGenMap       :: WriteGenMap+    , globalGenCounter  :: Int         , stringMap         :: StringMap     , sfMap             :: SfMap     , midiMap           :: MidiMap GE     , globals           :: Globals     , instrs            :: Instrs+    , udoPlugins        :: [UdoPlugin]+    , namedInstrs       :: NamedInstrs     , midis             :: [MidiAssign]     , midiCtrls         :: [MidiCtrl]     , totalDur          :: Maybe TotalDur@@ -105,7 +115,7 @@     , guis              :: Guis }  instance Default History where-    def = History def def def def def def def def def def def def (return ()) def def def+    def = History def def def def def def def def def def def def def def def (return ()) def def def  data Msg = Msg data MidiAssign = MidiAssign MidiType Channel InstrId@@ -164,6 +174,14 @@  onGenMap = onHistory genMap (\val h -> h{ genMap = val }) +saveWriteGen :: Gen -> GE E+saveWriteGen = onWriteGenMap . newWriteGen++saveWriteTab :: Int -> GE E+saveWriteTab = onWriteGenMap . newWriteTab++onWriteGenMap = onHistory writeGenMap (\val h -> h{ writeGenMap = val })+ saveTabs :: [Gen] -> GE E saveTabs = onGenMap . newTabOfGens @@ -205,7 +223,7 @@ getSysExpr terminatorInstrId = do     e1 <- withHistory $ clearGlobals . globals     dt <- getTotalDurForTerminator-    let e2 = event_i $ Event terminatorInstrId dt 0.01 [] +    let e2 = event_i $ Event (primInstrId terminatorInstrId) dt 0.01 []      return $ e1 >> e2     where clearGlobals = snd . renderGlobals @@ -216,9 +234,6 @@ addNote :: InstrId -> CsdEvent -> GE () addNote instrId evt = modifyHistory $ \h -> h { notes = (instrId, evt) : notes h } --- {- setMasterInstrId :: InstrId -> GE () setMasterInstrId masterId = onMasterInstrId $ put masterId@@ -267,6 +282,13 @@ onGlobals = onHistory globals (\a h -> h { globals = a })  ----------------------------------------------------------------------+-- named instruments++saveNamedInstr :: String -> InstrBody -> GE ()+saveNamedInstr name body = onNamedInstrs $ E.saveNamedInstr name body+    where onNamedInstrs = onHistory namedInstrs (\a h -> h { namedInstrs = a })++---------------------------------------------------------------------- -- cache  -- midi functions@@ -514,3 +536,21 @@ hrtfFileNames :: Int -> IO (String, String) hrtfFileNames sr = liftA2 (,) (getDataFileName (name "left" sr)) (getDataFileName (name "right" sr))     where name dir n = concat ["data/hrtf-", show n, "-", dir, ".dat"]++-----------------------------------------------+-- udo plugins++addUdoPlugin :: UdoPlugin -> GE ()+addUdoPlugin p = onUdo (E.addUdoPlugin p)+    where onUdo = onHistory udoPlugins (\val h -> h{ udoPlugins = val })++renderUdoPlugins :: History -> IO String +renderUdoPlugins h = fmap concat $ mapM getUdoPluginBody $ getUdoPluginNames $ udoPlugins h++getUdoPluginBody :: String -> IO String+getUdoPluginBody name = readFile =<< getDataFileName filename+    where filename = concat ["data/opcodes/", name, ".udo"]++++
src/Csound/Typed/GlobalState/Instr.hs view
@@ -114,4 +114,3 @@ terminatorInstr = do     ids <- fmap (getInstrIds . instrs) getHistory     return $ fromDep_ $ (mapM_ turnoff2 $ fmap instrIdE ids) >> exitnow-
src/Csound/Typed/GlobalState/Opcodes.hs view
@@ -7,7 +7,7 @@     masterUpdateChnRetrig, servantUpdateChnRetrig,     servantUpdateChnEvtLoop, getRetrigVal,     -- * trigger an instrument-    Event(..), event, event_i, appendChn, subinstr, subinstr_, changed, diff, delay1,+    Event(..), event, eventi, event_i, appendChn, subinstr, subinstr_, changed, diff, delay1, primInstrId,     -- * output     out, outs, safeOut, autoOff, turnoff, turnoff2, exitnow,     -- * vco2@@ -29,7 +29,11 @@     -- * Hrtf Pan     hrtfmove, hrtfstat,     -- * Read tables-    tableK, tableI+    tableK, tableI,+    -- * Portamento+    port,+    -- * Rate convertion+    downsamp ) where  import Prelude hiding ((<*))@@ -156,8 +160,11 @@  -- trigger +primInstrId :: InstrId -> E+primInstrId = prim . PrimInstrId+ data Event = Event-    { eventInstrId  :: InstrId+    { eventInstrId  :: E     , eventStart    :: E     , eventDur      :: E     , eventArgs     :: [E] }@@ -165,12 +172,15 @@ event :: Monad m => Event -> DepT m () event = eventBy "event" Kr +eventi :: Monad m => Event -> DepT m ()+eventi = eventBy "event" Ir+ event_i :: Monad m => Event -> DepT m () event_i = eventBy "event_i" Ir  eventBy :: Monad m => String -> Rate -> Event -> DepT m () eventBy name rate a = depT_ $ opcs name [(Xr, Sr : repeat rate)] -    (str "i" : (prim (PrimInstrId $ eventInstrId a)) : (eventStart a) : (eventDur a) : (eventArgs a))+    (str "i" : (eventInstrId a) : (eventStart a) : (eventDur a) : (eventArgs a))  appendChn :: E -> Event -> Event appendChn chn a = a { eventArgs = eventArgs a ++ [chn] }@@ -206,9 +216,11 @@  -- clipps values by 0dbfs safeOut :: Double -> [E] -> [E] -safeOut gainLevel = fmap (( * double gainLevel) . clip)-    where clip x = opcs "clip" [(Ar, [Ar, Ir, Ir])] [x, 0, readOnlyVar (VarVerbatim Ir "0dbfs")]+safeOut gainLevel = fmap (( * double gainLevel) . limiter) +limiter :: E -> E+limiter x = opcs "compress" [(Ar, [Ar, Ar, Kr, Kr, Kr, Kr, Kr, Kr, Ir])] [x, 1, 0, 89, 89, 100, 0, 0, 0]+ autoOff :: Monad m => E -> [E] -> DepT m [E] autoOff dt a = do     ihold    @@ -277,10 +289,15 @@  ftgen :: E -> Gen -> E ftgen n g = opcs "ftgen" [(Ir, repeat Ir)]-    $ [n, 0, int $ genSize g, int $ genId g]+    $ [n, 0, int $ genSize g, genIdE $ genId g]     ++ (maybe [] (return . str) $ genFile g)     ++ (fmap double $ genArgs g) +genIdE :: GenId -> E+genIdE genId = case genId of+    IntGenId n -> int n+    StringGenId a -> str a+ vco2init :: [E] -> E vco2init = opcs "vco2init" [(Ir, repeat Ir)] @@ -366,6 +383,9 @@  port :: E -> E -> E port a b = opcs "portk" [(Kr, [Kr, Ir])] [a, b]++downsamp :: E -> E+downsamp a = opcs "downsamp" [(Kr, [Ar])] [a]  ----------------------------------------------------------- 
src/Csound/Typed/GlobalState/Options.hs view
@@ -1,18 +1,23 @@ module Csound.Typed.GlobalState.Options (     Options(..),     defGain, defSampleRate, defBlockSize, defTabFi,-    -- ** Table fidelity+    -- * Table fidelity     TabFi(..), fineFi, coarseFi,-    -- *** Gen identifiers+    -- ** Gen identifiers     -- | Low level Csound integer identifiers for tables. These names can be used in the function 'Csound.Base.fineFi'+    -- *** Integer identifiers     idWavs, idMp3s, idDoubles, idSines, idSines3, idSines2,     idPartials, idSines4, idBuzzes, idConsts, idLins, idCubes,-    idExps, idSplines, idStartEnds,  idPolys, idChebs1, idChebs2, idBessels, idWins+    idExps, idSplines, idStartEnds,  idPolys, idChebs1, idChebs2, idBessels, idWins,+    -- *** String identifiers+    idPadsynth, idTanh, idExp, idSone, idFarey, idWave ) where  import Control.Applicative import Data.Default+ import qualified Data.IntMap as IM+import qualified Data.Map    as M  import Csound.Dynamic hiding (csdFlags) @@ -59,10 +64,13 @@ -- | Table size fidelity (how many points in the table by default). data TabFi = TabFi     { tabFiBase   :: Int-    , tabFiGens   :: IM.IntMap Int }+    , tabFiGens   :: IM.IntMap Int+    , tabNamedFiGens :: M.Map String Int }  instance Default TabFi where-    def = fineFi 13 [(idLins, 11), (idExps, 11), (idConsts, 9), (idSplines, 11), (idStartEnds, 12)]+    def = fineFi 13 +                [(idLins, 11), (idExps, 11), (idConsts, 9), (idSplines, 11), (idStartEnds, 12)] +                [(idPadsynth, 18), (idSone, 14), (idTanh, 13), (idExp, 13)]           -- | Sets different table size for different GEN-routines. @@ -77,8 +85,8 @@ --   given GEN-routine. -- -- with this function we can set lower table sizes for tables that are usually used in the envelopes.-fineFi :: Int -> [(Int, Int)] -> TabFi-fineFi n xs = TabFi n (IM.fromList xs)+fineFi :: Int -> [(Int, Int)] -> [(String, Int)] -> TabFi+fineFi n xs ys = TabFi n (IM.fromList xs) (M.fromList ys)  -- | Sets the same table size for all tables.  --@@ -86,7 +94,7 @@ -- -- where @n@  is a degree of 2. For example, @n = 10@ sets size to 1024 points for all tables by default. coarseFi :: Int -> TabFi-coarseFi n = TabFi n IM.empty+coarseFi n = TabFi n IM.empty M.empty  idWavs, idMp3s, idDoubles, idSines, idSines3, idSines2,     idPartials, idSines4, idBuzzes, idConsts, idLins, idCubes,@@ -115,4 +123,15 @@ idBessels = 12 idWins = 20 idMp3s = 49++-- Identifiers for named GEN-routines++idPadsynth, idTanh, idExp, idSone, idFarey, idWave :: String++idPadsynth = "padsynth"+idTanh     = "tanh"+idExp      = "exp"+idSone     = "sone"+idFarey    = "farey"+idWave     = "wave" 
src/Csound/Typed/GlobalState/SE.hs view
@@ -2,7 +2,7 @@     SE(..), LocalHistory(..),      runSE, execSE, evalSE, execGEinSE, hideGEinDep,      fromDep, fromDep_, geToSe,-    newLocalVar, newLocalVars, newGlobalVars+    newLocalVar, newLocalVars, newGlobalVars, newClearableGlobalVars ) where  import Control.Applicative@@ -12,7 +12,7 @@ import Csound.Dynamic hiding (newLocalVar, newLocalVars) import qualified Csound.Dynamic as D(newLocalVar, newLocalVars) import Csound.Typed.GlobalState.GE-import Csound.Typed.GlobalState.Elements(newPersistentGlobalVar)+import Csound.Typed.GlobalState.Elements(newPersistentGlobalVar, newClearableGlobalVar)  -- | The Csound's @IO@-monad. All values that produce side effects are wrapped -- in the @SE@-monad.@@ -75,4 +75,6 @@ newGlobalVars rs vs = geToSe $ zipWithM f rs =<< vs     where f r v = onGlobals $ newPersistentGlobalVar r v -+newClearableGlobalVars :: [Rate] -> GE [E] -> SE [Var]+newClearableGlobalVars rs vs = geToSe $ zipWithM f rs =<< vs+    where f r v = onGlobals $ newClearableGlobalVar r v
+ src/Csound/Typed/Plugins/TabQueue.hs view
@@ -0,0 +1,48 @@+module Csound.Typed.Plugins.TabQueue(+    tabQueue2_append, tabQueue2_delete, tabQueue2_hasElements, tabQueue2_readLastElement+) where++import Data.Boolean+import Control.Monad.Trans.Class++import Csound.Dynamic++import Csound.Typed.Types+import Csound.Typed.GlobalState+import qualified Csound.Typed.GlobalState.Elements as E(tabQueue2Plugin)++-------------------------------------------------------------------------------+-- table queue for midi notes++-- |+-- > tabQueue2_append table (pch, vol)+tabQueue2_append :: Tab -> (D, D) -> SE ()+tabQueue2_append tab (pch, vol) = SE $ (depT_ =<<) $ lift $ do    +    addUdoPlugin E.tabQueue2Plugin+    f <$> toGE tab <*> toGE pch <*> toGE vol+    where f tab pch vol = opcs "TabQueue2_Append" [(Xr, [Ir, Ir, Ir])] [tab, pch, vol]++-- | Delete by pitch+--+-- > tabQueue2_delete table pch+tabQueue2_delete :: Tab -> D -> SE ()+tabQueue2_delete tab pch = SE $ (depT_ =<<) $ lift $ do    +    addUdoPlugin E.tabQueue2Plugin+    f <$> toGE tab <*> toGE pch+    where f tab pch = opcs "TabQueue2_Delete" [(Xr, [Ir, Ir])] [tab, pch]++-- | Queue is not empty+tabQueue2_hasElements :: Tab -> BoolSig+tabQueue2_hasElements = (==* 1) . tabQueue2_hasElements'++tabQueue2_hasElements' :: Tab -> Sig+tabQueue2_hasElements' tab = fromGE $ do+    addUdoPlugin E.tabQueue2Plugin+    f <$> toGE tab+    where f tab = opcs "TabQueue2_HasElements" [(Kr, [Ir])] [tab]++tabQueue2_readLastElement :: Tab -> (Sig, Sig)+tabQueue2_readLastElement tab = toTuple $ fmap ($ 2) $ do+    addUdoPlugin E.tabQueue2Plugin    +    f <$> toGE tab+    where f tab = mopcs "TabQueue2_ReadLastElement" ([Kr, Kr], [Ir]) [tab]
src/Csound/Typed/Render.hs view
@@ -11,13 +11,16 @@ import Data.Default import Data.Maybe import Data.Tuple+import Data.Monoid import Data.Ord import Data.List(sortBy, groupBy) import qualified Data.IntMap as IM+import Control.Monad.IO.Class  import Csound.Dynamic hiding (csdFlags) import Csound.Typed.Types import Csound.Typed.GlobalState+import Csound.Typed.GlobalState.Elements(NamedInstrs(..)) import Csound.Typed.GlobalState.Options import Csound.Typed.Control.Instr import Csound.Typed.Control(getIns)@@ -64,27 +67,29 @@ renderHistory mnchnls_i nchnls opt = do     keyEventListener <- getKeyEventListener     hist1 <- getHistory-    instr0 <- execDepT $ getInstr0 mnchnls_i nchnls opt hist1    +    udos <- fmap verbatim $ liftIO $ renderUdoPlugins hist1+    instr0 <- execDepT $ getInstr0 mnchnls_i nchnls opt udos hist1         terminatorInstrId <- saveInstr =<< terminatorInstr     expr2 <- getSysExpr terminatorInstrId      saveAlwaysOnInstr =<< saveInstr (SE expr2)     expr3 <- guiInstrExp      saveAlwaysOnInstr =<< saveInstr (SE expr3)    -    hist2 <- getHistory-    let orc = Orc instr0 (maybeAppend keyEventListener $ fmap (uncurry Instr) $ instrsContent $ instrs hist2)   -    hist3 <- getHistory +    hist2 <- getHistory    +    let namedIntruments = fmap (\(name, body) -> Instr (InstrLabel name) body) $ unNamedInstrs $ namedInstrs hist2+    let orc = Orc instr0 ((namedIntruments ++ ) $ maybeAppend keyEventListener $ fmap (uncurry Instr) $ instrsContent $ instrs hist2)   +    hist3 <- getHistory          let flags   = reactOnMidi hist3 $ csdFlags opt         sco     = Sco (Just $ pureGetTotalDurForF0 $ totalDur hist3) -                      (renderGens $ genMap hist3) $+                      (renderGens (genMap hist3) (writeGenMap hist3)) $                       ((fmap alwaysOn $ alwaysOnInstrs hist3) ++ (getNoteEvents $ notes hist3))     return $ Csd flags orc sco     where-        renderGens = fmap swap . M.toList . idMapContent        +        renderGens gens writeGens = (fmap swap $ M.toList $ idMapContent  gens) ++ writeGens         maybeAppend ma = maybe id (:) ma          getNoteEvents = fmap $ \(instrId, evt) -> (instrId, [evt]) -getInstr0 :: Maybe Int -> Int -> Options -> History -> Dep ()-getInstr0 mnchnls_i nchnls opt hist = do+getInstr0 :: Maybe Int -> Int -> Options -> Dep () -> History -> Dep ()+getInstr0 mnchnls_i nchnls opt udos hist = do     globalConstants     midiAssigns     midiInitCtrls@@ -92,6 +97,7 @@     renderBandLimited (genMap hist) (bandLimitedMap hist)     userInstr0 hist     chnUpdateUdo+    udos     sf2     guiStmt $ getPanels hist     where
src/Csound/Typed/Types/MixSco.hs view
@@ -108,4 +108,4 @@ mkEvent instrId startD durD args =  hideGEinDep $ do         start <- toGE startD         dur   <- toGE durD-        return $ event_i $ Event instrId start dur args+        return $ event_i $ Event (primInstrId instrId) start dur args
src/Csound/Typed/Types/Prim.hs view
@@ -4,10 +4,10 @@     BoolSig(..), unBoolSig, BoolD(..), unBoolD, Unit(..), unit, Val(..), hideGE, SigOrD,      -- ** Tables-    preTab, TabSize(..), TabArgs(..), updateTabSize,+    preTab, preStringTab, TabSize(..), TabArgs(..), updateTabSize,     fromPreTab, getPreTabUnsafe, skipNorm, forceNorm,     nsamp, ftlen, ftchnls, ftsr, ftcps,-    TabList, tabList, fromTabList, fromTabListD,+    TabList, tabList, fromTabList, fromTabListD,         -- ** constructors     double, int, text, @@ -26,7 +26,8 @@         -- ** logic funs     when1, whens, untilDo, whileDo, boolSig,-    equalsTo, notEqualsTo, lessThan, greaterThan, lessThanEquals, greaterThanEquals+    equalsTo, notEqualsTo, lessThan, greaterThan, lessThanEquals, greaterThanEquals,+    whenD1, whenDs, untilDoD, whileDoD, untilBeginD ) where  import Prelude hiding ((<*))@@ -35,7 +36,8 @@ import Control.Monad import Control.Monad.Trans.Class import Data.Monoid-import qualified Data.IntMap as IM+import qualified Data.IntMap    as IM+import qualified Data.Map       as M  import Data.Default import Data.Boolean@@ -121,11 +123,14 @@     | TabPre PreTab  preTab :: TabSize -> Int -> TabArgs -> Tab-preTab size gen args = TabPre $ PreTab size gen args+preTab size gen args = TabPre $ PreTab size (IntGenId gen) args +preStringTab :: TabSize -> String -> TabArgs -> Tab+preStringTab size gen args = TabPre $ PreTab size (StringGenId gen) args+ data PreTab = PreTab     { preTabSize    :: TabSize-    , preTabGen     :: Int+    , preTabGen     :: GenId     , preTabArgs    :: TabArgs }  -- Table size.@@ -170,7 +175,9 @@                   (args, file) = defineTabArgs size (preTabArgs tab)  getTabSizeBase :: TabFi -> PreTab -> Int-getTabSizeBase tf tab = IM.findWithDefault (tabFiBase tf) (preTabGen tab) (tabFiGens tf)+getTabSizeBase tf tab = case preTabGen tab of+    IntGenId intId -> IM.findWithDefault (tabFiBase tf) intId (tabFiGens tf)+    StringGenId stringId -> M.findWithDefault (tabFiBase tf) stringId (tabNamedFiGens tf)  defineTabSize :: Int -> TabSize -> Int defineTabSize base x = case x of@@ -222,15 +229,24 @@ skipNorm :: Tab -> Tab skipNorm x = case x of     Tab _ -> error "you can skip normalization only for primitive tables (made with gen-routines)"-    TabPre a -> TabPre $ a{ preTabGen = negate $ abs $ preTabGen a }+    TabPre a -> TabPre $ a{ preTabGen = skipNormGenId $ preTabGen a } +skipNormGenId = mapIntGenId (negate . abs)+ -- | Force normalization (sets table size to positive value). -- Might be useful to restore normalization for table 'Csound.Tab.doubles'. forceNorm :: Tab -> Tab forceNorm x = case x of     Tab _ -> error "you can force normalization only for primitive tables (made with gen-routines)"-    TabPre a -> TabPre $ a{ preTabGen = abs $ preTabGen a }+    TabPre a -> TabPre $ a{ preTabGen = normGenId $ preTabGen a } +normGenId = mapIntGenId abs++mapIntGenId :: (Int -> Int) -> GenId -> GenId+mapIntGenId f genId = case genId of+    IntGenId intId -> IntGenId (f intId)+    _              -> genId+ ---------------------------------------------------------------------------- -- change table size @@ -408,6 +424,8 @@ instance Default Str    where def = text "" instance Default Spec   where def = fromE 0  +instance Default TabList where def = fromE 0+ ------------------------------------------------------------------------------- -- monoid @@ -602,6 +620,32 @@ elseBegin :: SE () elseBegin = fromDep_ D.elseBegin +-- | Invokes the given procedure if the boolean signal is true.+whenD1 :: BoolD -> SE () -> SE ()+whenD1 xp body = case xp of+    PrimBoolD p -> if p then body else return ()+    _             -> do+        ifBeginD xp+        body+        ifEnd++-- | The chain of @when1@s. Tests all the conditions in sequence+-- if everything is false it invokes the procedure given in the second argument.+whenDs :: [(BoolD, SE ())] -> SE () -> SE ()+whenDs bodies el = case bodies of+    []   -> el+    a:as -> do+        ifBeginD (fst a)+        snd a+        elseIfs as+        elseBegin +        el+        foldl1 (>>) $ replicate (length bodies) ifEnd+    where elseIfs = mapM_ (\(p, body) -> elseBegin >> ifBeginD p >> body)++ifBeginD :: BoolD -> SE ()+ifBeginD a = fromDep_ $ D.ifBegin =<< lift (toGE a)+ -- elseIfBegin :: BoolSig -> SE () -- elseIfBegin a = fromDep_ $ D.elseIfBegin =<< lift (toGE a) @@ -619,6 +663,18 @@  untilEnd :: SE () untilEnd = fromDep_ D.untilEnd++untilDoD :: BoolD -> SE () -> SE ()+untilDoD p body = do+    untilBeginD p+    body+    untilEnd++whileDoD :: BoolD -> SE () -> SE ()+whileDoD p = untilDoD (notB p) ++untilBeginD :: BoolD -> SE ()+untilBeginD a = fromDep_ $ D.untilBegin =<< lift (toGE a)  -- | Creates a constant boolean signal. boolSig :: BoolD -> BoolSig
src/Csound/Typed/Types/Tuple.hs view
@@ -106,6 +106,8 @@ instance Tuple Str   where tupleMethods = primTupleMethods Sr instance Tuple Spec  where tupleMethods = primTupleMethods Fr +instance Tuple TabList where tupleMethods = primTupleMethods Kr+ instance (Tuple a, Tuple b) => Tuple (a, b) where         tupleMethods = TupleMethods fromTuple' toTuple' tupleArity' tupleRates' defTuple'         where @@ -180,6 +182,7 @@ instance Arg D instance Arg Str instance Arg Tab+instance Arg TabList  instance (Arg a, Arg b) => Arg (a, b) instance (Arg a, Arg b, Arg c) => Arg (a, b, c)