module Sound.MIDI.Parser.Primitive
(getByte,
getN, getString, getBigN, getNByteInt,
get1, get2, get3, get4,
getNByteCardinal,
getVar, getVarBytes,
getEnum, makeEnum, ) where
import qualified Sound.MIDI.Parser.Class as Parser
import Control.Monad (replicateM, liftM, )
import Sound.MIDI.IO (ByteList, listCharFromByte, )
import qualified Sound.MIDI.Bit as Bit
import Data.Bits (testBit, clearBit)
import Data.Word (Word8)
import qualified Numeric.NonNegative.Wrapper as NonNeg
getByte :: Parser.C parser => Parser.Fallible parser Word8
getByte = Parser.getByte
getN :: Parser.C parser => NonNeg.Int -> Parser.Fallible parser ByteList
getN n = replicateM (NonNeg.toNumber n) getByte
getString :: Parser.C parser => NonNeg.Integer -> Parser.Fallible parser String
getString n = liftM listCharFromByte (getBigN n)
getBigN :: Parser.C parser => NonNeg.Integer -> Parser.Fallible parser ByteList
getBigN n =
sequence $
Bit.replicateBig
(1 + fromIntegral (maxBound :: NonNeg.Int))
(NonNeg.toNumber n)
getByte
get1 :: Parser.C parser => Parser.Fallible parser Int
get1 = liftM fromIntegral getByte
getNByteInt :: Parser.C parser => NonNeg.Int -> Parser.Fallible parser Int
getNByteInt n =
liftM Bit.fromBytes (replicateM (NonNeg.toNumber n) get1)
get2, get3, get4 :: Parser.C parser => Parser.Fallible parser Int
get2 = getNByteInt 2
get3 = getNByteInt 3
get4 = getNByteInt 4
getByteAsCardinal :: Parser.C parser => Parser.Fallible parser NonNeg.Integer
getByteAsCardinal = liftM fromIntegral getByte
getNByteCardinal :: Parser.C parser => NonNeg.Int -> Parser.Fallible parser NonNeg.Integer
getNByteCardinal n =
liftM Bit.fromBytes (replicateM (NonNeg.toNumber n) getByteAsCardinal)
getVar :: Parser.C parser => Parser.Fallible parser NonNeg.Integer
getVar =
liftM (Bit.fromBase (2^(7::Int)) . map fromIntegral) getVarBytes
getVarBytes :: Parser.C parser => Parser.Fallible parser [Word8]
getVarBytes =
do
digit <- getByte
if flip testBit 7 digit
then liftM (flip clearBit 7 digit :) getVarBytes
else return [digit]
getEnum :: (Parser.C parser, Enum enum, Bounded enum) => Parser.Fallible parser enum
getEnum = makeEnum =<< get1
makeEnum :: (Parser.C parser, Enum enum, Bounded enum) => Int -> Parser.Fallible parser enum
makeEnum n =
let go :: (Parser.C parser, Enum a) => a -> a -> Parser.Fallible parser a
go lower upper =
if fromEnum lower <= n && n <= fromEnum upper
then return (toEnum n)
else Parser.giveUp ("value " ++ show n ++ " is out of range for enumeration")
in go minBound maxBound