midi-0.2.2.6: src/Sound/MIDI/Message/Class/Query.hs
module Sound.MIDI.Message.Class.Query (
C(..),
noteExplicitOff,
noteImplicitOff,
liftMidi,
liftFile,
) where
import qualified Sound.MIDI.Message.Class.Utility as CU
import Sound.MIDI.Message.Channel (Channel, )
import Sound.MIDI.Message.Channel.Voice (Pitch, Velocity, Program, Controller, )
import qualified Sound.MIDI.File.Event as FileEvent
import qualified Sound.MIDI.Message as MidiMsg
import qualified Sound.MIDI.Message.Channel as ChannelMsg
import qualified Sound.MIDI.Message.Channel.Mode as Mode
import Data.Tuple.HT (mapSnd, )
{- |
All methods have default implementations that return 'Nothing'.
This helps implementing event data types
that support only a subset of types of events.
Maybe a better approach is to provide type classes
for every type of event
and make 'C' a subclass of all of them.
-}
class C event where
{- |
Warning: This returns note events as they are,
that is, a @NoteOff p 64@ might be encoded as such or as @NoteOn p 0@
depending on the content of @event@.
For normalized results you may use 'noteExplicitOff'.
-}
note :: event -> Maybe (Channel, (Velocity, Pitch, Bool))
program :: event -> Maybe (Channel, Program)
anyController :: event -> Maybe (Channel, (Controller, Int))
pitchBend :: event -> Maybe (Channel, Int)
channelPressure :: event -> Maybe (Channel, Int)
mode :: event -> Maybe (Channel, Mode.T)
note _ev = Nothing
program _ev = Nothing
anyController _ev = Nothing
pitchBend _ev = Nothing
channelPressure _ev = Nothing
mode _ev = Nothing
lift ::
(Maybe ChannelMsg.Body -> Maybe a) ->
ChannelMsg.T -> Maybe (Channel, a)
lift act msg =
fmap ((,) (ChannelMsg.messageChannel msg)) $
act $ Just $ ChannelMsg.messageBody msg
instance C ChannelMsg.T where
note = lift CU.note
program = lift CU.program
anyController = lift CU.anyController
pitchBend = lift CU.pitchBend
channelPressure = lift CU.channelPressure
mode = lift CU.mode
{- |
Like 'note', but converts @NoteOn p 0@ to @NoteOff p 64@.
See 'VoiceMsg.explicitNoteOff'.
-}
noteExplicitOff ::
(C event) =>
event -> Maybe (Channel, (Velocity, Pitch, Bool))
noteExplicitOff e =
fmap (mapSnd CU.explicitNoteOff) $ note e
{- |
Like 'note', but converts @NoteOff p 64@ to @NoteOn p 0@.
See 'VoiceMsg.implicitNoteOff'.
-}
noteImplicitOff ::
(C event) =>
event -> Maybe (Channel, (Velocity, Pitch, Bool))
noteImplicitOff e =
fmap (mapSnd CU.implicitNoteOff) $ note e
liftMidi ::
(ChannelMsg.T -> Maybe (Channel, a)) ->
(MidiMsg.T -> Maybe (Channel, a))
liftMidi checkMsg msg =
case msg of
MidiMsg.Channel chanMsg -> checkMsg chanMsg
_ -> Nothing
instance C MidiMsg.T where
note = liftMidi note
program = liftMidi program
anyController = liftMidi anyController
pitchBend = liftMidi pitchBend
channelPressure = liftMidi channelPressure
mode = liftMidi mode
liftFile ::
(ChannelMsg.T -> Maybe (Channel, a)) ->
(FileEvent.T -> Maybe (Channel, a))
liftFile checkMsg msg =
case msg of
FileEvent.MIDIEvent midiMsg -> checkMsg midiMsg
_ -> Nothing
instance C FileEvent.T where
note = liftFile note
program = liftFile program
anyController = liftFile anyController
pitchBend = liftFile pitchBend
channelPressure = liftFile channelPressure
mode = liftFile mode