diff --git a/README b/README
new file mode 100644
--- /dev/null
+++ b/README
@@ -0,0 +1,10 @@
+hosc - Haskell Open Sound Control
+
+hosc provides Sound.OpenSoundControl, a Haskell module that implements
+the Open Sound Control byte protocol.
+
+  http://slavepianos.org/rd/
+  http://haskell.org/
+  http://opensoundcontrol.org/
+
+(c) rohan drape, 2006-2008, GPL.2, http://gnu.org/copyleft/
diff --git a/Sound/OpenSoundControl/Byte.hs b/Sound/OpenSoundControl/Byte.hs
--- a/Sound/OpenSoundControl/Byte.hs
+++ b/Sound/OpenSoundControl/Byte.hs
@@ -6,56 +6,74 @@
 import Data.Binary
 import Sound.OpenSoundControl.Cast (f32_i32, f64_i64, i32_f32, i64_f64)
 
+-- | Encode a signed 8-bit integer.
 encode_i8 :: Int -> B.ByteString
 encode_i8 n = encode (fromIntegral n :: Int8)
 
+-- | Encode a signed 16-bit integer.
 encode_i16 :: Int -> B.ByteString
 encode_i16 n = encode (fromIntegral n :: Int16)
 
+-- | Encode a signed 32-bit integer.
 encode_i32 :: Int -> B.ByteString
 encode_i32 n = encode (fromIntegral n :: Int32)
 
+-- | Encode an unsigned 16-bit integer.
 encode_u32 :: Int -> B.ByteString
 encode_u32 n = encode (fromIntegral n :: Word32)
 
+-- | Encode a signed 64-bit integer.
 encode_i64 :: Integer -> B.ByteString
 encode_i64 n = encode (fromIntegral n :: Int64)
 
+-- | Encode an unsigned 64-bit integer.
 encode_u64 :: Integer -> B.ByteString
 encode_u64 n = encode (fromIntegral n :: Word64)
 
+-- | Encode a 32-bit IEEE floating point number.
 encode_f32 :: Double -> B.ByteString
 encode_f32 n = encode (f32_i32 (realToFrac n))
 
+-- | Encode a 64-bit IEEE floating point number.
 encode_f64 :: Double -> B.ByteString
 encode_f64 n = encode (f64_i64 n)
 
+-- | Encode an ASCII string.
 encode_str :: String -> B.ByteString
 encode_str s = B.pack (map (fromIntegral . ord) s)
 
+-- | Decode a signed 8-bit integer.
 decode_i8 :: B.ByteString -> Int
 decode_i8 b = fromIntegral (decode b :: Int8)
 
+-- | Decode a signed 16-bit integer.
 decode_i16 :: B.ByteString -> Int
 decode_i16 b = fromIntegral (decode b :: Int16)
 
+-- | Decode a signed 32-bit integer.
 decode_i32 :: B.ByteString -> Int
 decode_i32 b = fromIntegral (decode b :: Int32)
 
+-- | Decode an unsigned 32-bit integer.
 decode_u32 :: B.ByteString -> Int
 decode_u32 b = fromIntegral (decode b :: Word32)
 
+-- | Decode a signed 64-bit integer.
 decode_i64 :: B.ByteString -> Integer
 decode_i64 b = fromIntegral (decode b :: Int64)
 
+-- | Decode an unsigned 64-bit integer.
 decode_u64 :: B.ByteString -> Integer
 decode_u64 b = fromIntegral (decode b :: Word64)
 
+-- | Decode a 32-bit IEEE floating point number.
 decode_f32 :: B.ByteString -> Double
 decode_f32 b = realToFrac (i32_f32 (decode b :: Int32))
 
+-- | Decode a 64-bit IEEE floating point number.
 decode_f64 :: B.ByteString -> Double
 decode_f64 b = i64_f64 (decode b :: Int64)
 
+-- | Decode an ASCII string.
 decode_str :: B.ByteString -> String
 decode_str b = map (chr . fromIntegral) (B.unpack b)
