module Sound.OSC.Packet where
import Data.List
import Sound.OSC.Datum
import Sound.OSC.Time
type Address_Pattern = String
data Message = Message {messageAddress :: !Address_Pattern
,messageDatum :: ![Datum]}
deriving (Eq,Read,Show)
message :: Address_Pattern -> [Datum] -> Message
message a xs =
case a of
'/':_ -> Message a xs
_ -> error "message: ill-formed address pattern"
data Bundle = Bundle {bundleTime :: !Time
,bundleMessages :: ![Message]}
deriving (Eq,Read,Show)
instance Ord Bundle where
compare (Bundle a _) (Bundle b _) = compare a b
bundle :: Time -> [Message] -> Bundle
bundle t xs =
case xs of
[] -> error "bundle: empty?"
_ -> Bundle t xs
data Packet = Packet_Message {packetMessage :: !Message}
| Packet_Bundle {packetBundle :: !Bundle}
deriving (Eq,Read,Show)
p_bundle :: Time -> [Message] -> Packet
p_bundle t = Packet_Bundle . bundle t
p_message :: Address_Pattern -> [Datum] -> Packet
p_message a = Packet_Message . message a
packetTime :: Packet -> Time
packetTime = at_packet (const immediately) bundleTime
packetMessages :: Packet -> [Message]
packetMessages = at_packet return bundleMessages
packet_to_bundle :: Packet -> Bundle
packet_to_bundle = at_packet (\m -> Bundle immediately [m]) id
packet_to_message :: Packet -> Maybe Message
packet_to_message p =
case p of
Packet_Bundle b ->
case b of
Bundle t [m] -> if t == immediately then Just m else Nothing
_ -> Nothing
Packet_Message m -> Just m
packet_is_immediate :: Packet -> Bool
packet_is_immediate = (== immediately) . packetTime
at_packet :: (Message -> a) -> (Bundle -> a) -> Packet -> a
at_packet f g p =
case p of
Packet_Message m -> f m
Packet_Bundle b -> g b
message_has_address :: Address_Pattern -> Message -> Bool
message_has_address x = (== x) . messageAddress
bundle_has_address :: Address_Pattern -> Bundle -> Bool
bundle_has_address x = any (message_has_address x) . bundleMessages
packet_has_address :: Address_Pattern -> Packet -> Bool
packet_has_address x =
at_packet (message_has_address x)
(bundle_has_address x)
messagePP :: FP_Precision -> Message -> String
messagePP p (Message a d) =
let d' = map (datumPP p) d
in unwords ("#message" : a : d')
bundlePP :: FP_Precision -> Bundle -> String
bundlePP p (Bundle t m) =
let m' = intersperse ";" (map (messagePP p) m)
in unwords ("#bundle" : timePP p t : m')
packetPP :: FP_Precision -> Packet -> String
packetPP p pkt =
case pkt of
Packet_Message m -> messagePP p m
Packet_Bundle b -> bundlePP p b