hsc3-0.14: Sound/SC3/Server/Synthdef.hs
-- | The unit-generator graph structure implemented by the
-- SuperCollider synthesis server.
module Sound.SC3.Server.Synthdef where
import qualified Data.ByteString.Char8 as C {- bytestring -}
import qualified Data.ByteString.Lazy as B {- bytestring -}
import Data.Default {- data-default -}
import Data.List {- base -}
import Data.Maybe {- base -}
import Sound.OSC.Coding.Byte {- hosc -}
import Sound.OSC.Coding.Cast {- hosc -}
import System.FilePath {- filepath -}
import Sound.SC3.Server.Synthdef.Internal
import Sound.SC3.Server.Synthdef.Type
import Sound.SC3.UGen.Graph
import Sound.SC3.UGen.Type
-- | Transform a unit generator into a graph.
--
-- > import Sound.SC3.UGen
-- > synth (out 0 (pan2 (sinOsc AR 440 0) 0.5 0.1))
synth :: UGen -> Graph
synth u =
let (_,g) = mk_node (prepare_root u) empty_graph
g' = g {ugens = reverse (ugens g)}
in add_implicit g'
-- | Binary representation of a unit generator synth definition.
data Synthdef = Synthdef {synthdefName :: String
,synthdefGraph :: Graph}
deriving (Eq,Show)
instance Default Synthdef where def = defaultSynthdef
-- | Lift a 'UGen' graph into a 'Synthdef'.
synthdef :: String -> UGen -> Synthdef
synthdef s u = Synthdef s (synth u)
-- | The SC3 /default/ instrument 'Synthdef'.
defaultSynthdef :: Synthdef
defaultSynthdef = synthdef "default" default_ugen_graph
-- | Parameter names at 'Synthdef'.
--
-- > synthdefParam def == ["amp","pan","gate","freq"]
synthdefParam :: Synthdef -> [String]
synthdefParam = map node_k_name . controls . synthdefGraph
-- | Transform a unit generator graph into bytecode.
graphdef :: Graph -> Graphdef
graphdef = encode_graphdef
-- | Find the indices of the named UGen at 'Graph'. The index is
-- required when using 'Sound.SC3.Server.Command.u_cmd'.
ugenIndices :: String -> Graph -> [Integer]
ugenIndices nm =
let f (k,nd) =
case nd of
NodeU _ _ nm' _ _ _ _ -> if nm == nm' then Just k else Nothing
_ -> Nothing
in mapMaybe f . zip [0..] . ugens
-- | Encode 'Synthdef' as a binary data stream.
synthdefData :: Synthdef -> Graphdef
synthdefData (Synthdef s g) =
B.concat [encode_str (C.pack "SCgf")
,encode_i32 0
,encode_i16 1
,B.pack (str_pstr s)
,encode_graphdef g]
-- | Write 'Synthdef' to indicated directory. The filename is the
-- 'synthdefName' with the appropriate extension (@scsyndef@).
synthdefWrite :: Synthdef -> FilePath -> IO ()
synthdefWrite s dir =
let nm = dir </> synthdefName s <.> "scsyndef"
in B.writeFile nm (synthdefData s)
-- | Simple statistical analysis of a unit generator graph.
synthstat :: UGen -> String
synthstat u =
let s = synth u
cs = constants s
ks = controls s
us = ugens s
f g = let h (x:xs) = (x,length (x:xs))
h [] = error "synthstat"
in show . map h . group . sort . map g
in unlines ["number of constants : " ++ show (length cs)
,"number of controls : " ++ show (length ks)
,"control rates : " ++ f node_k_rate ks
,"number of unit generators : " ++ show (length us)
,"unit generator rates : " ++ f node_u_rate us]