-- | An 'Event' is a ('Key','Field') map. module Sound.SC3.Lang.Control.Event where import Data.List {- base -} import qualified Data.Map as Map {- containers -} import Data.Maybe {- base -} import Data.Monoid {- base -} import Data.String {- base -} import Sound.OSC {- hosc -} import Sound.SC3 {- hsc3 -} import System.Random {- base -} import qualified Sound.SC3.Lang.Collection as C import qualified Sound.SC3.Lang.Control.Duration as D import qualified Sound.SC3.Lang.Control.Instrument as I import qualified Sound.SC3.Lang.Control.Pitch as P import qualified Sound.SC3.Lang.Math as M -- * Field -- | Event field. -- -- 'Field's are 'Num'. -- -- > 5 :: Field -- > 4 + 5 :: Field -- > negate 5 :: Field -- > f_array [2,3] + f_array [4,5] == f_array [6,8] -- > f_array [1,2,3] + f_array [4,5] == f_array [5,7,7] -- > 4 + f_array [5,6] == f_array [9,10] data Field = F_Double {f_double :: Double} | F_Vector {f_vector :: [Field]} | F_String {f_string :: String} | F_Instr {f_instr :: I.Instr} deriving (Eq,Show) -- | Set of types that can be lifted to 'Field'. class F_Value a where toF :: a -> Field instance F_Value Bool where toF = F_Double . fromIntegral . fromEnum instance F_Value Int where toF = F_Double . fromIntegral instance F_Value Double where toF = F_Double instance F_Value I.Instr where toF = F_Instr instance F_Value Field where toF = id -- | Numeric 'F_Value' types. class F_Value a => F_Num a where instance F_Num Int instance F_Num Double instance F_Num Field -- | Maybe variant of 'f_double'. f_double_m :: Field -> Maybe Double f_double_m f = case f of {F_Double n -> Just n;_ -> Nothing;} -- | Variant of /reader/ with specified error message. f_reader_err :: String -> String -> (Field -> Maybe a) -> Field -> a f_reader_err nm err f x = let s = nm ++ ": " ++ err ++ " (" ++ show x ++ ")" in fromMaybe (error s) (f x) -- | Variant of 'f_double' with specified error message. f_double_err :: String -> Field -> Double f_double_err err = f_reader_err "f_double" err f_double_m -- | Run '>' @0@ at 'f_double'. f_bool_err :: String -> Field -> Bool f_bool_err err = (> 0) . f_reader_err "f_bool" err f_double_m -- | Run 'round' at 'f_double'. f_int_err :: String -> Field -> Int f_int_err err = round . f_reader_err "f_int" err f_double_m -- | Single element 'F_Vector' constructor. -- -- > f_ref 1 == f_array [1] f_ref :: Field -> Field f_ref = F_Vector . return -- | Uniform vector constructor. -- -- > f_array [1,2] == F_Vector [F_Double 1,F_Double 2] f_array :: [Double] -> Field f_array = F_Vector . map F_Double -- | Maybe variant of 'f_vector'. f_vector_m :: Field -> Maybe [Field] f_vector_m f = case f of {F_Vector v -> Just v;_ -> Nothing;} -- | 'length' of 'f_vector_m'. -- -- > f_vector_length (f_array [1..5]) == Just 5 f_vector_length :: Field -> Maybe Int f_vector_length = fmap length . f_vector_m -- | Indexed variant of 'f_double_err'. -- -- > f_double_err_ix "" Nothing 1 == 1 -- > f_double_err_ix "" (Just 1) (f_array [0,1]) == 1 f_double_err_ix :: String -> Maybe Int -> Field -> Double f_double_err_ix err n = case n of Nothing -> f_double_err err Just i -> f_double_err err . (!! i) . f_vector -- | Maybe variant of 'f_instr'. f_instr_m :: Field -> Maybe I.Instr f_instr_m f = case f of {F_Instr n -> Just n;_ -> Nothing;} -- | Variant of 'f_instr' with specified error message. f_instr_err :: String -> Field -> I.Instr f_instr_err err = fromMaybe (error ("f_instr: " ++ err)) . f_instr_m -- | Map /fn/ over vector elements at /f/. -- -- > f_map negate (f_array [0,1]) == f_array [0,-1] f_map :: (Field -> Field) -> Field -> Field f_map fn f = case f of F_Vector l -> F_Vector (map fn l) _ -> error ("f_map: " ++ show f) -- | Numerical unary operator. -- -- > f_uop negate (F_Double 1) == F_Double (-1) -- > f_uop negate (F_Vector [F_Double 0,F_Double 1]) == f_array [0,-1] f_uop :: (Double -> Double) -> Field -> Field f_uop f p = case p of F_Double n -> F_Double (f n) F_Vector v -> F_Vector (map (f_uop f) v) _ -> error ("f_uop: " ++ show p) -- | Numerical binary operator. -- -- > f_binop (+) (F_Double 1) (F_Double 2) == F_Double 3 -- > f_binop (*) (f_array [1,2,3]) (f_array [3,4,5]) == f_array [3,8,15] -- > f_binop (/) (F_Double 9) (F_Double 3) == F_Double 3 f_binop :: (Double -> Double -> Double) -> Field -> Field -> Field f_binop f p q = case (p,q) of (F_Double m,F_Double n) -> F_Double (f m n) (F_Vector v,F_Vector w) -> F_Vector (C.zipWith_c (f_binop f) v w) (F_Double _,F_Vector w) -> F_Vector (C.zipWith_c (f_binop f) [p] w) (F_Vector v,F_Double _) -> F_Vector (C.zipWith_c (f_binop f) v [q]) _ -> error ("f_binop: " ++ show (p,q)) -- | At floating branch of 'Field'. f_atf :: (Double -> a) -> Field -> a f_atf f = f . f_double -- | At floating branches of 'Field's. f_atf2 :: (Double -> Double -> a) -> Field -> Field -> a f_atf2 f p q = case (p,q) of (F_Double n1,F_Double n2) -> f n1 n2 _ -> error ("f_atf2: " ++ show (p,q)) -- | At floating branches of 'Field's. f_atf3 :: (Double -> Double -> Double -> a) -> Field -> Field -> Field -> a f_atf3 f p q r = case (p,q,r) of (F_Double n1,F_Double n2,F_Double n3) -> f n1 n2 n3 _ -> error ("f_atf3: " ++ show (p,q,r)) -- | Extend to 'Field' to /n/. -- -- > f_mce_extend 3 (f_array [1,2]) == f_array [1,2,1] -- > f_mce_extend 3 1 == f_array [1,1,1] f_mce_extend :: Int -> Field -> Field f_mce_extend n f = case f of F_Vector v -> F_Vector (take n (cycle v)) _ -> F_Vector (replicate n f) instance IsString Field where fromString = F_String instance Num Field where (+) = f_binop (+) (*) = f_binop (*) negate = f_uop negate abs = f_uop abs signum = f_uop signum fromInteger = F_Double . fromInteger instance Fractional Field where recip = f_uop recip (/) = f_binop (/) fromRational n = F_Double (fromRational n) instance Floating Field where pi = F_Double pi exp = f_uop exp log = f_uop log sqrt = f_uop sqrt (**) = f_binop (**) logBase = f_binop logBase sin = f_uop sin cos = f_uop cos tan = f_uop tan asin = f_uop asin acos = f_uop acos atan = f_uop atan sinh = f_uop sinh cosh = f_uop cosh tanh = f_uop tanh asinh = f_uop asinh acosh = f_uop acosh atanh = f_uop atanh instance Real Field where toRational d = case d of F_Double n -> toRational n _ -> error ("Field.toRational: " ++ show d) instance RealFrac Field where properFraction d = let (i,j) = properFraction (f_double d) in (i,F_Double j) truncate = f_atf truncate round = f_atf round ceiling = f_atf ceiling floor = f_atf floor instance RealFloat Field where floatRadix = f_atf floatRadix floatDigits = f_atf floatDigits floatRange = f_atf floatRange decodeFloat = f_atf decodeFloat encodeFloat i = F_Double . encodeFloat i exponent = f_atf exponent significand = f_uop significand scaleFloat i = f_uop (scaleFloat i) isNaN = f_atf isNaN isInfinite = f_atf isInfinite isDenormalized = f_atf isDenormalized isNegativeZero = f_atf isNegativeZero isIEEE = f_atf isIEEE atan2 = f_binop atan2 instance Ord Field where compare p q = case (p,q) of (F_Double m,F_Double n) -> compare m n _ -> error ("Field.compare: " ++ show (p,q)) instance Enum Field where fromEnum = f_atf fromEnum enumFrom = f_atf (map F_Double . enumFrom) enumFromThen = f_atf2 (\a -> map F_Double . enumFromThen a) enumFromTo = f_atf2 (\a -> map F_Double . enumFromTo a) enumFromThenTo = f_atf3 (\a b -> map F_Double . enumFromThenTo a b) toEnum = F_Double . fromIntegral instance Random Field where randomR i g = case i of (F_Double l,F_Double r) -> let (n,g') = randomR (l,r) g in (F_Double n,g') _ -> error ("Field.randomR: " ++ show i) random g = let (n,g') = randomR (0::Double,1::Double) g in (F_Double n,g') instance EqE Field instance OrdE Field instance RealFracE Field instance UnaryOp Field instance BinaryOp Field -- * Key -- | The type of the /key/ at an 'Event'. -- -- > :set -XOverloadedStrings -- > [K_dur,"pan"] == [K_dur,K_param "pan"] data Key = K_degree | K_mtranspose | K_scale | K_stepsPerOctave | K_gtranspose | K_note | K_octave | K_root | K_ctranspose | K_harmonic | K_midinote | K_detune | K_freq | K_delta | K_dur | K_lag | K_legato | K_fwd' | K_stretch | K_sustain | K_tempo | K_db | K_amp | K_rest | K_instr | K_id | K_type | K_latency | K_param String deriving (Eq,Ord,Show) instance IsString Key where fromString = K_param -- | SC3 name of 'Key'. -- -- > map k_name [K_freq,K_dur,K_param "pan"] == ["freq","dur","pan"] k_name :: Key -> String k_name k = case k of K_param nm -> nm _ -> drop 2 (show k) -- | List of reserved 'Key's used in pitch, duration and amplitude -- models. These are keys that may be provided explicitly, but if not -- will be calculated implicitly. -- -- > (K_freq `elem` k_reserved) == True k_reserved :: [Key] k_reserved = [K_freq,K_midinote,K_note ,K_delta,K_sustain ,K_amp ,K_instr,K_id,K_type,K_latency,K_rest] k_vector :: [Key] k_vector = [K_scale] -- | Is 'Key' /not/ 'k_reserved', and /not/ 'k_vector'. -- -- > k_is_parameter (K_param "pan",0) == True k_is_parameter :: (Key,a) -> Bool k_is_parameter (k,_) = k `notElem` (k_reserved ++ k_vector) -- * Event -- | An 'Event' is a ('Key','Field') map. type Event = Map.Map Key Field -- | Insert (/k/,/v/) into /e/. -- -- > e_get K_id (e_insert K_id 1 mempty) == Just 1 e_insert :: Key -> Field -> Event -> Event e_insert k v = Map.insert k v -- | Event from association list. -- -- > e_get K_id (e_from_list [(K_id,1)]) == Just 1 e_from_list :: [(Key,Field)] -> Event e_from_list = Map.fromList -- | Event from association list. -- -- > let a = [(K_id,1)] in e_to_list (e_from_list a) == a e_to_list :: Event -> [(Key,Field)] e_to_list = Map.toList -- | Lookup /k/ in /e/. -- -- > e_get K_id mempty == Nothing e_get :: Key -> Event -> Maybe Field e_get k = Map.lookup k -- | Immediate or vector element lookup. -- -- > e_get_ix Nothing K_id (e_from_list [(K_id,1)]) == Just 1 -- -- > let n = f_array [0,1,2] -- > in e_get_ix Nothing K_id (e_from_list [(K_id,n)]) == Just n -- -- > let n = f_array [0..9] -- > in e_get_ix (Just 5) K_id (e_from_list [(K_id,n)]) == Just 5 e_get_ix :: Maybe Int -> Key -> Event -> Maybe Field e_get_ix n k = case n of Nothing -> e_get k Just i -> fmap ((!! i) . f_vector) . e_get k -- | Type specialised 'e_get'. e_get_double :: Key -> Event -> Maybe Double e_get_double k = fmap (f_double_err (k_name k)) . e_get k -- | Type specialised 'e_get_ix'. e_get_double_ix :: Maybe Int -> Key -> Event -> Maybe Double e_get_double_ix n k = fmap (f_double_err (k_name k)) . e_get_ix n k -- | Type specialised 'e_get'. e_get_bool :: Key -> Event -> Maybe Bool e_get_bool k = fmap (f_bool_err (k_name k)) . e_get k -- | Type specialised 'e_get'. e_get_int :: Key -> Event -> Maybe Int e_get_int k = fmap (f_int_err (k_name k)) . e_get k -- | Type specialised 'e_get_ix'. e_get_int_ix :: Maybe Int -> Key -> Event -> Maybe Int e_get_int_ix n k = fmap (f_int_err (k_name k)) . e_get_ix n k -- | Type specialised 'e_get'. e_get_instr :: Key -> Event -> Maybe I.Instr e_get_instr k = fmap (f_instr_err (k_name k)) . e_get k -- | Type specialised 'e_get_ix'. e_get_instr_ix :: Maybe Int -> Key -> Event -> Maybe I.Instr e_get_instr_ix n k = fmap (f_instr_err (k_name k)) . e_get_ix n k -- | Type specialised 'e_get'. e_get_array :: Key -> Event -> Maybe [Double] e_get_array k = fmap (map (f_double_err (k_name k)) . f_vector) . e_get k -- | Type specialised 'e_get_ix'. -- -- > let e = e_from_list [(K_scale,f_array [0,2])] -- > in e_get_array_ix Nothing K_scale e == Just [0,2] -- -- > let e = e_from_list [(K_scale,f_ref (f_array [0,2]))] -- > in e_get_array_ix (Just 0) K_scale e == Just [0,2] e_get_array_ix :: Maybe Int -> Key -> Event -> Maybe [Double] e_get_array_ix n k = fmap (map (f_double_err (k_name k)) . f_vector) . e_get_ix n k -- | 'Event' /type/. -- -- > e_type mempty == "s_new" e_type :: Event -> String e_type = fromMaybe "s_new" . fmap f_string . e_get K_type -- | Match on event types, in sequence: s_new, n_set, rest. e_type_match :: Event -> T3 (Event -> t) -> t e_type_match e (f,g,h) = case e_type e of "s_new" -> f e "n_set" -> g e "rest" -> h e _ -> error ("Event.type: " ++ show e) -- | 'const' variant of 'e_type_match'. e_type_match' :: Event -> T3 t -> t e_type_match' e (f,g,h) = e_type_match e (const f,const g,const h) -- | Generate 'D.Dur' from 'Event'. -- -- > D.delta (e_dur Nothing mempty) == 1 -- > D.fwd (e_dur Nothing (e_from_list [(K_dur,1),(K_stretch,2)])) == 2 -- -- > let e = e_from_list [(K_dur,1),(K_legato,0.5)] -- > in D.occ (e_dur Nothing e) == 0.5 e_dur :: Maybe Int -> Event -> D.Dur e_dur n e = let f k = e_get_double_ix n k e in D.optDur (f K_tempo ,f K_dur ,f K_stretch ,f K_legato ,f K_sustain ,f K_delta ,f K_lag ,f K_fwd') -- | Generate 'Pitch' from 'Event'. -- -- > P.midinote (e_pitch Nothing mempty) == 60 -- > P.freq (e_pitch Nothing (e_from_list [(K_degree,5)])) == 440 -- -- > let e = e_from_list [(K_degree,5),(K_scale,f_array [0,2,3,5,7,8,10])] -- > in P.midinote (e_pitch Nothing e) == 68 -- -- > let e = e_from_list [(K_degree,5),(K_scale,f_ref (f_array [0,2,3,5,7,8,10]))] -- > in P.midinote (e_pitch (Just 0) (e_mce_expand e)) == 68 -- -- > P.freq (e_pitch Nothing (e_from_list [(K_midinote,69)])) == 440 e_pitch :: Maybe Int -> Event -> P.Pitch e_pitch n e = let f k = e_get_double_ix n k e in P.optPitch (f K_mtranspose ,f K_gtranspose ,f K_ctranspose ,f K_octave ,f K_root ,f K_degree ,e_get_array_ix n K_scale e ,f K_stepsPerOctave ,f K_detune ,f K_harmonic ,f K_freq ,f K_midinote ,f K_note) -- | 'Event' identifier. e_id :: Maybe Int -> Event -> Maybe Int e_id n = e_get_int_ix n K_id -- | Lookup /db/ field of 'Event'. -- -- > e_db Nothing mempty == (-20) e_db :: Maybe Int -> Event -> Double e_db n = fromMaybe (-20) . e_get_double_ix n K_db -- | The linear amplitude of the amplitude model at /e/. -- -- > e_amp Nothing (e_from_list [(K_db,-60)]) == 0.001 -- > e_amp Nothing (e_from_list [(K_amp,0.01)]) == 0.01 -- > e_amp Nothing mempty == 0.1 e_amp :: Maybe Int -> Event -> Double e_amp n e = fromMaybe (M.dbamp (e_db n e)) (e_get_double_ix n K_amp e) -- | Message /latency/ of event. -- -- > e_latency mempty == 0.1 e_latency :: Event -> Double e_latency = fromMaybe 0.1 . e_get_double K_latency -- | Extract non-'reserved' 'Keys' from 'Event'. -- -- > let e = e_from_list [(K_freq,1),(K_param "p",1),(K_scale,f_ref (f_array [0,3,7]))] -- > in e_parameters Nothing e == [("p",1)] e_parameters :: Maybe Int -> Event -> [(String,Double)] e_parameters n = map (\(k,v) -> (k_name k,f_double_err_ix (k_name k) n v)) . filter k_is_parameter . Map.toList -- | 'Value' editor for 'Key' at 'Event', with default value in case -- 'Key' is not present. e_edit :: Key -> Field -> (Field -> Field) -> Event -> Event e_edit k v f e = case e_get k e of Just n -> e_insert k (f n) e Nothing -> e_insert k (f v) e -- | Variant of 'edit_v' with no default value. e_edit' :: Key -> (Field -> Field) -> Event -> Event e_edit' k f e = case e_get k e of Just n -> e_insert k (f n) e Nothing -> e -- * Event temporal -- | Merge two time-stamped 'Event' sequences. Note that this uses -- 'D.fwd' to calculate start times. e_merge' :: (Time,[Event]) -> (Time,[Event]) -> [(Time,Event)] e_merge' (pt,p) (qt,q) = let f = D.fwd . e_dur Nothing p_st = map (+ pt) (0 : scanl1 (+) (map f p)) q_st = map (+ qt) (0 : scanl1 (+) (map f q)) in t_merge (zip p_st p) (zip q_st q) -- | Insert /fwd/ 'Key's into a time-stamped 'Event' sequence. e_add_fwd :: [(Time,Event)] -> [Event] e_add_fwd e = case e of (t0,e0):(t1,e1):e' -> e_insert K_fwd' (F_Double (t1 - t0)) e0 : e_add_fwd ((t1,e1):e') _ -> map snd e -- | Composition of 'add_fwd' and 'merge''. e_merge :: (Time,[Event]) -> (Time,[Event]) -> [Event] e_merge p q = e_add_fwd (e_merge' p q) -- | N-ary variant of 'e_merge'. -- -- > e_par [(0,repeat (e_from_list [(K_id,1)])) -- > ,(0,repeat (e_from_list [(K_param "b",2)])) -- > ,(0,repeat (e_from_list [(K_param "c",3)]))] e_par :: [(Time,[Event])] -> [Event] e_par l = case l of [] -> [] [(_,p)] -> p (pt,p):(qt,q):r -> e_par ((min pt qt,e_merge (pt,p) (qt,q)) : r) -- | 'mempty' with /rest/. e_rest :: Event e_rest = e_from_list [(K_rest,1)] -- | Does 'Event' have a 'True' @rest@ key. -- -- > e_is_rest mempty == False -- > e_is_rest (e_from_list [(K_rest,1)]) == True e_is_rest :: Event -> Bool e_is_rest = fromMaybe False . e_get_bool K_rest -- * MCE -- | Maximum vector length at 'Event'. -- -- > e_mce_depth (e_from_list [(K_id,1)]) == Nothing -- > e_mce_depth (e_from_list [(K_id,1),(K_param "b",f_array [2,3])]) == Just 2 e_mce_depth :: Event -> Maybe Int e_mce_depth e = let f = map snd (e_to_list e) in case mapMaybe f_vector_length f of [] -> Nothing l -> Just (maximum l) -- | Extend vectors at 'Event' if required, returning 'e_mce_depth'. -- -- > let {e = e_from_list [(K_id,f_array [1,2]),(K_param "b",f_array [2,3,4])] -- > ;r = e_from_list [(K_id,f_array [1,2,1]),(K_param "b",f_array [2,3,4])]} -- > in e_mce_extend e == Just (3,r) -- -- > let e = e_from_list [(K_id,1)] -- > in e_mce_extend e == Nothing e_mce_extend :: Event -> Maybe (Int,Event) e_mce_extend e = let e' = e_to_list e flds = map snd e' f n = let flds' = map (f_mce_extend n) flds in (n,e_from_list (zip (map fst e') flds')) in fmap f (e_mce_depth e) -- | 'e_mce_extend' variant. e_mce_expand :: Event -> Event e_mce_expand e = maybe e snd (e_mce_extend e) -- | Parallel 'Event's, if required. -- -- > let {e = e_from_list [(K_id,1),(K_param "b",f_array [2,3])] -- > ;r = [e_from_list [(K_id,1),(K_param "b",2)],e_from_list [(K_id,1),(K_param "b",3)]]} -- > in e_un_mce e == Just r -- -- > let {e = e_from_list [(K_id,f_array [1,2]),(K_param "b",f_array [3,4,5])] -- > ;r = e_from_list [(K_id,1),(K_param "b",5)]} -- > in fmap (!! 2) (e_un_mce e) == Just r -- -- > e_un_mce (e_from_list [(K_id,1)]) == Nothing e_un_mce :: Event -> Maybe [Event] e_un_mce e = let e' = e_to_list e flds = map snd e' f n = let flds' = transpose (map (f_vector . f_mce_extend n) flds) in map (e_from_list . zip (map fst e')) flds' in fmap f (e_mce_depth e) -- | 'e_un_mce' variant. e_un_mce' :: Event -> [Event] e_un_mce' e = fromMaybe [e] (e_un_mce e) -- * SC3 -- | Generate @SC3@ /(on,off)/ 'Message' sets describing 'Event'. e_messages :: D.Dur -> Event -> Int -> Maybe Int -> Maybe (T2 [Message]) e_messages d e n_id n = let e_i = e_get_instr_ix n K_instr e s = maybe "default" I.i_name e_i sr = maybe True I.i_send_release e_i p = e_pitch n e rt = D.occ d {- rt = release time -} f = P.freq p pr = ("freq",f) : ("midinote",P.midinote p) : ("delta",D.delta d) : ("sustain",rt) : ("amp",e_amp n e) : e_parameters n e n_id' = fromMaybe n_id (e_id n e) in if e_is_rest e || isNaN f then Nothing else let m_on = e_type_match' e ([s_new s n_id' AddToTail 1 pr] ,[n_set n_id' pr] ,[]) m_off = if not sr then [] else e_type_match' e ([n_set n_id' [("gate",0)]] ,[n_set n_id' [("gate",0)]] ,[]) m_on' = case I.i_synthdef =<< e_i of Just sy -> d_recv sy : m_on Nothing -> m_on in Just (m_on',m_off) -- | MCE variant of 'e_messages'. e_messages_mce :: D.Dur -> Event -> Int -> (Maybe (T2 [Message]),Int) e_messages_mce d e n_id = let (r,n) = case e_mce_extend e of Just (m,e') -> (zipWith (e_messages d e') [n_id ..] (map Just [0 .. m - 1]),m) Nothing -> ([e_messages d e n_id Nothing],1) in case unzip (catMaybes r) of ([],[]) -> (Nothing,n_id) (m_on,m_off) -> (Just (concat m_on,concat m_off),n_id + n) -- | Generate @SC3@ /(on,off)/ 'Bundle's describing 'Event'. e_bundles :: Time -> Int -> D.Dur -> Event-> (Maybe (T2 Bundle),Int) e_bundles t n_id d e = let rt = D.occ d {- rt = release time -} t' = t + realToFrac (e_latency e) t'' = t' + realToFrac rt in case e_messages_mce d e n_id of (Nothing,n_id') -> (Nothing,n_id') (Just (m_on,m_off),n_id') -> (Just (Bundle t' m_on,Bundle t'' m_off),n_id') -- | Ordered sequence of 'Event'. newtype Event_Seq = Event_Seq {e_seq_events :: [Event]} -- | Transform 'Event_Seq' into a sequence of @SC3@ /(on,off)/ 'Bundles'. -- -- > e_bundle_seq 0 (Event_Seq (replicate 5 mempty)) e_bundle_seq :: Time -> Event_Seq -> [T2 Bundle] e_bundle_seq st = let rec t i l = case l of [] -> [] e:l' -> let d = e_dur Nothing e t' = t + D.fwd d (b,i') = e_bundles t i d e in b `mcons` rec t' i' l' in rec st 1000 . e_seq_events -- | Transform (productively) an 'Event_Seq' into an 'NRT' score. -- -- > let {n1 = nrt_bundles (e_nrt (Event_Seq (replicate 5 mempty))) -- > ;n2 = take 10 (nrt_bundles (e_nrt (Event_Seq (repeat mempty))))} -- > in n1 == n2 e_nrt :: Event_Seq -> NRT e_nrt = let rec r l = case l of [] -> r (o,c):l' -> let (c',r') = span (<= o) (insert o (insert c r)) in c' ++ rec r' l' in NRT . rec [] . e_bundle_seq 0 -- | Audition 'Event_Seq'. e_play :: Transport m => Event_Seq -> m () e_play l = do st <- time let f (p,q) = pauseThreadUntil (bundleTime p - 0.1) >> sendBundle p >> sendBundle q mapM_ f (e_bundle_seq st l) instance Audible Event_Seq where play = e_play -- * Aliases -- | Type-specialised 'mempty'. e_empty :: Event e_empty = mempty -- | Type-specialised 'mappend'. -- -- > let {l = [(K_id,0)];r = [(K_degree,1)]} -- > in e_from_list l <> e_from_list r == e_from_list (l <> r) e_union :: Event -> Event -> Event e_union = mappend -- * Temporal -- | Left-biased merge of two sorted sequence of temporal values. -- -- > let m = t_merge (zip [0,2,4,6] ['a'..]) (zip [0,3,6] ['A'..]) -- > in m == [(0,'a'),(0,'A'),(2,'b'),(3,'B'),(4,'c'),(6,'d'),(6,'C')] t_merge :: Ord t => [(t,a)] -> [(t,a)] -> [(t,a)] t_merge p q = case (p,q) of ([],_) -> q (_,[]) -> p ((t0,e0):r0,(t1,e1):r1) -> if t0 <= t1 then (t0,e0) : t_merge r0 q else (t1,e1) : t_merge p r1 -- * Tuple -- | Two tuple of /n/. type T2 n = (n,n) -- | Three tuple of /n/. type T3 n = (n,n,n) -- * List -- | 'Maybe' variant of ':'. mcons :: Maybe a -> [a] -> [a] mcons e l = case e of {Just e' -> e' : l;Nothing -> l}