{- |
Functions for reading and writing data
using the endianess of the machine.
This is the way Sox handles raw data.
This module is more or less provided for completeness,
since it is based on lists,
which means that it is too slow
to process real world data.
For serious applications use Data.StorableVector.Lazy.
-}
module Sound.Sox.Signal.List (
   writeFile, put,
   withReadFile, getContents,
   ReadException, IOReadException,
   ) where

import qualified Control.Monad.Exception.Synchronous as Sync
import qualified Control.Monad.Exception.Asynchronous as Async

import Control.Monad.Trans.Class (lift, )

import Foreign.Storable (Storable (..), )

import Foreign (Ptr, alloca, )
import System.IO (withBinaryFile, IOMode(WriteMode,ReadMode), Handle, hPutBuf, hGetBuf, )
import Control.Exception.Extensible (SomeException, try, )
import Control.Monad (liftM)

import System.IO.Unsafe (unsafeInterleaveIO, )

import Prelude hiding (writeFile, readFile, getContents, )


writeFile :: Storable a => FilePath -> [a] -> IO ()
writeFile :: forall a. Storable a => FilePath -> [a] -> IO ()
writeFile FilePath
fileName [a]
signal =
   forall r. FilePath -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile FilePath
fileName IOMode
WriteMode (forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a. Storable a => Handle -> [a] -> IO ()
put [a]
signal)

put :: Storable a => Handle -> [a] -> IO ()
put :: forall a. Storable a => Handle -> [a] -> IO ()
put Handle
h [a]
signal =
   forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$
      \Ptr a
p -> forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (forall a. Storable a => Handle -> Ptr a -> a -> IO ()
putFrame Handle
h Ptr a
p) [a]
signal

putFrame :: Storable a => Handle -> Ptr a -> a -> IO ()
putFrame :: forall a. Storable a => Handle -> Ptr a -> a -> IO ()
putFrame Handle
h Ptr a
p a
n =
   forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr a
p a
n forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall a. Handle -> Ptr a -> Int -> IO ()
hPutBuf Handle
h Ptr a
p (forall a. Storable a => a -> Int
sizeOf a
n)



data ReadException =
   BrokenFrame
  deriving (Int -> ReadException -> ShowS
[ReadException] -> ShowS
ReadException -> FilePath
forall a.
(Int -> a -> ShowS) -> (a -> FilePath) -> ([a] -> ShowS) -> Show a
showList :: [ReadException] -> ShowS
$cshowList :: [ReadException] -> ShowS
show :: ReadException -> FilePath
$cshow :: ReadException -> FilePath
showsPrec :: Int -> ReadException -> ShowS
$cshowsPrec :: Int -> ReadException -> ShowS
Show, ReadException -> ReadException -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ReadException -> ReadException -> Bool
$c/= :: ReadException -> ReadException -> Bool
== :: ReadException -> ReadException -> Bool
$c== :: ReadException -> ReadException -> Bool
Eq, Int -> ReadException
ReadException -> Int
ReadException -> [ReadException]
ReadException -> ReadException
ReadException -> ReadException -> [ReadException]
ReadException -> ReadException -> ReadException -> [ReadException]
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: ReadException -> ReadException -> ReadException -> [ReadException]
$cenumFromThenTo :: ReadException -> ReadException -> ReadException -> [ReadException]
enumFromTo :: ReadException -> ReadException -> [ReadException]
$cenumFromTo :: ReadException -> ReadException -> [ReadException]
enumFromThen :: ReadException -> ReadException -> [ReadException]
$cenumFromThen :: ReadException -> ReadException -> [ReadException]
enumFrom :: ReadException -> [ReadException]
$cenumFrom :: ReadException -> [ReadException]
fromEnum :: ReadException -> Int
$cfromEnum :: ReadException -> Int
toEnum :: Int -> ReadException
$ctoEnum :: Int -> ReadException
pred :: ReadException -> ReadException
$cpred :: ReadException -> ReadException
succ :: ReadException -> ReadException
$csucc :: ReadException -> ReadException
Enum)

