module Sound.OpenSoundControl.Coding.Encode.Builder (buildOSC
,encodeOSC
,encodeOSC') where
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
import Data.Monoid (mappend, mconcat)
import Data.Word (Word8)
import Sound.OpenSoundControl.Coding.Byte (align, bundleHeader)
import Sound.OpenSoundControl.Time
import Sound.OpenSoundControl.Type (Datum(..), OSC(..), tag)
descriptor :: [Datum] -> String
descriptor l = ',' : map tag l
padding :: Integral i => i -> [Word8]
padding n = replicate (fromIntegral n) 0
build_string :: String -> B.Builder
build_string s = B.fromString s `mappend` B.fromWord8s (0:padding (align (length s + 1)))
build_bytes :: L.ByteString -> B.Builder
build_bytes s = B.fromInt32be (fromIntegral (L.length s))
`mappend` B.fromLazyByteString s
`mappend` B.fromWord8s (padding (align (L.length s)))
build_datum :: Datum -> B.Builder
build_datum (Int i) = B.fromInt32be (fromIntegral i)
build_datum (Float f) = B.fromWord32be (I.floatToWord (realToFrac f))
build_datum (Double d) = B.fromWord64be (I.doubleToWord d)
build_datum (TimeStamp t) = B.fromWord64be (fromIntegral (as_ntpi t))
build_datum (String s) = build_string s
build_datum (Midi (b0,b1,b2,b3)) = B.fromWord8s [b0,b1,b2,b3]
build_datum (Blob b) = build_bytes b
build_message :: String -> [Datum] -> B.Builder
build_message c l =
mconcat [ build_string c
, build_string (descriptor l)
, mconcat $ map build_datum l ]
build_bundle_ntpi :: NTPi -> [OSC] -> B.Builder
build_bundle_ntpi t l =
mconcat [ B.fromLazyByteString bundleHeader
, B.fromWord64be t
, mconcat $ map (build_bytes . B.toLazyByteString . buildOSC) l ]
buildOSC :: OSC -> B.Builder
buildOSC (Message c l) = build_message c l
buildOSC (Bundle (NTPi t) l) = build_bundle_ntpi t l
buildOSC (Bundle (NTPr t) l) = build_bundle_ntpi (ntpr_ntpi t) l
buildOSC (Bundle (UTCr t) l) = build_bundle_ntpi (utcr_ntpi t) l
encodeOSC :: OSC -> L.ByteString
encodeOSC = B.toLazyByteString . buildOSC
encodeOSC' :: OSC -> S.ByteString
encodeOSC' = B.toByteString . buildOSC