module Sound.MED.Basic.Amiga where
import qualified System.IO as IO
import qualified Foreign.Marshal.Alloc as Alloc
import Foreign.Storable (Storable, peekByteOff)
import Foreign.Ptr (Ptr)
import Control.Monad (when)
import Control.Applicative ((<$>))
import qualified Data.List.Reverse.StrictSpine as ListRev
import Data.List.HT (sliceVertical)
import Data.Storable.Endian (HasBigEndian, getBigEndian)
import Data.Word (Word8, Word16, Word32)
import Data.Int (Int8, Int16, Int32)
type MEM = Ptr ()
type PTR = Word32
type LONG = Int32
type ULONG = Word32
type WORD = Int16
type UWORD = Word16
type BYTE = Int8
type UBYTE = Word8
type Peek a = MEM -> PTR -> IO a
peekOffset :: (Storable a) => Peek a
peekOffset mem ptr = peekByteOff mem (fromIntegral ptr)
peekBig :: (Storable a, HasBigEndian a) => Peek a
peekBig mem ptr = getBigEndian <$> peekOffset mem ptr
peekPTR :: Peek PTR ; peekPTR = peekBig
peekLONG :: Peek LONG ; peekLONG = peekBig
peekULONG :: Peek ULONG ; peekULONG = peekBig
peekWORD :: Peek WORD ; peekWORD = peekBig
peekUWORD :: Peek UWORD ; peekUWORD = peekBig
peekBYTE :: Peek BYTE ; peekBYTE = peekOffset
peekUBYTE :: Peek UBYTE ; peekUBYTE = peekOffset
infixr 0 $?
($?) :: (PTR -> IO a) -> PTR -> IO (Maybe a)
f $? ptr = skipIf (ptr == 0) (f ptr)
skipIf :: Bool -> IO a -> IO (Maybe a)
skipIf cond act =
if cond
then return Nothing
else Just <$> act
loadMEM :: String -> IO MEM
loadMEM s =
IO.withBinaryFile s IO.ReadMode $ \h -> do
size <- fromInteger <$> IO.hFileSize h
ptr <- Alloc.mallocBytes size
readSize <- IO.hGetBuf h ptr size
when (readSize<size) $
ioError $ userError $ "loadMEM: incomplete load of " ++ s
return ptr
freeMEM :: MEM -> IO ()
freeMEM = Alloc.free
pointerRange :: PTR -> ULONG -> Int -> [PTR]
pointerRange start step len =
take len $ iterate (fromIntegral step +) start
pointerRangeGen :: (Integral i) => PTR -> ULONG -> i -> [PTR]
pointerRangeGen start step len = pointerRange start step (fromIntegral len)
pointerRangeGenCheck :: (Integral i) => PTR -> ULONG -> i -> [PTR]
pointerRangeGenCheck start step len =
if start == 0 then [] else pointerRangeGen start step len
pointerRangeGen2 :: (Integral i, Integral j) => PTR -> ULONG -> i -> j -> [PTR]
pointerRangeGen2 start step len0 len1 =
pointerRange start step (fromIntegral len0 * fromIntegral len1)
chunk :: (Integral i) => i -> [a] -> [[a]]
chunk k = sliceVertical (fromIntegral k)
stringFromBytes :: [UBYTE] -> String
stringFromBytes = map (toEnum . fromEnum) . ListRev.dropWhile (==0)