{-# language ScopedTypeVariables #-}
{-# language RecordWildCards #-}
module Codec.EDF.Raw where
import Data.ByteString.Lazy as BL
import Data.ByteString.Internal as BI
import Data.Binary.Get
import Data.Text as T
import Data.Text.Encoding
import Data.Text.Encoding.Error
import Data.Monoid
import Control.Monad
import Control.Exception
data Header = Header {
version :: Text
, patient :: Text
, numBytes :: Integer
, numRecords :: Integer
, durationSec :: Integer
, numSignals :: Integer
, labels :: [Text]
, transducerType :: [Text]
, dimensions :: [Text]
, physicalMin :: [Integer]
, physicalMax :: [Integer]
, digitalMin :: [Integer]
, digitalMax :: [Integer]
, prefiltering :: [Text]
, numSamples :: [Integer]
} deriving (Show)
getHeader :: Get (Header)
getHeader = do
version <- utf8 8
patient <- utf8 80
recordingId <- getByteString 80
startDate <- getByteString 8
startTime <- getByteString 8
numBytes <- int 8
reserved1 <- getByteString 44
numRecords <- int 8
durationSec <- int 8
numSignals <- int 4
labels <- utf8s numSignals 16
transducerType <- utf8s numSignals 80
dimensions <- utf8s numSignals 8
physicalMin <- ints numSignals 8
physicalMax <- ints numSignals 8
digitalMin <- ints numSignals 8
digitalMax <- ints numSignals 8
prefiltering <- utf8s numSignals 80
numSamples <- ints numSignals 8
reserved2 <- skips numSignals 32
return $ Header {..}
where
utf8 width = decodeUtf8 <$> getByteString width
utf8s n width = replicateM (fromInteger n) $ decodeUtf8 <$> getByteString width
bs2i :: BI.ByteString -> Integer
bs2i = read . T.unpack . decodeUtf8
int width = bs2i <$> getByteString width
ints n width = replicateM (fromInteger n) $ bs2i <$> getByteString width
skip width = getByteString width
skips n width = replicateM (fromInteger n) $ getByteString width
type Samples = [Integer]
type Signals = [Samples]
type Records = [Signals]
getSamples :: (Integral nSamples) => nSamples -> Get Samples
getSamples n = replicateM (fromIntegral n) (getInt16le >>= return . fromIntegral)
getRecords :: Get Records
getRecords = do
h <- getHeader
s <- replicateM (fromIntegral $ numRecords h) $ numSamples h `forM` \n -> getSamples n
return s
getRecordsFromFile :: FilePath -> IO Records
getRecordsFromFile fn = do
f <- BL.readFile fn
return $ runGet getRecords f
getHeaderFromFile :: FilePath -> IO Header
getHeaderFromFile f = do
f <- BL.readFile f
return $ runGet getHeader f