{-# LANGUAGE CPP #-}
module Sound.OSC.Coding.Encode.Builder
(build_packet
,encodeMessage
,encodeBundle
,encodePacket
,encodePacket_strict) where
import Data.Word
import qualified Data.Binary.IEEE754 as I
import qualified Data.ByteString as S
import qualified Data.ByteString.Lazy as L
import qualified Blaze.ByteString.Builder as B
import qualified Blaze.ByteString.Builder.Char8 as B
#ifdef IMPORT_SEMIGROUP
import Data.Semigroup
#endif
import qualified Sound.OSC.Coding.Byte as Byte
import qualified Sound.OSC.Coding.Convert as Convert
import Sound.OSC.Datum
import Sound.OSC.Packet
import Sound.OSC.Time
padding :: Int -> [Word8]
padding n = replicate n 0
nul_and_padding :: Int -> B.Builder
nul_and_padding n = B.fromWord8s (0 : padding (Byte.align n))
build_ascii :: ASCII -> B.Builder
build_ascii s = B.fromByteString s <> nul_and_padding (S.length s + 1)
build_string :: String -> B.Builder
build_string s = B.fromString s <> nul_and_padding (length s + 1)
build_bytes :: L.ByteString -> B.Builder
build_bytes s =
B.fromInt32be (Convert.int64_to_int32 (L.length s)) <>
B.fromLazyByteString s <>
B.fromWord8s (padding (Convert.int64_to_int (Byte.align (L.length s))))
build_datum :: Datum -> B.Builder
build_datum d =
case d of
Int32 i -> B.fromInt32be i
Int64 i -> B.fromInt64be i
Float n -> B.fromWord32be (I.floatToWord n)
Double n -> B.fromWord64be (I.doubleToWord n)
TimeStamp t -> B.fromWord64be (ntpr_to_ntpi t)
ASCII_String s -> build_ascii s
Midi (MIDI b0 b1 b2 b3) -> B.fromWord8s [b0,b1,b2,b3]
Blob b -> build_bytes b
build_message :: Message -> B.Builder
build_message (Message c l) =
mconcat [build_string c
,build_ascii (descriptor l)
,mconcat (map build_datum l)]
build_bundle_ntpi :: NTP64 -> [Message] -> B.Builder
build_bundle_ntpi t l =
mconcat [B.fromLazyByteString Byte.bundleHeader
,B.fromWord64be t
,mconcat (map (build_bytes . B.toLazyByteString . build_message) l)]
build_packet :: Packet -> B.Builder
build_packet o =
case o of
Packet_Message m -> build_message m
Packet_Bundle (Bundle t m) -> build_bundle_ntpi (ntpr_to_ntpi t) m
{-# INLINE encodePacket #-}
{-# INLINE encodeMessage #-}
{-# INLINE encodeBundle #-}
{-# INLINE encodePacket_strict #-}
encodePacket :: Packet -> L.ByteString
encodePacket = B.toLazyByteString . build_packet
encodeMessage :: Message -> L.ByteString
encodeMessage = encodePacket . Packet_Message
encodeBundle :: Bundle -> L.ByteString
encodeBundle = encodePacket . Packet_Bundle
encodePacket_strict :: Packet -> S.ByteString
encodePacket_strict = B.toByteString . build_packet