module Sound.MIDI.File.Event (
T(..), get, put,
TrackEvent, getTrackEvent,
ElapsedTime, fromElapsedTime, toElapsedTime,
mapBody, maybeMIDIEvent, maybeMetaEvent, maybeVoice, mapVoice,
) where
import qualified Sound.MIDI.Message.Channel as ChannelMsg
import qualified Sound.MIDI.Message.Channel.Voice as Voice
import qualified Sound.MIDI.File.Event.SystemExclusive as SysEx
import qualified Sound.MIDI.File.Event.Meta as MetaEvent
import Sound.MIDI.Message.Channel (Channel)
import Sound.MIDI.File.Event.Meta (
ElapsedTime, fromElapsedTime, toElapsedTime,
)
import Sound.MIDI.Parser.Primitive
import qualified Sound.MIDI.Parser.Status as StatusParser
import qualified Sound.MIDI.Parser.Class as Parser
import Control.Monad (liftM, liftM2, )
import qualified Sound.MIDI.Writer.Status as StatusWriter
import qualified Sound.MIDI.Writer.Basic as Writer
import Sound.MIDI.Monoid ((+#+))
import Data.Tuple.HT (mapSnd)
import Test.QuickCheck (Arbitrary(arbitrary), )
import qualified Test.QuickCheck as QC
type TrackEvent = (ElapsedTime, T)
mapBody :: (T -> T) -> (TrackEvent -> TrackEvent)
mapBody = mapSnd
data T =
MIDIEvent ChannelMsg.T
| MetaEvent MetaEvent.T
| SystemExclusive SysEx.T
deriving (Show,Eq,Ord)
instance Arbitrary T where
arbitrary =
QC.frequency $
(100, liftM MIDIEvent arbitrary) :
( 1, liftM MetaEvent arbitrary) :
[]
maybeMIDIEvent :: T -> Maybe ChannelMsg.T
maybeMIDIEvent (MIDIEvent msg) = Just msg
maybeMIDIEvent _ = Nothing
maybeMetaEvent :: T -> Maybe MetaEvent.T
maybeMetaEvent (MetaEvent mev) = Just mev
maybeMetaEvent _ = Nothing
maybeVoice :: T -> Maybe (Channel, Voice.T)
maybeVoice (MIDIEvent (ChannelMsg.Cons ch (ChannelMsg.Voice ev))) = Just (ch,ev)
maybeVoice _ = Nothing
mapVoice :: (Voice.T -> Voice.T) -> T -> T
mapVoice f (MIDIEvent (ChannelMsg.Cons ch (ChannelMsg.Voice ev))) =
MIDIEvent (ChannelMsg.Cons ch (ChannelMsg.Voice (f ev)))
mapVoice _ msg = msg
get :: Parser.C parser => Parser.Fragile (StatusParser.T parser) T
get =
StatusParser.lift get1 >>= \tag ->
if tag < 0xF0
then liftM MIDIEvent $ ChannelMsg.getWithStatus tag
else
StatusParser.set Nothing >>
(StatusParser.lift $
if tag == 0xFF
then liftM MetaEvent $ MetaEvent.get
else liftM SystemExclusive $ SysEx.get tag)
getTrackEvent :: Parser.C parser => Parser.Fragile (StatusParser.T parser) TrackEvent
getTrackEvent = liftM2 (,) (StatusParser.lift getVar) get
put ::
(StatusWriter.Compression compress, Writer.C writer) =>
T -> StatusWriter.T compress writer
put e =
case e of
MIDIEvent m -> ChannelMsg.putWithStatus m
MetaEvent m -> StatusWriter.clear +#+ StatusWriter.lift (MetaEvent.put m)
SystemExclusive m -> StatusWriter.clear +#+ StatusWriter.lift (SysEx.put m)