{-
The instances Class.C Event.T and Class.C Event.Data are orphan.
I could put it in package 'midi' or 'alsa-seq'
but in both of them it imposes a lot of new dependencies.
-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Sound.MIDI.ALSA.Query (
   Class.C,
   Class.note,
   Class.program,
   Class.anyController,
   Class.mode,
   Class.pitchBend,
   Class.channelPressure,
   ) where

import qualified Sound.MIDI.Message.Class.Query as Class
import qualified Sound.MIDI.Message.Channel.Mode as Mode

import qualified Sound.MIDI.ALSA as MALSA

import qualified Sound.ALSA.Sequencer.Event as Event

import Sound.MIDI.Message.Channel (Channel, )
import Sound.MIDI.Message.Channel.Voice (Pitch, Velocity, Controller, Program, )

import Data.Accessor.Basic ((^.), )


instance Class.C Event.T where
   note = noteData . Event.body
   program = programData . Event.body
   anyController = anyControllerData . Event.body
   mode = modeData . Event.body
   pitchBend = pitchBendData . Event.body
   channelPressure = channelPressureData . Event.body

instance Class.C Event.Data where
   note = noteData
   program = programData
   anyController = anyControllerData
   mode = modeData
   pitchBend = pitchBendData
   channelPressure = channelPressureData


noteData ::
   Event.Data -> Maybe (Channel, (Velocity, Pitch, Bool))
noteData e = do
   Event.NoteEv n c <- Just e
   let pitch    = c ^. MALSA.notePitch
       velocity = c ^. MALSA.noteVelocity
   fmap ((,) (c ^. MALSA.noteChannel)) $
      case n of
         Event.NoteOn  -> Just (velocity, pitch, True)
         Event.NoteOff -> Just (velocity, pitch, False)
         _ -> Nothing

programData ::
   Event.Data -> Maybe (Channel, Program)
programData e = do
   Event.CtrlEv Event.PgmChange c <- Just e
   return (c ^. MALSA.ctrlChannel, c ^. MALSA.ctrlProgram)

anyControllerData ::
   Event.Data -> Maybe (Channel, (Controller, Int))
anyControllerData e = do
   -- let Event.TickTime n = Event.timestamp e
   Event.CtrlEv Event.Controller c <- Just e
   MALSA.Controller cn cv <- Just $ c ^. MALSA.ctrlControllerMode
   return (c ^. MALSA.ctrlChannel, (cn, cv))

modeData :: Event.Data -> Maybe (Channel, Mode.T)
modeData e = do
   Event.CtrlEv Event.Controller c <- Just e
   MALSA.Mode m <- Just $ c ^. MALSA.ctrlControllerMode
   return (c ^. MALSA.ctrlChannel, m)

pitchBendData :: Event.Data -> Maybe (Channel, Int)
pitchBendData e =
   case e of
      Event.CtrlEv Event.PitchBend c ->
         Just (c ^. MALSA.ctrlChannel, c ^. MALSA.ctrlValue)
      _ -> Nothing

channelPressureData :: Event.Data -> Maybe (Channel, Int)
channelPressureData e =
   case e of
      Event.CtrlEv Event.ChanPress c ->
         Just (c ^. MALSA.ctrlChannel, c ^. MALSA.ctrlValue)
      _ -> Nothing