diff --git a/Sound/OpenSoundControl/OSC.hs b/Sound/OpenSoundControl/OSC.hs
--- a/Sound/OpenSoundControl/OSC.hs
+++ b/Sound/OpenSoundControl/OSC.hs
@@ -1,5 +1,7 @@
-module Sound.OpenSoundControl.OSC ( OSC(..)
-                                  , Datum(..)
+module Sound.OpenSoundControl.OSC ( OSC, message, bundle
+                                  , address, arguments
+                                  , timestamp, messages
+                                  , Datum, int, float, double, string, blob
                                   , encodeOSC
                                   , encodeOSC_NTP
                                   , decodeOSC ) where
@@ -21,11 +23,63 @@
            | Blob [Word8]
              deriving (Eq, Show)
 
+-- | Construct OSC int datum.
+int :: Int -> Datum
+int = Int
+
+-- | Construct OSC float datum.
+float :: Double -> Datum
+float = Float
+
+-- | Construct OSC double datum.
+double :: Double -> Datum
+double = Double
+
+-- | Construct OSC string datum.
+string :: String -> Datum
+string = String
+
+-- | Construct OSC blob datum.
+blob :: [Word8] -> Datum
+blob = Blob
+
 -- | An OSC packet.
 data OSC = Message String [Datum]
          | Bundle Double [OSC]
            deriving (Eq, Show)
 
+-- | OSC message constructor
+message :: String -> [Datum] -> OSC
+message = Message
+
+-- | OSC bundle constructor
+bundle :: Double -> [OSC] -> OSC
+bundle = Bundle
+
+-- | Retrieve the address of an OSC message,
+--   or Nothing for a bundle.
+address :: OSC -> Maybe String
+address (Message s _) = Just s
+address (Bundle _ _) = Nothing
+
+-- | Retrieve the arguments of an OSC message,
+--   or Nothing for a bundle.
+arguments :: OSC -> Maybe [Datum]
+arguments (Message _ a) = Just a
+arguments (Bundle _ _) = Nothing
+
+-- | Retrieve the timestamp of an OSC bundle,
+--   or Nothing for a message.
+timestamp :: OSC -> Maybe Double
+timestamp (Bundle t _) = Just t
+timestamp (Message _ _) = Nothing
+
+-- | Retrieve the messages in an OSC bundle,
+--   or Nothing for a message.
+messages :: OSC -> Maybe [OSC]
+messages (Bundle _ m) = Just m
+messages (Message _ _) = Nothing
+
 instance Ord OSC where
     compare (Bundle a _) (Bundle b _) = compare a b
     compare _            _            = EQ
@@ -71,7 +125,7 @@
 -- | Encode an OSC packet.
 encodeOSC :: OSC -> B.ByteString
 encodeOSC (Message c l) = encodeOSC_NTP (Message c l)
-encodeOSC (Bundle t l) = encodeOSC_NTP (Bundle (t + n) l) 
+encodeOSC (Bundle t l) = encodeOSC_NTP (Bundle (t + n) l)
     where n = (70 * 365 + 17) * 24 * 60 * 60
 
 -- | The plain byte count of an OSC value.
@@ -79,7 +133,7 @@
 size 'i' _ = 4
 size 'f' _ = 4
 size 'd' _ = 8
-size 's' b = fromIntegral (fromMaybe 
+size 's' b = fromIntegral (fromMaybe
                            (error ("no terminating zero found in " ++ show b))
                            (B.elemIndex 0 b))
 size 'b' b = decode_i32 (B.take 4 b)
diff --git a/Sound/OpenSoundControl/Transport.hs b/Sound/OpenSoundControl/Transport.hs
--- a/Sound/OpenSoundControl/Transport.hs
+++ b/Sound/OpenSoundControl/Transport.hs
@@ -2,8 +2,8 @@
                                         , withTransport
                                         , wait ) where
 
-import Sound.OpenSoundControl.OSC (OSC(..))
-import Control.Exception (bracket)
+import Sound.OpenSoundControl.OSC
+import Control.Exception
 
 -- | Abstract over the underlying transport protocol.
 class Transport t where
@@ -16,8 +16,7 @@
 
 -- | Does the OSC message have the specified address.
 hasAddress :: String -> OSC -> Bool
-hasAddress addr (Message s _) = s == addr
-hasAddress _    (Bundle _ _)  = False
+hasAddress addr o = maybe False (== addr) (address o)
 
 -- | Repeat action until predicate holds on result.
 untilM :: Monad m => (a -> Bool) -> m a -> m a
diff --git a/hosc.cabal b/hosc.cabal
--- a/hosc.cabal
+++ b/hosc.cabal
@@ -1,7 +1,7 @@
 Name:             hosc
-Version:          0.1.1
+Version:          0.2
 License:          GPL
-Copyright:        Rohan Drape, 2006-2007
+Copyright:        Rohan Drape, 2006-2008
 Author:           Rohan Drape
 Maintainer:       rd@slavepianos.org
 Stability:        Experimental
@@ -9,28 +9,17 @@
 Synopsis:         Haskell Open Sound Control
 Description:      Haskell implementation of the Open Sound Control byte protocol
 Category:         Sound
-Tested-With:      GHC==6.4.1, GHC==6.8.2
-Cabal-Version:    >=1.2
+Tested-With:      GHC==6.8.2
 Build-Type:       Simple
-
-Flag splitBase
-  description: Choose the new smaller, split-up base package.
-
-Library
-  Build-Depends: bytestring, binary, network, time >= 1.1
-  -- time version 1.1 provides secondsToDiffTime
-  If flag(splitBase)
-    Build-Depends: base >= 2, array
-  Else
-    Build-Depends: base >= 1.0 && < 2
+Build-Depends:    array, base, bytestring, binary, network, time
+GHC-Options:      -Wall -O2
+Exposed-modules:  Sound.OpenSoundControl
+                  Sound.OpenSoundControl.OSC
+                  Sound.OpenSoundControl.Time
+                  Sound.OpenSoundControl.Byte
+                  Sound.OpenSoundControl.Transport
+                  Sound.OpenSoundControl.Transport.TCP
+                  Sound.OpenSoundControl.Transport.UDP
+Other-modules:    Sound.OpenSoundControl.Cast
 
-  GHC-Options:      -Wall
-  Exposed-modules:
-    Sound.OpenSoundControl
-    Sound.OpenSoundControl.OSC
-    Sound.OpenSoundControl.Time
-    Sound.OpenSoundControl.Cast
-    Sound.OpenSoundControl.Byte
-    Sound.OpenSoundControl.Transport
-    Sound.OpenSoundControl.Transport.TCP
-    Sound.OpenSoundControl.Transport.UDP
+Data-Files:       README