type IOReadException =
   Either ReadException SomeException

withReadFile :: Storable a =>
   FilePath ->
   (Async.Exceptional IOReadException [a] -> IO b) ->
   IO b
withReadFile :: forall a b.
Storable a =>
FilePath -> (Exceptional IOReadException [a] -> IO b) -> IO b
withReadFile FilePath
fileName Exceptional IOReadException [a] -> IO b
act =
   forall r. FilePath -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile FilePath
fileName IOMode
ReadMode forall a b. (a -> b) -> a -> b
$ \Handle
sig ->
      forall a.
Storable a =>
Handle -> IO (Exceptional IOReadException [a])
getContents Handle
sig forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Exceptional IOReadException [a] -> IO b
act

getContents :: Storable a =>
   Handle -> IO (Async.Exceptional IOReadException [a])
getContents :: forall a.
Storable a =>
Handle -> IO (Exceptional IOReadException [a])
getContents Handle
h =
   forall a b. Storable a => (Ptr a -> IO b) -> IO b
alloca forall a b. (a -> b) -> a -> b
$
      \Ptr a
p ->
--         Async.eatNothingT $
         forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM (\(Async.Exceptional (Just Maybe IOReadException
e) [a]
a) -> forall e a. Maybe e -> a -> Exceptional e a
Async.Exceptional Maybe IOReadException
e [a]
a) forall a b. (a -> b) -> a -> b
$
         forall (m :: * -> *) e b a.
Monad m =>
(m (Exceptional e b) -> m (Exceptional e b))
-> (a -> b -> b) -> b -> ExceptionalT e m a -> m (Exceptional e b)
Async.manySynchronousT
            forall a. IO a -> IO a
unsafeInterleaveIO
            (:) [] (forall a.
Storable a =>
Handle -> Ptr a -> ExceptionalT (Maybe IOReadException) IO a
getFrame Handle
h Ptr a
p)

getFrame :: Storable a =>
   Handle -> Ptr a ->
   Sync.ExceptionalT (Maybe IOReadException) IO a
getFrame :: forall a.
Storable a =>
Handle -> Ptr a -> ExceptionalT (Maybe IOReadException) IO a
getFrame Handle
h Ptr a
p =
   do let getSize :: Storable a => a -> Ptr a -> Int
          getSize :: forall a. Storable a => a -> Ptr a -> Int
getSize a
dummy Ptr a
_ = forall a. Storable a => a -> Int
sizeOf a
dummy
          size :: Int
size = forall a. Storable a => a -> Ptr a -> Int
getSize forall a. HasCallStack => a
undefined Ptr a
p
      Int
cnt <-
         forall (m :: * -> *) e0 e1 a.
Monad m =>
(e0 -> e1) -> ExceptionalT e0 m a -> ExceptionalT e1 m a
Sync.mapExceptionT (forall a. a -> Maybe a
Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. b -> Either a b
Right) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) e a.
Monad m =>
m (Either e a) -> ExceptionalT e m a
Sync.fromEitherT forall a b. (a -> b) -> a -> b
$
         forall e a. Exception e => IO a -> IO (Either e a)
try forall a b. (a -> b) -> a -> b
$ forall a. Handle -> Ptr a -> Int -> IO Int
hGetBuf Handle
h Ptr a
p Int
size
      forall (m :: * -> *) e. Monad m => e -> Bool -> ExceptionalT e m ()
Sync.assertT forall a. Maybe a
Nothing (Int
cnt forall a. Ord a => a -> a -> Bool
> Int
0)
      forall (m :: * -> *) e. Monad m => e -> Bool -> ExceptionalT e m ()
Sync.assertT (forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall a b. a -> Either a b
Left ReadException
BrokenFrame) (Int
cnt forall a. Eq a => a -> a -> Bool
== Int
size)
      forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall a b. (a -> b) -> a -> b
$ forall a. Storable a => Ptr a -> IO a
peek Ptr a
p