{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
module Vivid.OSC.Bundles (
encodeOSCBundles
, initTreeCommand
) where
import Vivid.OSC
import qualified Vivid.SC.Server.Commands as SCCmd
import Vivid.SC.Server.Types (NodeId(..))
import Data.ByteString (ByteString)
import qualified Data.List as L
import Data.Monoid
import Data.Word
import qualified Data.ByteString.Lazy as BSL
import qualified Data.ByteString as BS
import Data.Binary (encode)
encodedOSC_addLength :: ByteString -> ByteString
encodedOSC_addLength bs =
BSL.toStrict (encode (toEnum (BS.length bs) :: Word32)) <> bs
encodeOSCBundles :: [OSCBundle] -> ByteString
encodeOSCBundles bundles =
mconcat . map (encodedOSC_addLength . encodeOSCBundle) $ withEnd
where
sortedBundles :: [OSCBundle]
sortedBundles =
L.sortBy (\(OSCBundle t0 _) (OSCBundle t1 _) -> compare t0 t1) bundles
sortedBundlesWithDefinitionsFirst :: [OSCBundle]
sortedBundlesWithDefinitionsFirst =
map putDefinitionsFirst joinedByTime
where
joinedByTime :: [OSCBundle]
joinedByTime =
(flip map) groupedByTime $ \case
as@(OSCBundle t _:_) ->
OSCBundle t (concatMap (\(OSCBundle _ a) -> a) as)
[] -> error "Should be impossible"
groupedByTime :: [[OSCBundle]]
groupedByTime =
L.groupBy (\(OSCBundle t0 _) (OSCBundle t1 _) -> t1 == t0) sortedBundles
putDefinitionsFirst :: OSCBundle -> OSCBundle
putDefinitionsFirst (OSCBundle t actions) = OSCBundle t $ (\(a,b)->a<>b) $
(flip L.partition) actions $ \case
Right (OSC "/d_recv" _) -> True
_ -> False
lastTimestamp = (\(OSCBundle t _) ->t) $ last sortedBundles
withEnd = mconcat [
[OSCBundle (Timestamp 0) [Right initTreeCommand]]
,sortedBundlesWithDefinitionsFirst
,[OSCBundle lastTimestamp [Right $ OSC "" []]]
]
initTreeCommand :: OSC
initTreeCommand =
SCCmd.g_new (NodeId 1) SCCmd.AddToHead (NodeId 0)