{-# LANGUAGE
LambdaCase
, 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 :: ByteString -> ByteString
encodedOSC_addLength ByteString
bs =
ByteString -> ByteString
BSL.toStrict (Word32 -> ByteString
forall a. Binary a => a -> ByteString
encode (Int -> Word32
forall a. Enum a => Int -> a
toEnum (ByteString -> Int
BS.length ByteString
bs) :: Word32)) ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
bs
encodeOSCBundles :: [OSCBundle] -> ByteString
encodeOSCBundles :: [OSCBundle] -> ByteString
encodeOSCBundles [OSCBundle]
bundles =
[ByteString] -> ByteString
forall a. Monoid a => [a] -> a
mconcat ([ByteString] -> ByteString)
-> ([OSCBundle] -> [ByteString]) -> [OSCBundle] -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (OSCBundle -> ByteString) -> [OSCBundle] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map (ByteString -> ByteString
encodedOSC_addLength (ByteString -> ByteString)
-> (OSCBundle -> ByteString) -> OSCBundle -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OSCBundle -> ByteString
encodeOSCBundle) ([OSCBundle] -> ByteString) -> [OSCBundle] -> ByteString
forall a b. (a -> b) -> a -> b
$ [OSCBundle]
withEnd
where
sortedBundles :: [OSCBundle]
sortedBundles :: [OSCBundle]
sortedBundles =
(OSCBundle -> OSCBundle -> Ordering) -> [OSCBundle] -> [OSCBundle]
forall a. (a -> a -> Ordering) -> [a] -> [a]
L.sortBy (\(OSCBundle Timestamp
t0 [Either ByteString OSC]
_) (OSCBundle Timestamp
t1 [Either ByteString OSC]
_) -> Timestamp -> Timestamp -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Timestamp
t0 Timestamp
t1) [OSCBundle]
bundles
sortedBundlesWithDefinitionsFirst :: [OSCBundle]
sortedBundlesWithDefinitionsFirst :: [OSCBundle]
sortedBundlesWithDefinitionsFirst =
(OSCBundle -> OSCBundle) -> [OSCBundle] -> [OSCBundle]
forall a b. (a -> b) -> [a] -> [b]
map OSCBundle -> OSCBundle
putDefinitionsFirst [OSCBundle]
joinedByTime
where
joinedByTime :: [OSCBundle]
joinedByTime :: [OSCBundle]
joinedByTime =
((([OSCBundle] -> OSCBundle) -> [[OSCBundle]] -> [OSCBundle])
-> [[OSCBundle]] -> ([OSCBundle] -> OSCBundle) -> [OSCBundle]
forall a b c. (a -> b -> c) -> b -> a -> c
flip ([OSCBundle] -> OSCBundle) -> [[OSCBundle]] -> [OSCBundle]
forall a b. (a -> b) -> [a] -> [b]
map) [[OSCBundle]]
groupedByTime (([OSCBundle] -> OSCBundle) -> [OSCBundle])
-> ([OSCBundle] -> OSCBundle) -> [OSCBundle]
forall a b. (a -> b) -> a -> b
$ \case
as :: [OSCBundle]
as@(OSCBundle Timestamp
t [Either ByteString OSC]
_:[OSCBundle]
_) ->
Timestamp -> [Either ByteString OSC] -> OSCBundle
OSCBundle Timestamp
t ((OSCBundle -> [Either ByteString OSC])
-> [OSCBundle] -> [Either ByteString OSC]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\(OSCBundle Timestamp
_ [Either ByteString OSC]
a) -> [Either ByteString OSC]
a) [OSCBundle]
as)
[] -> [Char] -> OSCBundle
forall a. HasCallStack => [Char] -> a
error [Char]
"Should be impossible"
groupedByTime :: [[OSCBundle]]
groupedByTime :: [[OSCBundle]]
groupedByTime =
(OSCBundle -> OSCBundle -> Bool) -> [OSCBundle] -> [[OSCBundle]]
forall a. (a -> a -> Bool) -> [a] -> [[a]]
L.groupBy (\(OSCBundle Timestamp
t0 [Either ByteString OSC]
_) (OSCBundle Timestamp
t1 [Either ByteString OSC]
_) -> Timestamp
t1 Timestamp -> Timestamp -> Bool
forall a. Eq a => a -> a -> Bool
== Timestamp
t0) [OSCBundle]
sortedBundles
putDefinitionsFirst :: OSCBundle -> OSCBundle
putDefinitionsFirst :: OSCBundle -> OSCBundle
putDefinitionsFirst (OSCBundle Timestamp
t [Either ByteString OSC]
actions) = Timestamp -> [Either ByteString OSC] -> OSCBundle
OSCBundle Timestamp
t ([Either ByteString OSC] -> OSCBundle)
-> [Either ByteString OSC] -> OSCBundle
forall a b. (a -> b) -> a -> b
$ (\([Either ByteString OSC]
a,[Either ByteString OSC]
b)->[Either ByteString OSC]
a[Either ByteString OSC]
-> [Either ByteString OSC] -> [Either ByteString OSC]
forall a. Semigroup a => a -> a -> a
<>[Either ByteString OSC]
b) (([Either ByteString OSC], [Either ByteString OSC])
-> [Either ByteString OSC])
-> ([Either ByteString OSC], [Either ByteString OSC])
-> [Either ByteString OSC]
forall a b. (a -> b) -> a -> b
$
(((Either ByteString OSC -> Bool)
-> [Either ByteString OSC]
-> ([Either ByteString OSC], [Either ByteString OSC]))
-> [Either ByteString OSC]
-> (Either ByteString OSC -> Bool)
-> ([Either ByteString OSC], [Either ByteString OSC])
forall a b c. (a -> b -> c) -> b -> a -> c
flip (Either ByteString OSC -> Bool)
-> [Either ByteString OSC]
-> ([Either ByteString OSC], [Either ByteString OSC])
forall a. (a -> Bool) -> [a] -> ([a], [a])
L.partition) [Either ByteString OSC]
actions ((Either ByteString OSC -> Bool)
-> ([Either ByteString OSC], [Either ByteString OSC]))
-> (Either ByteString OSC -> Bool)
-> ([Either ByteString OSC], [Either ByteString OSC])
forall a b. (a -> b) -> a -> b
$ \case
Right (OSC ByteString
"/d_recv" [OSCDatum]
_) -> Bool
True
Either ByteString OSC
_ -> Bool
False
lastTimestamp :: Timestamp
lastTimestamp = (\(OSCBundle Timestamp
t [Either ByteString OSC]
_) ->Timestamp
t) (OSCBundle -> Timestamp) -> OSCBundle -> Timestamp
forall a b. (a -> b) -> a -> b
$ [OSCBundle] -> OSCBundle
forall a. [a] -> a
last [OSCBundle]
sortedBundles
withEnd :: [OSCBundle]
withEnd = [[OSCBundle]] -> [OSCBundle]
forall a. Monoid a => [a] -> a
mconcat [
[Timestamp -> [Either ByteString OSC] -> OSCBundle
OSCBundle (Double -> Timestamp
Timestamp Double
0) [OSC -> Either ByteString OSC
forall a b. b -> Either a b
Right OSC
initTreeCommand]]
,[OSCBundle]
sortedBundlesWithDefinitionsFirst
,[Timestamp -> [Either ByteString OSC] -> OSCBundle
OSCBundle Timestamp
lastTimestamp [OSC -> Either ByteString OSC
forall a b. b -> Either a b
Right (OSC -> Either ByteString OSC) -> OSC -> Either ByteString OSC
forall a b. (a -> b) -> a -> b
$ ByteString -> [OSCDatum] -> OSC
OSC ByteString
"" []]]
]
initTreeCommand :: OSC
initTreeCommand :: OSC
initTreeCommand =
NodeId -> AddAction -> NodeId -> OSC
SCCmd.g_new (Int32 -> NodeId
NodeId Int32
1) AddAction
SCCmd.AddToHead (Int32 -> NodeId
NodeId Int32
0)