-- | 'NRT' operations. module Sound.SC3.Server.NRT.Edit where import Data.List {- base -} import qualified Data.List.Ordered as L {- data-ordlist -} import Sound.OSC {- hosc -} import Sound.SC3.Server.Command import Sound.SC3.Server.NRT -- * List -- | Inserts at the first position where it compares less but not -- equal to the next element. -- -- > import Data.Function -- > insertBy (compare `on` fst) (3,'x') (zip [1..5] ['a'..]) -- > insertBy_post (compare `on` fst) (3,'x') (zip [1..5] ['a'..]) insertBy_post :: (a -> a -> Ordering) -> a -> [a] -> [a] insertBy_post cmp e l = case l of [] -> [e] h:l' -> case cmp e h of LT -> e : l _ -> h : insertBy_post cmp e l' -- | 'insertBy_post' using 'compare'. insert_post :: Bundle -> [Bundle] -> [Bundle] insert_post = insertBy_post compare -- | Apply /f/ at all but last element, and /g/ at last element. -- -- > at_last (* 2) negate [1..4] == [2,4,6,-4] at_last :: (a -> b) -> (a -> b) -> [a] -> [b] at_last f g x = case x of [] -> [] [i] -> [g i] i:x' -> f i : at_last f g x' -- * NRT -- | Merge two NRT scores. Retains internal 'nrt_end' messages. nrt_merge :: NRT -> NRT -> NRT nrt_merge (NRT p) (NRT q) = NRT (L.merge p q) -- | Merge a set of NRT. Retains internal 'nrt_end' messages. nrt_merge_set :: [NRT] -> NRT nrt_merge_set = foldr nrt_merge nrt_empty -- | The empty NRT. nrt_empty :: NRT nrt_empty = NRT [] -- | Add bundle at first permissable location of NRT. nrt_insert_pre :: Bundle -> NRT -> NRT nrt_insert_pre p (NRT q) = NRT (insert p q) -- | Add bundle at last permissable location of NRT. nrt_insert_post :: Bundle -> NRT -> NRT nrt_insert_post p (NRT q) = NRT (insert_post p q) -- | 'bundleTime' of 'last' of 'nrt_bundles'. nrt_end_time :: NRT -> Time nrt_end_time = bundleTime . last . nrt_bundles -- | Apply temporal and message functions to bundle. bundle_map :: (Time -> Time) -> ([Message] -> [Message]) -> Bundle -> Bundle bundle_map t_f m_f (Bundle t m) = Bundle (t_f t) (m_f m) -- | Delete any internal 'nrt_end' messages, and require one at the -- final bundle. nrt_close :: NRT -> NRT nrt_close (NRT l) = let is_nrt_end_msg = (== "/nrt_end") . messageAddress rem_end_msg = bundle_map id (filter (not . is_nrt_end_msg)) req_end_msg = let f m = if any is_nrt_end_msg m then m else m ++ [nrt_end] in bundle_map id f in NRT (at_last rem_end_msg req_end_msg l) -- | Append /q/ to /p/, assumes last timestamp at /p/ precedes first at /q/. nrt_append :: NRT -> NRT -> NRT nrt_append (NRT p) (NRT q) = NRT (p ++ q)