module Main where import Common import qualified Sound.ALSA.Sequencer.Event as Event import qualified Sound.ALSA.Sequencer as SndSeq import Graphics.UI.WX ((.+.), Prop((:=)), set, get, selection, command, on, button, close, container, hfloatCentre, widget, vfill, layout, margin, select, spinCtrl, text, label, ) import qualified Graphics.UI.WX as WX import qualified Graphics.UI.WXCore as WXCore import Control.Monad (forM, forM_, when, ) import qualified Data.List as List wxSL_INVERSE :: Int wxSL_INVERSE = 0x1000 vslider :: WX.Window a -> Bool -> Int -> Int -> [WX.Prop (WX.Slider ())] -> IO (WX.Slider ()) vslider parentW showLabels top bottom props = let (minV, maxV, dirFlags) = if top WX.Event a (IO ()) -> (Event.Value -> IO ()) -> a -> b -> IO () transferSelection event action src dst = set src [on event := get src selection >>= \i -> set dst [selection := i] >> action (Event.Value $ fromIntegral i)] getController :: WX.SpinCtrl () -> IO Event.Parameter getController ctrlSpin = fmap (Event.Parameter . fromIntegral) $ WX.get ctrlSpin WX.selection data Slider = Slider (WX.Slider ()) (WX.SpinCtrl ()) (WX.SpinCtrl ()) (WX.SpinCtrl ()) updateSliders :: [Slider] -> Event.T -> IO () updateSliders sliders ev = case Event.body ev of Event.CtrlEv Event.Controller ctrlEv -> forM_ sliders $ \(Slider val sval ctrl chan) -> do midiChan <- getChannel chan midiCtrl <- getController ctrl when (midiChan == Event.ctrlChannel ctrlEv && midiCtrl == Event.ctrlParam ctrlEv) $ let v = fromIntegral $ Event.unValue $ Event.ctrlValue ctrlEv in set val [selection := v] >> set sval [selection := v] _ -> return () makeGUI :: Sequencer SndSeq.DuplexMode -> IO () makeGUI sequ = do f <- WX.frame [text := "MIDI Controllers"] p <- WX.panel f [] sliders <- forM [7, 1, 73, 70, 71, 93, 94, 95] $ \n -> do val <- vslider p False 127 0 [] sval <- spinCtrl p 0 127 [] ctrl <- spinCtrl p 0 119 [selection := n] chan <- spinCtrl p 0 15 [] let send x = do midiChan <- getChannel chan midiCtrl <- getController ctrl sendCtrl sequ midiChan midiCtrl x transferSelection command send val sval transferSelection select send sval val return $ Slider val sval ctrl chan reactOnEvent 20 f sequ (updateSliders sliders) quit <- button p [text := "Quit", on command := close f] let makeCol (Slider val sval ctrl chan) = vfill (widget val) : widget sval : widget ctrl : widget chan : [] labels = map WX.valignCentre $ WX.vglue : label "Value" : label "Controller" : label "Channel" : [] set f [layout := container p $ margin 10 $ WX.column 5 [ WX.grid 5 5 $ List.transpose $ labels : map makeCol sliders, hfloatCentre (widget quit)]] sendCtrl :: Sequencer SndSeq.DuplexMode -> Event.Channel -> Event.Parameter -> Event.Value -> IO () sendCtrl h chan ctrl val = sendEvent h $ Event.CtrlEv Event.Controller $ Event.Ctrl { Event.ctrlChannel = chan, Event.ctrlParam = ctrl, Event.ctrlValue = val } main :: IO () main = withSequencer "Slider bank" $ WX.start . makeGUI