module Sound.SC3.Server.Graphdef where
import Control.Monad
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Char8 as C
import Data.List
import System.IO
import Sound.OSC.Coding.Byte
import Sound.OSC.Coding.Cast
import Sound.OSC.Type
type Name = ASCII
type Control = (Name,Int)
type Sample = Double
data Input = Input Int Int deriving (Eq,Show)
input_ugen_ix :: Input -> Maybe Int
input_ugen_ix (Input u p) = if p == 1 then Nothing else Just u
type Output = Int
type Rate = Int
type Special = Int
type UGen = (Name,Rate,[Input],[Output],Special)
ugen_inputs :: UGen -> [Input]
ugen_inputs (_,_,i,_,_) = i
ugen_outputs :: UGen -> [Output]
ugen_outputs (_,_,_,o,_) = o
ugen_is_control :: UGen -> Bool
ugen_is_control (nm,_,_,_,_) = ascii_to_string nm `elem` ["Control","LagControl","TrigControl"]
ugen_rate :: UGen -> Rate
ugen_rate (_,r,_,_,_) = r
input_is_control :: Graphdef -> Input -> Bool
input_is_control g (Input u _) =
if u == 1
then False
else ugen_is_control (graphdef_ugen g u)
data Graphdef = Graphdef {graphdef_name :: Name
,graphdef_constants :: [Sample]
,graphdef_controls :: [(Control,Sample)]
,graphdef_ugens :: [UGen]}
deriving (Eq,Show)
graphdef_ugen :: Graphdef -> Int -> UGen
graphdef_ugen g = (graphdef_ugens g !!)
graphdef_control :: Graphdef -> Int -> (Control,Sample)
graphdef_control g = (graphdef_controls g !!)
graphdef_constant_nid :: Graphdef -> Int -> Int
graphdef_constant_nid _ = id
graphdef_control_nid :: Graphdef -> Int -> Int
graphdef_control_nid g = (+) (length (graphdef_constants g))
graphdef_ugen_nid :: Graphdef -> Int -> Int
graphdef_ugen_nid g n = graphdef_control_nid g 0 + length (graphdef_controls g) + n
read_i8 :: Handle -> IO Int
read_i8 h = fmap decode_i8 (L.hGet h 1)
read_i16 :: Handle -> IO Int
read_i16 h = fmap decode_i16 (L.hGet h 2)
read_i32 :: Handle -> IO Int
read_i32 h = fmap decode_i32 (L.hGet h 4)
read_sample :: Handle -> IO Sample
read_sample h = fmap (realToFrac . decode_f32) (L.hGet h 4)
read_pstr :: Handle -> IO ASCII
read_pstr h = do
n <- fmap decode_u8 (L.hGet h 1)
fmap decode_str (L.hGet h n)
read_control :: Handle -> IO Control
read_control h = do
nm <- read_pstr h
ix <- read_i16 h
return (nm,ix)
read_input :: Handle -> IO Input
read_input h = do
u <- read_i16 h
p <- read_i16 h
return (Input u p)
read_output :: Handle -> IO Int
read_output = read_i8
read_ugen :: Handle -> IO UGen
read_ugen h = do
name <- read_pstr h
rate <- read_i8 h
number_of_inputs <- read_i16 h
number_of_outputs <- read_i16 h
special <- read_i16 h
inputs <- replicateM number_of_inputs (read_input h)
outputs <- replicateM number_of_outputs (read_output h)
return (name
,rate
,inputs
,outputs
,special)
read_graphdef :: Handle -> IO Graphdef
read_graphdef h = do
magic <- L.hGet h 4
version <- read_i32 h
number_of_definitions <- read_i16 h
when (magic /= L.pack (map (fromIntegral . fromEnum) "SCgf"))
(error "read_graphdef: illegal magic string")
when (version /= 0)
(error "read_graphdef: version not at zero")
when (number_of_definitions /= 1)
(error "read_graphdef: non unary graphdef file")
name <- read_pstr h
number_of_constants <- read_i16 h
constants <- replicateM number_of_constants (read_sample h)
number_of_control_defaults <- read_i16 h
control_defaults <- replicateM number_of_control_defaults (read_sample h)
number_of_controls <- read_i16 h
controls <- replicateM number_of_controls (read_control h)
number_of_ugens <- read_i16 h
ugens <- replicateM number_of_ugens (read_ugen h)
return (Graphdef name
constants
(zip controls control_defaults)
ugens)
read_graphdef_file :: FilePath -> IO Graphdef
read_graphdef_file nm = do
h <- openFile nm ReadMode
g <- read_graphdef h
hClose h
return g
encode_pstr :: ASCII -> L.ByteString
encode_pstr = L.pack . str_pstr . ascii_to_string
encode_input :: Input -> L.ByteString
encode_input (Input u p) = L.append (encode_i16 u) (encode_i16 p)
encode_control :: Control -> L.ByteString
encode_control (nm,k) = L.concat [encode_pstr nm,encode_i16 k]
encode_ugen :: UGen -> L.ByteString
encode_ugen (nm,r,i,o,s) =
L.concat [encode_pstr nm
,encode_i8 r
,encode_i16 (length i)
,encode_i16 (length o)
,encode_i16 s
,L.concat (map encode_input i)
,L.concat (map encode_i8 o)]
encode_sample :: Sample -> L.ByteString
encode_sample = encode_f32 . realToFrac
encode_graphdef :: Graphdef -> L.ByteString
encode_graphdef (Graphdef nm cs ks us) =
let (ks_ctl,ks_def) = unzip ks
in L.concat [encode_str (C.pack "SCgf")
,encode_i32 0
,encode_i16 1
,encode_pstr nm
,encode_i16 (length cs)
,L.concat (map encode_sample cs)
,encode_i16 (length ks_def)
,L.concat (map encode_sample ks_def)
,encode_i16 (length ks_ctl)
,L.concat (map encode_control ks_ctl)
,encode_i16 (length us)
,L.concat (map encode_ugen us)]
graphdef_stat :: Graphdef -> String
graphdef_stat (Graphdef _ cs ks us) =
let u_nm (sc3_nm,_,_,_,_) = ascii_to_string sc3_nm
f g = let h (x:xs) = (x,length (x:xs))
h [] = error "graphdef_stat"
in show . map h . group . sort . map g
sq = intercalate "," (map u_nm us)
in unlines ["number of constants : " ++ show (length cs)
,"number of controls : " ++ show (length ks)
,"number of unit generators : " ++ show (length us)
,"unit generator rates : " ++ f ugen_rate us
,"unit generator sequence : " ++ sq]