{- | Parser which handles the running state that is used in MIDI messages in realtime and files. The running state consists of a message code and the message channel. -} module Sound.MIDI.Parser.Status (T, Status, set, get, run, State.lift, Channel, fromChannel, toChannel, ) where import qualified Sound.MIDI.Parser.State as ParserState import Control.Monad.State (evalStateT, ) import qualified Control.Monad.State as State import Sound.MIDI.Utility (checkRange, ) import Data.Ix (Ix) {- | The 'T' monad parses a track of a MIDI File. In MIDI, a shortcut is used for long strings of similar MIDI events: If a stream of consecutive events all have the same type and channel, the type and channel can be omitted for all but the first event. To implement this /feature/, the parser must keep track of the type and channel of the most recent MIDI Event. This is done by managing a 'Status' in the parser. -} type T parser a = ParserState.T Status parser a type Status = Maybe (Int,Channel) set :: Monad parser => Status -> T parser () set = State.put get :: Monad parser => T parser Status get = State.get run :: Monad parser => T parser a -> parser a run = flip evalStateT Nothing -- * Channel definition {- | This definition should be in Message.Channel, but this results in a cyclic import. -} newtype Channel = Channel {fromChannel :: Int} deriving (Show, Eq, Ord, Ix) toChannel :: Int -> Channel toChannel = checkRange "Channel" Channel instance Enum Channel where toEnum = toChannel fromEnum = fromChannel instance Bounded Channel where minBound = Channel 0 maxBound = Channel 15