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 event
_ev = Maybe (Channel, (Velocity, Pitch, Bool))
forall a. Maybe a
Nothing
   program event
_ev = Maybe (Channel, Program)
forall a. Maybe a
Nothing
   anyController event
_ev = Maybe (Channel, (Controller, Int))
forall a. Maybe a
Nothing
   pitchBend event
_ev = Maybe (Channel, Int)
forall a. Maybe a
Nothing
   channelPressure event
_ev = Maybe (Channel, Int)
forall a. Maybe a
Nothing
   mode event
_ev = Maybe (Channel, T)
forall a. Maybe a
Nothing


lift ::
   (Maybe ChannelMsg.Body -> Maybe a) ->
   ChannelMsg.T -> Maybe (Channel, a)
lift :: (Maybe Body -> Maybe a) -> T -> Maybe (Channel, a)
lift Maybe Body -> Maybe a
act T
msg =
   (a -> (Channel, a)) -> Maybe a -> Maybe (Channel, a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((,) (T -> Channel
ChannelMsg.messageChannel T
msg)) (Maybe a -> Maybe (Channel, a)) -> Maybe a -> Maybe (Channel, a)
forall a b. (a -> b) -> a -> b
$
   Maybe Body -> Maybe a
act (Maybe Body -> Maybe a) -> Maybe Body -> Maybe a
forall a b. (a -> b) -> a -> b
$ Body -> Maybe Body
forall a. a -> Maybe a
Just (Body -> Maybe Body) -> Body -> Maybe Body
forall a b. (a -> b) -> a -> b
$ T -> Body
ChannelMsg.messageBody T
msg

instance C ChannelMsg.T where
   note :: T -> Maybe (Channel, (Velocity, Pitch, Bool))
note = (Maybe Body -> Maybe (Velocity, Pitch, Bool))
-> T -> Maybe (Channel, (Velocity, Pitch, Bool))
forall a. (Maybe Body -> Maybe a) -> T -> Maybe (Channel, a)
lift Maybe Body -> Maybe (Velocity, Pitch, Bool)
CU.note
   program :: T -> Maybe (Channel, Program)
program = (Maybe Body -> Maybe Program) -> T -> Maybe (Channel, Program)
forall a. (Maybe Body -> Maybe a) -> T -> Maybe (Channel, a)
lift Maybe Body -> Maybe Program
CU.program
   anyController :: T -> Maybe (Channel, (Controller, Int))
anyController = (Maybe Body -> Maybe (Controller, Int))
-> T -> Maybe (Channel, (Controller, Int))
forall a. (Maybe Body -> Maybe a) -> T -> Maybe (Channel, a)
lift Maybe Body -> Maybe (Controller, Int)
CU.anyController
   pitchBend :: T -> Maybe (Channel, Int)
pitchBend = (Maybe Body -> Maybe Int) -> T -> Maybe (Channel, Int)
forall a. (Maybe Body -> Maybe a) -> T -> Maybe (Channel, a)
lift Maybe Body -> Maybe Int
CU.pitchBend
   channelPressure :: T -> Maybe (Channel, Int)
channelPressure = (Maybe Body -> Maybe Int) -> T -> Maybe (Channel, Int)
forall a. (Maybe Body -> Maybe a) -> T -> Maybe (Channel, a)
lift Maybe Body -> Maybe Int
CU.channelPressure
   mode :: T -> Maybe (Channel, T)
mode = (Maybe Body -> Maybe T) -> T -> Maybe (Channel, T)
forall a. (Maybe Body -> Maybe a) -> T -> Maybe (Channel, a)
lift Maybe Body -> Maybe T
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 :: event -> Maybe (Channel, (Velocity, Pitch, Bool))
noteExplicitOff event
e =
   ((Channel, (Velocity, Pitch, Bool))
 -> (Channel, (Velocity, Pitch, Bool)))
-> Maybe (Channel, (Velocity, Pitch, Bool))
-> Maybe (Channel, (Velocity, Pitch, Bool))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (((Velocity, Pitch, Bool) -> (Velocity, Pitch, Bool))
-> (Channel, (Velocity, Pitch, Bool))
-> (Channel, (Velocity, Pitch, Bool))
forall b c a. (b -> c) -> (a, b) -> (a, c)
mapSnd (Velocity, Pitch, Bool) -> (Velocity, Pitch, Bool)
CU.explicitNoteOff) (Maybe (Channel, (Velocity, Pitch, Bool))
 -> Maybe (Channel, (Velocity, Pitch, Bool)))
-> Maybe (Channel, (Velocity, Pitch, Bool))
-> Maybe (Channel, (Velocity, Pitch, Bool))
forall a b. (a -> b) -> a -> b
$ event -> Maybe (Channel, (Velocity, Pitch, Bool))
forall event.
C event =>
event -> Maybe (Channel, (Velocity, Pitch, Bool))
note event
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 :: event -> Maybe (Channel, (Velocity, Pitch, Bool))
noteImplicitOff event
e =
   ((Channel, (Velocity, Pitch, Bool))
 -> (Channel, (Velocity, Pitch, Bool)))
-> Maybe (Channel, (Velocity, Pitch, Bool))
-> Maybe (Channel, (Velocity, Pitch, Bool))
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (((Velocity, Pitch, Bool) -> (Velocity, Pitch, Bool))
-> (Channel, (Velocity, Pitch, Bool))
-> (Channel, (Velocity, Pitch, Bool))
forall b c a. (b -> c) -> (a, b) -> (a, c)
mapSnd (Velocity, Pitch, Bool) -> (Velocity, Pitch, Bool)
CU.implicitNoteOff) (Maybe (Channel, (Velocity, Pitch, Bool))
 -> Maybe (Channel, (Velocity, Pitch, Bool)))
-> Maybe (Channel, (Velocity, Pitch, Bool))
-> Maybe (Channel, (Velocity, Pitch, Bool))
forall a b. (a -> b) -> a -> b
$ event -> Maybe (Channel, (Velocity, Pitch, Bool))
forall event.
C event =>
event -> Maybe (Channel, (Velocity, Pitch, Bool))
note event
e


liftMidi ::
   (ChannelMsg.T -> Maybe (Channel, a)) ->
   (MidiMsg.T -> Maybe (Channel, a))
liftMidi :: (T -> Maybe (Channel, a)) -> T -> Maybe (Channel, a)
liftMidi T -> Maybe (Channel, a)
checkMsg T
msg =
   case T
msg of
      MidiMsg.Channel T
chanMsg -> T -> Maybe (Channel, a)
checkMsg T
chanMsg
      T
_ -> Maybe (Channel, a)
forall a. Maybe a
Nothing

instance C MidiMsg.T where
   note :: T -> Maybe (Channel, (Velocity, Pitch, Bool))
note = (T -> Maybe (Channel, (Velocity, Pitch, Bool)))
-> T -> Maybe (Channel, (Velocity, Pitch, Bool))
forall a. (T -> Maybe (Channel, a)) -> T -> Maybe (Channel, a)
liftMidi T -> Maybe (Channel, (Velocity, Pitch, Bool))
forall event.
C event =>
event -> Maybe (Channel, (Velocity, Pitch, Bool))
note
   program :: T -> Maybe (Channel, Program)
program = (T -> Maybe (Channel, Program)) -> T -> Maybe (Channel, Program)
forall a. (T -> Maybe (Channel, a)) -> T -> Maybe (Channel, a)
liftMidi T -> Maybe (Channel, Program)
forall event. C event => event -> Maybe (Channel, Program)
program
   anyController :: T -> Maybe (Channel, (Controller, Int))
anyController = (T -> Maybe (Channel, (Controller, Int)))
-> T -> Maybe (Channel, (Controller, Int))
forall a. (T -> Maybe (Channel, a)) -> T -> Maybe (Channel, a)
liftMidi T -> Maybe (Channel, (Controller, Int))
forall event.
C event =>
event -> Maybe (Channel, (Controller, Int))
anyController
   pitchBend :: T -> Maybe (Channel, Int)
pitchBend = (T -> Maybe (Channel, Int)) -> T -> Maybe (Channel, Int)
forall a. (T -> Maybe (Channel, a)) -> T -> Maybe (Channel, a)
liftMidi T -> Maybe (Channel, Int)
forall event. C event => event -> Maybe (Channel, Int)
pitchBend
   channelPressure :: T -> Maybe (Channel, Int)
channelPressure = (T -> Maybe (Channel, Int)) -> T -> Maybe (Channel, Int)
forall a. (T -> Maybe (Channel, a)) -> T -> Maybe (Channel, a)
liftMidi T -> Maybe (Channel, Int)
forall event. C event => event -> Maybe (Channel, Int)
channelPressure
   mode :: T -> Maybe (Channel, T)
mode = (T -> Maybe (Channel, T)) -> T -> Maybe (Channel, T)
forall a. (T -> Maybe (Channel, a)) -> T -> Maybe (Channel, a)
liftMidi T -> Maybe (Channel, T)
forall event. C event => event -> Maybe (Channel, T)
mode


liftFile ::
   (ChannelMsg.T -> Maybe (Channel, a)) ->
   (FileEvent.T -> Maybe (Channel, a))
liftFile :: (T -> Maybe (Channel, a)) -> T -> Maybe (Channel, a)
liftFile T -> Maybe (Channel, a)
checkMsg T
msg =
   case T
msg of
      FileEvent.MIDIEvent T
midiMsg -> T -> Maybe (Channel, a)
checkMsg T
midiMsg
      T
_ -> Maybe (Channel, a)
forall a. Maybe a
Nothing

instance C FileEvent.T where
   note :: T -> Maybe (Channel, (Velocity, Pitch, Bool))
note = (T -> Maybe (Channel, (Velocity, Pitch, Bool)))
-> T -> Maybe (Channel, (Velocity, Pitch, Bool))
forall a. (T -> Maybe (Channel, a)) -> T -> Maybe (Channel, a)
liftFile T -> Maybe (Channel, (Velocity, Pitch, Bool))
forall event.
C event =>
event -> Maybe (Channel, (Velocity, Pitch, Bool))
note
   program :: T -> Maybe (Channel, Program)
program = (T -> Maybe (Channel, Program)) -> T -> Maybe (Channel, Program)
forall a. (T -> Maybe (Channel, a)) -> T -> Maybe (Channel, a)
liftFile T -> Maybe (Channel, Program)
forall event. C event => event -> Maybe (Channel, Program)
program
   anyController :: T -> Maybe (Channel, (Controller, Int))
anyController = (T -> Maybe (Channel, (Controller, Int)))
-> T -> Maybe (Channel, (Controller, Int))
forall a. (T -> Maybe (Channel, a)) -> T -> Maybe (Channel, a)
liftFile T -> Maybe (Channel, (Controller, Int))
forall event.
C event =>
event -> Maybe (Channel, (Controller, Int))
anyController
   pitchBend :: T -> Maybe (Channel, Int)
pitchBend = (T -> Maybe (Channel, Int)) -> T -> Maybe (Channel, Int)
forall a. (T -> Maybe (Channel, a)) -> T -> Maybe (Channel, a)
liftFile T -> Maybe (Channel, Int)
forall event. C event => event -> Maybe (Channel, Int)
pitchBend
   channelPressure :: T -> Maybe (Channel, Int)
channelPressure = (T -> Maybe (Channel, Int)) -> T -> Maybe (Channel, Int)
forall a. (T -> Maybe (Channel, a)) -> T -> Maybe (Channel, a)
liftFile T -> Maybe (Channel, Int)
forall event. C event => event -> Maybe (Channel, Int)
channelPressure
   mode :: T -> Maybe (Channel, T)
mode = (T -> Maybe (Channel, T)) -> T -> Maybe (Channel, T)
forall a. (T -> Maybe (Channel, a)) -> T -> Maybe (Channel, a)
liftFile T -> Maybe (Channel, T)
forall event. C event => event -> Maybe (Channel, T)
mode