diff --git a/Data/Iteratee/ZoomCache.hs b/Data/Iteratee/ZoomCache.hs
--- a/Data/Iteratee/ZoomCache.hs
+++ b/Data/Iteratee/ZoomCache.hs
@@ -41,7 +41,8 @@
 
 module Data.Iteratee.ZoomCache (
   -- * Types
-    Stream(..)
+    Block(..)
+  , BlockData(..)
 
   -- * Reading zoom-cache files and ByteStrings
   , enumCacheFile
@@ -49,9 +50,9 @@
   , wholeTrackSummaryUTC
 
   , iterHeaders
-  , enumStream
-  , enumStreamIncomplete
-  , enumStreamTrackNo
+  , enumBlock
+  , enumBlockIncomplete
+  , enumBlockTrackNo
 
   -- * Seeking
   , seekTimeStamp
@@ -92,6 +93,7 @@
 import Data.Ratio
 import Data.Time
 
+import Data.Iteratee.ZoomCache.Seek
 import Data.Iteratee.ZoomCache.Utils
 import Data.ZoomCache.Common
 import Data.ZoomCache.Format
@@ -101,31 +103,26 @@
 
 ----------------------------------------------------------------------
 
-data Stream =
-    StreamPacket
-        { strmFile    :: CacheFile
-        , strmTrack   :: TrackNo
-        , strmPacket  :: PacketSO
-        }
-    | StreamSummary
-        { strmFile    :: CacheFile
-        , strmTrack   :: TrackNo
-        , strmSummary :: ZoomSummarySO
+data Block = Block
+        { blkFile  :: CacheFile
+        , blkTrack :: TrackNo
+        , blkData  :: BlockData
         }
 
-instance Timestampable Stream where
-    timestamp (StreamPacket c t p) = timestamp (packetFromCTPSO (c,t,p))
-    timestamp (StreamSummary c t s) = timestamp (summaryFromCTSO (c,t,s))
+data BlockData = BlockPacket PacketSO | BlockSummary ZoomSummarySO
 
+instance Timestampable Block where
+    timestamp (Block c t (BlockPacket p)) = timestamp (packetFromCTPSO (c,t,p))
+    timestamp (Block c t (BlockSummary s)) = timestamp (summaryFromCTSO (c,t,s))
+
 ----------------------------------------------------------------------
 
 -- | Read the summary of an entire track.
 wholeTrackSummary :: (Functor m, MonadIO m)
-                  => [IdentifyCodec]
-                  -> TrackNo
-                  -> Iteratee ByteString m (TrackSpec, ZoomSummary)
-wholeTrackSummary identifiers trackNo = I.joinI $ enumCacheFile identifiers .
-    I.joinI . filterTracks [trackNo] .  I.joinI . enumCTSO $ f <$> I.last
+                  => TrackNo
+                  -> Iteratee [Block] m (TrackSpec, ZoomSummary)
+wholeTrackSummary trackNo = I.joinI $
+    filterTracks [trackNo] .  I.joinI . enumCTSO $ f <$> I.last
     where
         f :: (CacheFile, TrackNo, ZoomSummarySO) -> (TrackSpec, ZoomSummary)
         f ctso@(cf, _, _) = (fromJust $ IM.lookup trackNo (cfSpecs cf),
@@ -133,11 +130,10 @@
 
 -- | Read the summary of an entire track.
 wholeTrackSummaryUTC :: (Functor m, MonadIO m)
-                     => [IdentifyCodec]
-                     -> TrackNo
-                     -> Iteratee ByteString m (TrackSpec, Maybe ZoomSummaryUTC)
-wholeTrackSummaryUTC identifiers trackNo = I.joinI $ enumCacheFile identifiers .
-    I.joinI . filterTracks [trackNo] .  I.joinI . enumCTSO $ f <$> I.last
+                     => TrackNo
+                     -> Iteratee [Block] m (TrackSpec, Maybe ZoomSummaryUTC)
+wholeTrackSummaryUTC trackNo = I.joinI $
+    filterTracks [trackNo] .  I.joinI . enumCTSO $ f <$> I.last
     where
         f :: (CacheFile, TrackNo, ZoomSummarySO) -> (TrackSpec, Maybe ZoomSummaryUTC)
         f ctso@(cf, _, _) = (fromJust $ IM.lookup trackNo (cfSpecs cf),
@@ -146,7 +142,7 @@
 
 -- | Filter just the raw data
 enumPackets :: (Functor m, Monad m)
-            => I.Enumeratee [Stream] [Packet] m a
+            => I.Enumeratee [Block] [Packet] m a
 enumPackets = I.joinI . enumCTPSO . I.mapChunks (map packetFromCTPSO)
 
 -- | Convert a CTPSO triple into a Packet
@@ -159,7 +155,7 @@
 
 -- | Filter just the raw data, timestamped by UTC
 enumPacketsUTC :: (Functor m, Monad m)
-               => I.Enumeratee [Stream] [PacketUTC] m a
+               => I.Enumeratee [Block] [PacketUTC] m a
 enumPacketsUTC = I.joinI . enumCTPSO . I.mapChunks (catMaybes . map packetUTCFromCTPSO)
 
 -- | Convert a CTPSO triple into a Packet
@@ -175,14 +171,14 @@
 -- | Filter summaries at a particular summary level
 enumSummaryLevel :: (Functor m, Monad m)
                  => Int
-                 -> I.Enumeratee [Stream] [ZoomSummary] m a
+                 -> I.Enumeratee [Block] [ZoomSummary] m a
 enumSummaryLevel level =
     I.joinI . enumSummaries .
     I.filter (\(ZoomSummary s) -> summaryLevel s == level)
 
 -- | Filter summaries at all levels
 enumSummaries :: (Functor m, Monad m)
-              => I.Enumeratee [Stream] [ZoomSummary] m a
+              => I.Enumeratee [Block] [ZoomSummary] m a
 enumSummaries = I.joinI . enumCTSO .  I.mapChunks (map summaryFromCTSO)
 
 -- | Convert a CTSO triple into a ZoomSummary
@@ -197,14 +193,14 @@
 -- | Filter summaries at a particular summary level
 enumSummaryUTCLevel :: (Functor m, Monad m)
                     => Int
-                    -> I.Enumeratee [Stream] [ZoomSummaryUTC] m a
+                    -> I.Enumeratee [Block] [ZoomSummaryUTC] m a
 enumSummaryUTCLevel level =
     I.joinI . enumSummariesUTC .
     I.filter (\(ZoomSummaryUTC s) -> summaryUTCLevel s == level)
 
 -- | Filter summaries at all levels
 enumSummariesUTC :: (Functor m, Monad m)
-                 => I.Enumeratee [Stream] [ZoomSummaryUTC] m a
+                 => I.Enumeratee [Block] [ZoomSummaryUTC] m a
 enumSummariesUTC = I.joinI . enumCTSO .  I.mapChunks (catMaybes . map summaryUTCFromCTSO)
 
 -- | Convert a CTSO triple into a ZoomSummaryUTC
@@ -219,45 +215,45 @@
 
 -- | Filter just the raw data
 enumPacketSOs :: (Functor m, Monad m)
-              => I.Enumeratee [Stream] [PacketSO] m a
+              => I.Enumeratee [Block] [PacketSO] m a
 enumPacketSOs = I.joinI . enumCTPSO . I.mapChunks (map (\(_,_,p) -> p))
 
 -- | Filter summaries at a particular summary level
 enumSummarySOLevel :: (Functor m, Monad m)
                    => Int
-                   -> I.Enumeratee [Stream] [ZoomSummarySO] m a
+                   -> I.Enumeratee [Block] [ZoomSummarySO] m a
 enumSummarySOLevel level =
     I.joinI . enumSummarySOs .
     I.filter (\(ZoomSummarySO s) -> summarySOLevel s == level)
 
 -- | Filter summaries at all levels
 enumSummarySOs :: (Functor m, Monad m)
-               => I.Enumeratee [Stream] [ZoomSummarySO] m a
+               => I.Enumeratee [Block] [ZoomSummarySO] m a
 enumSummarySOs = I.joinI . enumCTSO .  I.mapChunks (map (\(_,_,s) -> s))
 
 -- | Filter raw data
 enumCTPSO :: (Functor m, Monad m)
-          => I.Enumeratee [Stream] [(CacheFile, TrackNo, PacketSO)] m a
+          => I.Enumeratee [Block] [(CacheFile, TrackNo, PacketSO)] m a
 enumCTPSO = I.mapChunks (catMaybes . map toCTPSO)
     where
-        toCTPSO :: Stream -> Maybe (CacheFile, TrackNo, PacketSO)
-        toCTPSO StreamPacket{..} = Just (strmFile, strmTrack, strmPacket)
-        toCTPSO _                = Nothing
+        toCTPSO :: Block -> Maybe (CacheFile, TrackNo, PacketSO)
+        toCTPSO (Block c t (BlockPacket p)) = Just (c, t, p)
+        toCTPSO _                           = Nothing
 
 -- | Filter summaries
 enumCTSO :: (Functor m, Monad m)
-         => I.Enumeratee [Stream] [(CacheFile, TrackNo, ZoomSummarySO)] m a
+         => I.Enumeratee [Block] [(CacheFile, TrackNo, ZoomSummarySO)] m a
 enumCTSO = I.mapChunks (catMaybes . map toCTSO)
     where
-        toCTSO :: Stream -> Maybe (CacheFile, TrackNo, ZoomSummarySO)
-        toCTSO StreamSummary{..} = Just (strmFile, strmTrack, strmSummary)
-        toCTSO _                 = Nothing
+        toCTSO :: Block -> Maybe (CacheFile, TrackNo, ZoomSummarySO)
+        toCTSO (Block c t (BlockSummary s)) = Just (c, t, s)
+        toCTSO _                            = Nothing
 
 -- | Filter to a given list of track names
 filterTracksByName :: (Functor m, Monad m)
                    => CacheFile
                    -> [ByteString]
-                   -> I.Enumeratee [Stream] [Stream] m a
+                   -> I.Enumeratee [Block] [Block] m a
 filterTracksByName CacheFile{..} names = filterTracks tracks
     where
         tracks :: [TrackNo]
@@ -268,22 +264,21 @@
 -- | Filter to a given list of track numbers
 filterTracks :: (Functor m, Monad m)
              => [TrackNo]
-             -> I.Enumeratee [Stream] [Stream] m a
+             -> I.Enumeratee [Block] [Block] m a
 filterTracks tracks = I.filter fil
     where
-        fil :: Stream -> Bool
-        fil StreamPacket{..}  = strmTrack `elem` tracks
-        fil StreamSummary{..} = strmTrack `elem` tracks
+        fil :: Block -> Bool
+        fil b = (blkTrack b) `elem` tracks
 
 -- | An enumeratee of a zoom-cache file, from the global header onwards.
 -- The global and track headers will be transparently read, and the 
--- 'CacheFile' visible in the 'Stream' elements.
+-- 'CacheFile' visible in the 'Block' elements.
 enumCacheFile :: (Functor m, MonadIO m)
               => [IdentifyCodec]
-              -> I.Enumeratee ByteString [Stream] m a
+              -> I.Enumeratee ByteString [Block] m a
 enumCacheFile identifiers iter = do
     fi <- iterHeaders identifiers
-    enumStream fi iter
+    enumBlock fi iter
 
 -- | An enumeratee of zoom-cache data, after global and track headers
 -- have been read, or if the 'CacheFile' has been acquired elsewhere.
@@ -292,43 +287,44 @@
 -- This function should only be used in applications where only one track is
 -- used from a file; if you need to process multiple tracks independently then
 -- give each an iteratee filtered by filterTracks or filterTracksByName, and
--- run these in parallel on the output of 'enumCacheFile' or 'enumStream'.
+-- run these in parallel on the output of 'enumCacheFile' or 'enumBlock'.
 -- Using this function multiple times in parallel will duplicate some parsing.
-enumStreamTrackNo :: (Functor m, MonadIO m)
+enumBlockTrackNo :: (Functor m, MonadIO m)
                   => CacheFile
                   -> TrackNo
-                  -> I.Enumeratee ByteString [Stream] m a
-enumStreamTrackNo cf0 trackNo = I.unfoldConvStreamCheck I.eneeCheckIfDoneIgnore go cf0
+                  -> I.Enumeratee ByteString [Block] m a
+enumBlockTrackNo cf0 trackNo = I.unfoldConvStreamCheck I.eneeCheckIfDoneIgnore go cf0
     where
         go :: (Functor m, MonadIO m)
            => CacheFile
-           -> Iteratee ByteString m (CacheFile, [Stream])
+           -> Iteratee ByteString m (CacheFile, [Block])
         go cf = do
             header <- I.joinI $ I.takeUpTo 8 I.stream2list
             case parseHeader (B.pack header) of
                 Just PacketHeader -> do
                     (_, packet) <- readPacketTrackNo (cfSpecs cf) trackNo
-                    let res = maybe [] (\p -> [StreamPacket cf trackNo p]) packet
+                    let res = maybe [] (\p -> [Block cf trackNo (BlockPacket p)]) packet
                     return (cf, res)
                 Just SummaryHeader -> do
                     (_, summary) <- readSummaryBlockTrackNo (cfSpecs cf) trackNo
-                    let res = maybe [] (\s -> [StreamSummary cf trackNo s]) summary
+                    let res = maybe [] (\s -> [Block cf trackNo (BlockSummary s)]) summary
                     return (cf, res)
                 _ -> return (cf, [])
 
 -- | An iteratee of zoom-cache which produces a singleton list of zoom-cache
 -- stream, if it can.
-iterStream :: (Functor m, MonadIO m) =>
-              CacheFile -> Iteratee ByteString m [Stream]
-iterStream cf = do
+iterBlock :: (Functor m, MonadIO m) =>
+              CacheFile -> Iteratee ByteString m [Block]
+iterBlock cf = do
+    I.dropWhile (/= headerMarker)
     header <- I.joinI $ I.takeUpTo 8 I.stream2list
     case parseHeader (B.pack header) of
         Just PacketHeader -> do
              (trackNo, packet) <- readPacket (cfSpecs cf)
-             return [StreamPacket cf trackNo (fromJust packet)]
+             return [Block cf trackNo (BlockPacket $ fromJust packet)]
         Just SummaryHeader -> do
              (trackNo, summary) <- readSummaryBlock (cfSpecs cf)
-             return [StreamSummary cf trackNo (fromJust summary)]
+             return [Block cf trackNo (BlockSummary $ fromJust summary)]
         _ -> return []
 
 -- | An iteratee of zoom-cache data, after global and track headers
@@ -337,11 +333,11 @@
 -- Unfortunately the iteratee library does not have a convStreamCheck function
 -- (yet), so we end up doing a (trivial) fold when we really just want to do a
 -- map.
-enumStream :: (Functor m, MonadIO m)
+enumBlock :: (Functor m, MonadIO m)
             => CacheFile
-            -> I.Enumeratee ByteString [Stream] m a
-enumStream = I.unfoldConvStreamCheck I.eneeCheckIfDoneIgnore $ \cf ->
-             liftM (cf, ) (iterStream cf)
+            -> I.Enumeratee ByteString [Block] m a
+enumBlock = I.unfoldConvStreamCheck I.eneeCheckIfDonePass $ \cf ->
+             liftM (cf, ) (iterBlock cf)
 
 -- | A version of convStream which will not fail in case EOF is reached at an
 -- unexpected point.
@@ -361,12 +357,12 @@
           I.eneeCheckIfDonePass check $ k str
         e@(Just _) -> I.eneeCheckIfDonePass check . k $ I.EOF e
 
--- | A version of enumStream which won't fail with an EofException if the last
+-- | A version of enumBlock which won't fail with an EofException if the last
 -- bit is incomplete (perhaps still being written to).
-enumStreamIncomplete :: (Functor m, MonadIO m) =>
+enumBlockIncomplete :: (Functor m, MonadIO m) =>
                         CacheFile
-                     -> I.Enumeratee ByteString [Stream] m a
-enumStreamIncomplete = convStreamIncomplete . iterStream
+                     -> I.Enumeratee ByteString [Block] m a
+enumBlockIncomplete = convStreamIncomplete . iterBlock
 
 ------------------------------------------------------------
 
diff --git a/Data/Iteratee/ZoomCache/Seek.hs b/Data/Iteratee/ZoomCache/Seek.hs
new file mode 100644
--- /dev/null
+++ b/Data/Iteratee/ZoomCache/Seek.hs
@@ -0,0 +1,68 @@
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# OPTIONS -Wall #-}
+----------------------------------------------------------------------
+-- |
+-- Module      : Data.Iteratee.ZoomCache.Seek
+-- Copyright   : Conrad Parker
+-- License     : BSD3-style (see LICENSE)
+--
+-- Maintainer  : Conrad Parker <conrad@metadecks.org>
+-- Stability   : unstable
+-- Portability : unknown
+--
+-- Iteratee reading of ZoomCache files.
+----------------------------------------------------------------------
+
+module Data.Iteratee.ZoomCache.Seek (
+    -- * Seeking
+      seekTimeStamp
+    , seekUTCTime
+) where
+
+import Data.Iteratee (Iteratee)
+import qualified Data.Iteratee as I
+import qualified Data.ListLike as LL
+import Data.Time.Clock (UTCTime)
+
+import Data.ZoomCache.Common
+import Data.ZoomCache.Types
+
+----------------------------------------------------------------------
+
+seekTimeStamp :: (LL.ListLike s el, I.Nullable s, I.NullPoint s, Timestampable el, Monad m)
+              => Maybe TimeStamp -> Iteratee s m ()
+seekTimeStamp ts = do
+    I.seek 0
+    dropWhileB (before ts)
+
+seekUTCTime :: (LL.ListLike s el, I.Nullable s, I.NullPoint s, UTCTimestampable el, Monad m)
+            => Maybe UTCTime -> Iteratee s m ()
+seekUTCTime uts = do
+    I.seek 0
+    dropWhileB (beforeUTC uts)
+
+-- |Skip all elements while the predicate is true, but also return the last false element
+--
+-- The analogue of @List.dropWhile@
+dropWhileB :: (Monad m, LL.ListLike s el) => (el -> Bool) -> I.Iteratee s m ()
+dropWhileB p = I.liftI step
+  where
+    step (I.Chunk str)
+      | LL.null left = I.liftI step
+      | otherwise    = I.idone () (I.Chunk left)
+      where
+        left = llDropWhileB p str
+    step stream      = I.idone () stream
+{-# INLINE dropWhileB #-}
+
+{- | Drops all elements form the start of the list that satisfy the
+       function. -}
+llDropWhileB :: LL.ListLike full item => (item -> Bool) -> full -> full
+llDropWhileB = dw LL.empty
+    where
+        dw prev func l
+            | LL.null l = prev
+            | func (LL.head l) = dw (LL.take 1 l) func (LL.tail l)
+            | otherwise = LL.append prev l
+
diff --git a/Data/Iteratee/ZoomCache/Utils.hs b/Data/Iteratee/ZoomCache/Utils.hs
--- a/Data/Iteratee/ZoomCache/Utils.hs
+++ b/Data/Iteratee/ZoomCache/Utils.hs
@@ -15,12 +15,8 @@
 ----------------------------------------------------------------------
 
 module Data.Iteratee.ZoomCache.Utils (
-    -- * Seeking
-      seekTimeStamp
-    , seekUTCTime
-
     -- * Raw data reading iteratees
-    , readInt8
+      readInt8
     , readInt16be
     , readInt32be
     , readInt64be
@@ -47,50 +43,10 @@
 import qualified Data.Iteratee as I
 import qualified Data.ListLike as LL
 import Data.Ratio
-import Data.Time.Clock (UTCTime)
 import Data.Word
 import Unsafe.Coerce (unsafeCoerce)
 
-import Data.ZoomCache.Common
 import Data.ZoomCache.Types
-
-----------------------------------------------------------------------
-
-seekTimeStamp :: (LL.ListLike s el, I.Nullable s, I.NullPoint s, Timestampable el, Monad m)
-              => Maybe TimeStamp -> Iteratee s m ()
-seekTimeStamp ts = do
-    I.seek 0
-    dropWhileB (before ts)
-
-seekUTCTime :: (LL.ListLike s el, I.Nullable s, I.NullPoint s, UTCTimestampable el, Monad m)
-            => Maybe UTCTime -> Iteratee s m ()
-seekUTCTime uts = do
-    I.seek 0
-    dropWhileB (beforeUTC uts)
-
--- |Skip all elements while the predicate is true, but also return the last false element
---
--- The analogue of @List.dropWhile@
-dropWhileB :: (Monad m, LL.ListLike s el) => (el -> Bool) -> I.Iteratee s m ()
-dropWhileB p = I.liftI step
-  where
-    step (I.Chunk str)
-      | LL.null left = I.liftI step
-      | otherwise    = I.idone () (I.Chunk left)
-      where
-        left = llDropWhileB p str
-    step stream      = I.idone () stream
-{-# INLINE dropWhileB #-}
-
-{- | Drops all elements form the start of the list that satisfy the
-       function. -}
-llDropWhileB :: LL.ListLike full item => (item -> Bool) -> full -> full
-llDropWhileB = dw LL.empty
-    where
-        dw prev func l
-            | LL.null l = prev
-            | func (LL.head l) = dw (LL.take 1 l) func (LL.tail l)
-            | otherwise = LL.append prev l
 
 ----------------------------------------------------------------------
 
diff --git a/Data/ZoomCache/Dump.hs b/Data/ZoomCache/Dump.hs
--- a/Data/ZoomCache/Dump.hs
+++ b/Data/ZoomCache/Dump.hs
@@ -48,7 +48,7 @@
                      -> [IdentifyCodec] -> TrackNo -> FilePath -> IO ()
 zoomDumpSummaryLevel lvl = dumpSomething (dumpSummaryLevel lvl)
 
-dumpSomething :: (Stream -> IO ()) -> [IdentifyCodec] -> TrackNo -> FilePath -> IO ()
+dumpSomething :: (Block -> IO ()) -> [IdentifyCodec] -> TrackNo -> FilePath -> IO ()
 dumpSomething f identifiers trackNo = I.fileDriverRandom
     (I.joinI . enumCacheFile identifiers . I.joinI . filterTracks [trackNo] . I.mapM_ $ f)
 
@@ -59,32 +59,32 @@
     putStrLn . prettyGlobal $ cfGlobal
     mapM_ (putStrLn . uncurry prettyTrackSpec) . IM.assocs $ cfSpecs
 
-streamRate :: Stream -> Maybe Rational
-streamRate s = specRate <$> IM.lookup (strmTrack s) (cfSpecs (strmFile s))
+blockRate :: Block -> Maybe Rational
+blockRate b = specRate <$> IM.lookup (blkTrack b) (cfSpecs (blkFile b))
 
-dumpData :: Stream -> IO ()
-dumpData s@StreamPacket{..} = mapM_ (\(t,d) -> putStrLn $ printf "%s: %s" t d) tds
+dumpData :: Block -> IO ()
+dumpData b@(Block _ _ (BlockPacket p)) = mapM_ (\(t,d) -> putStrLn $ printf "%s: %s" t d) tds
     where
-        pretty = case streamRate s of
+        pretty = case blockRate b of
             Just r  -> prettySampleOffset r
             Nothing -> show . unSO
-        tds = zip (map pretty (packetSOSampleOffsets strmPacket)) vals
-        vals = f (packetSOData strmPacket)
+        tds = zip (map pretty (packetSOSampleOffsets p)) vals
+        vals = f (packetSOData p)
         f (ZoomRaw a) = map prettyRaw a
 dumpData _ = return ()
 
-dumpSummary :: Stream -> IO ()
-dumpSummary s@StreamSummary{..} = case streamRate s of
-        Just r  -> putStrLn $ f r strmSummary
+dumpSummary :: Block -> IO ()
+dumpSummary b@(Block _ _ (BlockSummary s)) = case blockRate b of
+        Just r  -> putStrLn $ f r s
         Nothing -> return ()
     where
         f r (ZoomSummarySO a) = prettySummarySO r a
 dumpSummary _ = return ()
 
-dumpSummaryLevel :: Int -> Stream -> IO ()
-dumpSummaryLevel level s@StreamSummary{..}
-    | level == opLevel strmSummary = dumpSummary s
-    | otherwise                    = return ()
+dumpSummaryLevel :: Int -> Block -> IO ()
+dumpSummaryLevel level b@(Block _ _ (BlockSummary s))
+    | level == opLevel s = dumpSummary b
+    | otherwise          = return ()
     where opLevel (ZoomSummarySO a) = summarySOLevel a
 dumpSummaryLevel _ _ = return ()
 
diff --git a/Data/ZoomCache/Format.hs b/Data/ZoomCache/Format.hs
--- a/Data/ZoomCache/Format.hs
+++ b/Data/ZoomCache/Format.hs
@@ -22,8 +22,11 @@
 ----------------------------------------------------------------------
 
 module Data.ZoomCache.Format (
+    -- * One-byte marker at start of all headers
+      headerMarker
+
     -- * Global header
-      globalHeader
+    , globalHeader
     , versionMajor
     , versionMinor
 
@@ -39,6 +42,10 @@
 
 import Data.ByteString (ByteString)
 import qualified Data.ByteString.Char8 as C
+import Data.Word
+
+headerMarker :: Word8
+headerMarker = 0xe5
 
 {- |
 
diff --git a/Data/ZoomCache/Multichannel/List.hs b/Data/ZoomCache/Multichannel/List.hs
--- a/Data/ZoomCache/Multichannel/List.hs
+++ b/Data/ZoomCache/Multichannel/List.hs
@@ -36,7 +36,6 @@
 
 import Control.Applicative ((<$>))
 import Control.Monad.Trans (MonadIO)
-import Data.ByteString (ByteString)
 import Data.Int
 import qualified Data.Iteratee as I
 import Data.Maybe
@@ -179,19 +178,17 @@
 
 -- | Read the summary of an entire track.
 wholeTrackSummaryListDouble :: (Functor m, MonadIO m)
-                            => [IdentifyCodec]
-                            -> TrackNo
-                            -> I.Iteratee ByteString m [Summary Double]
-wholeTrackSummaryListDouble identifiers trackNo =
-    I.joinI $ enumCacheFile identifiers .
-    I.joinI . filterTracks [trackNo] .  I.joinI . e $ I.last
+                            => TrackNo
+                            -> I.Iteratee [Block] m [Summary Double]
+wholeTrackSummaryListDouble trackNo =
+    I.joinI $ filterTracks [trackNo] .  I.joinI . e $ I.last
     where
         e = I.joinI . enumSummaries . I.mapChunks (catMaybes . map toSLD)
         toSLD :: ZoomSummary -> Maybe [Summary Double]
         toSLD (ZoomSummary s) = toSummaryListDouble s
 
 enumListDouble :: (Functor m, Monad m)
-               => I.Enumeratee [Stream] [(TimeStamp, [Double])] m a
+               => I.Enumeratee [Block] [(TimeStamp, [Double])] m a
 enumListDouble = I.joinI . enumPackets . I.mapChunks (concatMap f)
     where
         f :: Packet -> [(TimeStamp, [Double])]
@@ -199,7 +196,7 @@
 
 enumSummaryListDouble :: (Functor m, Monad m)
                       => Int
-                      -> I.Enumeratee [Stream] [[Summary Double]] m a
+                      -> I.Enumeratee [Block] [[Summary Double]] m a
 enumSummaryListDouble level =
     I.joinI . enumSummaryLevel level .
     I.mapChunks (catMaybes . map toSLD)
@@ -211,19 +208,17 @@
 
 -- | Read the summary of an entire track.
 wholeTrackSummaryUTCListDouble :: (Functor m, MonadIO m)
-                               => [IdentifyCodec]
-                               -> TrackNo
-                               -> I.Iteratee ByteString m [SummaryUTC Double]
-wholeTrackSummaryUTCListDouble identifiers trackNo =
-    I.joinI $ enumCacheFile identifiers .
-    I.joinI . filterTracks [trackNo] .  I.joinI . e $ I.last
+                               => TrackNo
+                               -> I.Iteratee [Block] m [SummaryUTC Double]
+wholeTrackSummaryUTCListDouble trackNo =
+    I.joinI $ filterTracks [trackNo] .  I.joinI . e $ I.last
     where
         e = I.joinI . enumSummariesUTC . I.mapChunks (catMaybes . map toSLD)
         toSLD :: ZoomSummaryUTC -> Maybe [SummaryUTC Double]
         toSLD (ZoomSummaryUTC s) = toSummaryUTCListDouble s
 
 enumUTCListDouble :: (Functor m, Monad m)
-                  => I.Enumeratee [Stream] [(UTCTime, [Double])] m a
+                  => I.Enumeratee [Block] [(UTCTime, [Double])] m a
 enumUTCListDouble = I.joinI . enumPacketsUTC . I.mapChunks (concatMap f)
     where
         f :: PacketUTC -> [(UTCTime, [Double])]
@@ -231,7 +226,7 @@
 
 enumSummaryUTCListDouble :: (Functor m, Monad m)
                          => Int
-                         -> I.Enumeratee [Stream] [[SummaryUTC Double]] m a
+                         -> I.Enumeratee [Block] [[SummaryUTC Double]] m a
 enumSummaryUTCListDouble level =
     I.joinI . enumSummaryUTCLevel level .
     I.mapChunks (catMaybes . map toSLD)
diff --git a/Data/ZoomCache/Numeric.hs b/Data/ZoomCache/Numeric.hs
--- a/Data/ZoomCache/Numeric.hs
+++ b/Data/ZoomCache/Numeric.hs
@@ -38,7 +38,6 @@
 
 import Control.Applicative ((<$>))
 import Control.Monad.Trans (MonadIO)
-import Data.ByteString (ByteString)
 import Data.Int
 import qualified Data.Iteratee as I
 import Data.Maybe
@@ -164,11 +163,10 @@
 
 -- | Read the summary of an entire track.
 wholeTrackSummaryDouble :: (Functor m, MonadIO m)
-                        => [IdentifyCodec]
-                        -> TrackNo
-                        -> I.Iteratee ByteString m (Summary Double)
-wholeTrackSummaryDouble identifiers trackNo = I.joinI $ enumCacheFile identifiers .
-    I.joinI . filterTracks [trackNo] .  I.joinI . e $ I.last
+                        => TrackNo
+                        -> I.Iteratee [Block] m (Summary Double)
+wholeTrackSummaryDouble trackNo =
+    I.joinI $ filterTracks [trackNo] .  I.joinI . e $ I.last
     where
         e = I.joinI . enumSummaries . I.mapChunks (catMaybes . map toSD)
         toSD :: ZoomSummary -> Maybe (Summary Double)
@@ -176,25 +174,24 @@
 
 -- | Read the summary of an entire track.
 wholeTrackSummaryUTCDouble :: (Functor m, MonadIO m)
-                           => [IdentifyCodec]
-                           -> TrackNo
-                           -> I.Iteratee ByteString m (SummaryUTC Double)
-wholeTrackSummaryUTCDouble identifiers trackNo = I.joinI $ enumCacheFile identifiers .
-    I.joinI . filterTracks [trackNo] .  I.joinI . e $ I.last
+                           => TrackNo
+                           -> I.Iteratee [Block] m (SummaryUTC Double)
+wholeTrackSummaryUTCDouble trackNo =
+    I.joinI $ filterTracks [trackNo] .  I.joinI . e $ I.last
     where
         e = I.joinI . enumSummariesUTC . I.mapChunks (catMaybes . map toSD)
         toSD :: ZoomSummaryUTC -> Maybe (SummaryUTC Double)
         toSD (ZoomSummaryUTC s) = toSummaryUTCDouble s
 
 enumDouble :: (Functor m, Monad m)
-           => I.Enumeratee [Stream] [(TimeStamp, Double)] m a
+           => I.Enumeratee [Block] [(TimeStamp, Double)] m a
 enumDouble = I.joinI . enumPackets . I.mapChunks (concatMap f)
     where
         f :: Packet -> [(TimeStamp, Double)]
         f Packet{..} = zip packetTimeStamps (rawToDouble packetData)
 
 enumUTCDouble :: (Functor m, Monad m)
-              => I.Enumeratee [Stream] [(UTCTime, Double)] m a
+              => I.Enumeratee [Block] [(UTCTime, Double)] m a
 enumUTCDouble = I.joinI . enumPacketsUTC . I.mapChunks (concatMap f)
     where
         f :: PacketUTC -> [(UTCTime, Double)]
@@ -202,7 +199,7 @@
 
 enumSummaryDouble :: (Functor m, Monad m)
                   => Int
-                  -> I.Enumeratee [Stream] [Summary Double] m a
+                  -> I.Enumeratee [Block] [Summary Double] m a
 enumSummaryDouble level =
     I.joinI . enumSummaryLevel level .
     I.mapChunks (catMaybes . map toSD)
@@ -212,7 +209,7 @@
 
 enumSummaryUTCDouble :: (Functor m, Monad m)
                      => Int
-                     -> I.Enumeratee [Stream] [SummaryUTC Double] m a
+                     -> I.Enumeratee [Block] [SummaryUTC Double] m a
 enumSummaryUTCDouble level =
     I.joinI . enumSummaryUTCLevel level .
     I.mapChunks (catMaybes . map toSD)
diff --git a/zoom-cache.cabal b/zoom-cache.cabal
--- a/zoom-cache.cabal
+++ b/zoom-cache.cabal
@@ -3,7 +3,7 @@
 -- The package version. See the Haskell package versioning policy
 -- (http://www.haskell.org/haskellwiki/Package_versioning_policy) for
 -- standards guiding when and how versions should be incremented.
-Version:             1.0.0.0
+Version:             1.1.0.0
 
 Synopsis:            A streamable, seekable, zoomable cache file format
 
@@ -95,6 +95,7 @@
   Exposed-modules:
     Blaze.ByteString.Builder.ZoomCache
     Data.Iteratee.ZoomCache
+    Data.Iteratee.ZoomCache.Seek
     Data.Iteratee.ZoomCache.Utils
     Data.ZoomCache
     Data.ZoomCache.Bool
