summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2015-12-17 18:06:40 -0500
committerAndrew Cady <d@jerkface.net>2015-12-17 18:06:40 -0500
commit9a065c35ecdf3cc78d08d4b785762d7c5cc51466 (patch)
tree2039d78ccaba5a9b2fe13625e393ba897c0d32a3
parent4c1e311e6b267eacee2b1a240024d9210827538b (diff)
axis.hs: start to move mainloop into RWST
-rw-r--r--axis-of-eval.cabal7
-rw-r--r--axis.hs188
2 files changed, 107 insertions, 88 deletions
diff --git a/axis-of-eval.cabal b/axis-of-eval.cabal
index da7a2a8..852d040 100644
--- a/axis-of-eval.cabal
+++ b/axis-of-eval.cabal
@@ -18,9 +18,10 @@ executable axis
18 default-language: Haskell2010 18 default-language: Haskell2010
19 hs-source-dirs: . 19 hs-source-dirs: .
20 build-depends: 20 build-depends:
21 base, time, SDL, SDL-ttf, SDL-gfx, containers, haskore, alsa-seq, alsa-core, base-prelude 21 base, time, SDL, SDL-ttf, SDL-gfx, containers, haskore, alsa-seq, alsa-core, base-prelude, mtl
22 main-is: axis.hs 22 main-is: axis.hs
23 other-modules: AlsaSeq 23 ghc-options: -threaded -W -Wall -O2
24 other-modules: AlsaSeq, AlsaShutUp
24 25
25executable rtq 26executable rtq
26 default-language: Haskell2010 27 default-language: Haskell2010
@@ -39,5 +40,5 @@ executable midi-dump
39 sqlite-simple, bytestring, base-prelude, midi-alsa, midi, psqueues, 40 sqlite-simple, bytestring, base-prelude, midi-alsa, midi, psqueues,
40 transformers, semigroups, HCodecs, threads 41 transformers, semigroups, HCodecs, threads
41 main-is: midi-dump.hs 42 main-is: midi-dump.hs
42 other-modules: AlsaSeq, Midi, RealTimeQueue 43 other-modules: AlsaSeq, Midi, RealTimeQueue, AlsaShutUp
43 ghc-options: -threaded -W -Wall -O2 -rtsopts 44 ghc-options: -threaded -W -Wall -O2 -rtsopts
diff --git a/axis.hs b/axis.hs
index b093414..cdbcc7c 100644
--- a/axis.hs
+++ b/axis.hs
@@ -1,4 +1,5 @@
1{-# LANGUAGE StandaloneDeriving #-} 1{-# LANGUAGE StandaloneDeriving #-}
2{-# LANGUAGE FlexibleContexts #-}
2import Prelude () 3import Prelude ()
3import BasePrelude 4import BasePrelude
4import Data.Time.Clock 5import Data.Time.Clock
@@ -18,6 +19,11 @@ import Data.Bits
18import qualified Sound.ALSA.Sequencer.Event as Event 19import qualified Sound.ALSA.Sequencer.Event as Event
19import qualified Graphics.UI.SDL.Utilities as SDL.Util 20import qualified Graphics.UI.SDL.Utilities as SDL.Util
20import qualified Data.Map as Map 21import qualified Data.Map as Map
22import Control.Monad.RWS.Strict
23
24import qualified Sound.ALSA.Sequencer
25import qualified Sound.ALSA.Sequencer.Queue
26import qualified Sound.ALSA.Sequencer.Address
21 27
22smartShowPitch = showPitch -- TODO: use flat for Eb, Bb; use unicode flat/sharp chars 28smartShowPitch = showPitch -- TODO: use flat for Eb, Bb; use unicode flat/sharp chars
23 29
@@ -188,6 +194,12 @@ firstDigitDown :: Set.Set SDL.Keysym.SDLKey -> Maybe Integer
188firstDigitDown k = if Set.null digitsDown then Nothing else Just $ (-48 +) $ fromIntegral $ SDL.Util.fromEnum $ Set.findMin digitsDown 194firstDigitDown k = if Set.null digitsDown then Nothing else Just $ (-48 +) $ fromIntegral $ SDL.Util.fromEnum $ Set.findMin digitsDown
189 where digitsDown = Set.intersection _SDL_DIGITS k 195 where digitsDown = Set.intersection _SDL_DIGITS k
190 196
197data Env = Env
198 (Sound.ALSA.Sequencer.T Sound.ALSA.Sequencer.DuplexMode)
199 Sound.ALSA.Sequencer.Queue.T
200 Sound.ALSA.Sequencer.Address.T
201 (Int -> Int -> IO SDL.Surface)
202
191main = 203main =
192 withAlsaInit $ \h public private q publicAddr privateAddr -> do 204 withAlsaInit $ \h public private q publicAddr privateAddr -> do
193 cmdlineAlsaConnect h public -- fail early if bad command lines 205 cmdlineAlsaConnect h public -- fail early if bad command lines
@@ -211,91 +223,97 @@ main =
211 -- SDL.createRGBSurfaceEndian [] 1 1 24 223 -- SDL.createRGBSurfaceEndian [] 1 1 24
212 putStrLn "Initialized." 224 putStrLn "Initialized."
213 225
214 let parseAlsa keysDown = parseAlsaEvents h keysDown (forwardNoteEvent h q publicAddr) 226 (_, ()) <- execRWST
215 let loop state midiKeysDown keysDown resolution font = do 227 (mainLoop Set.empty Set.empty (sWidth, sHeight) font)
216 let LoopState firstLoop colsRepeat = state 228 (Env h q publicAddr setVideoMode) (LoopState True _AXIS_COLS_REPEAT)
217 229 return ()
218 (keysDown', resolution') <- parseSDLEvents keysDown resolution 230
219 midiKeysDown' <- parseAlsa midiKeysDown 231mainLoop :: (MonadIO f, MonadState LoopState f, MonadReader Env f)
220 let colsRepeat' = 232 => Set.Set (Event.Channel, Event.Pitch) -> Set.Set SDLKey -> (Int, Int) -> SDL.TTF.Font -> f ()
221 case firstDigitDown keysDown' of 233mainLoop midiKeysDown keysDown resolution font = do
222 Nothing -> colsRepeat 234 Env h q publicAddr setVideoMode <- ask
223 (Just 0) -> colsRepeat 235 LoopState firstLoop colsRepeat <- get
224 (Just n) -> n 236
225 237 (keysDown', resolution') <- liftIO $ parseSDLEvents keysDown resolution
226 let restartVideo = resolution' /= resolution || colsRepeat' /= colsRepeat 238 midiKeysDown' <- liftIO $ parseAlsaEvents h midiKeysDown (forwardNoteEvent h q publicAddr)
227 239 let colsRepeat' =
228 when restartVideo $ do 240 case firstDigitDown keysDown' of
229 let (w, h) = resolution' 241 Nothing -> colsRepeat
230 _ <- setVideoMode w h 242 (Just 0) -> colsRepeat
231 return () 243 (Just n) -> n
232 244
233 let (w, h) = resolution' 245 let restartVideo = resolution' /= resolution || colsRepeat' /= colsRepeat
234 fontSize = chooseFontSize w h 246
235 font' <- if restartVideo 247 when restartVideo $ do
236 then SDL.TTF.openFont "LiberationMono-Bold.ttf" fontSize 248 let (w, h) = resolution'
237 else return font 249 void $ liftIO $ setVideoMode w h
238 250
239 videoSurface <- SDL.getVideoSurface 251 let (w, h) = resolution'
240 videoClipRect <- SDL.getClipRect videoSurface 252 fontSize = chooseFontSize w h
241 let (axis_key_size, axis_key_locations) = getKeyLocations colsRepeat' videoClipRect 253 font' <- if restartVideo
242 254 then liftIO $ SDL.TTF.openFont "LiberationMono-Bold.ttf" fontSize
243 let _ALL_PITCHES = Set.fromList $ map (\p -> (Event.Channel 1, Event.Pitch p)) [_AXIS_BOTTOMLEFT_PITCH .. _AXIS_TOPRIGHT_PITCH] 255 else return font
244 keysOFF really = allKeysOff colsRepeat' really videoSurface font' axis_key_locations axis_key_size 256
245 allKeysOFF = keysOFF False 257 videoSurface <- liftIO SDL.getVideoSurface
246 allKeysReallyOFF = keysOFF True 258 videoClipRect <- liftIO $ SDL.getClipRect videoSurface
247 259 let (axis_key_size, axis_key_locations) = getKeyLocations colsRepeat' videoClipRect
248 when firstLoop allKeysOFF 260
249 261 let _ALL_PITCHES = Set.fromList $ map (\p -> (Event.Channel 1, Event.Pitch p))
250 -- when (x /= x' && x' /= "") $ do 262 [_AXIS_BOTTOMLEFT_PITCH .. _AXIS_TOPRIGHT_PITCH]
251 -- textBand videoSurface videoClipRect (SDL.Rect 0 0 0 70) font x' 263 keysOFF really = allKeysOff colsRepeat' really videoSurface font' axis_key_locations axis_key_size
252 -- return () 264 allKeysOFF = keysOFF False
253 let chanfilter = Set.filter (\(c, _) -> c /= Event.Channel 9) 265 allKeysReallyOFF = keysOFF True
254 beforeKeys = chanfilter midiKeysDown 266
255 nowKeys = chanfilter midiKeysDown' 267 when firstLoop $ liftIO allKeysOFF
256 268
257 changedPitches = Set.map snd $ Set.union (Set.difference nowKeys beforeKeys) (Set.difference beforeKeys nowKeys) 269 -- when (x /= x' && x' /= "") $ do
258 playingNowChans n = Set.map fst $ Set.filter (\(_, p) -> p == n) nowKeys 270 -- textBand videoSurface videoClipRect (SDL.Rect 0 0 0 70) font x'
259 actions = Set.toList $ Set.map (\p -> (p, Set.toList $ playingNowChans p)) changedPitches 271 -- return ()
260 chanPitches = Map.fromListWith (++) $ map (\(c, p) -> (c, [p])) $ Set.toList nowKeys 272 let chanfilter = Set.filter (\(c, _) -> c /= Event.Channel 9)
261 273 beforeKeys = chanfilter midiKeysDown
262 when (midiKeysDown' /= midiKeysDown) $ do 274 nowKeys = chanfilter midiKeysDown'
263 -- let chord = showChord midiKeysDown' 275
264 -- let chord = show $ pitchList midiKeysDown' 276 changedPitches = Set.map snd $ Set.union (Set.difference nowKeys beforeKeys)
265 -- let chord = show $ map (\i->elemIndices i pitchIndex) $ pitchList midiKeysDown' 277 (Set.difference beforeKeys nowKeys)
266 -- textBand videoSurface videoClipRect (SDL.Rect 0 70 0 70) font chord 278 playingNowChans n = Set.map fst $ Set.filter (\(_, p) -> p == n) nowKeys
267 smartDrawKeys colsRepeat' False midiKeysDown midiKeysDown' videoSurface font' axis_key_locations axis_key_size 279 actions = Set.toList $ Set.map (\p -> (p, Set.toList $ playingNowChans p)) changedPitches
268 280 chanPitches = Map.fromListWith (++) $ map (\(c, p) -> (c, [p])) $ Set.toList nowKeys
269 when restartVideo $ do 281
270 allKeysOFF 282 when (midiKeysDown' /= midiKeysDown) $ do
271 smartDrawKeys colsRepeat' False Set.empty midiKeysDown' videoSurface font' axis_key_locations axis_key_size 283 -- let chord = showChord midiKeysDown'
272 284 -- let chord = show $ pitchList midiKeysDown'
273 when (keysDown' /= keysDown) $ do 285 -- let chord = show $ map (\i->elemIndices i pitchIndex) $ pitchList midiKeysDown'
274 when (keyDown SDL.SDLK_BACKSPACE keysDown') allKeysOFF 286 -- textBand videoSurface videoClipRect (SDL.Rect 0 70 0 70) font chord
275 when (keyDown SDL.SDLK_c keysDown') allKeysReallyOFF 287 liftIO $ smartDrawKeys colsRepeat' False midiKeysDown midiKeysDown' videoSurface font' axis_key_locations axis_key_size
276 288
277 -- Control.Monad.when (keysDown' /= keysDown) $ do 289 when restartVideo $ do
278 -- let chord = unwords $ map (\k -> drop 5 (show k)) $ Set.toList keysDown' 290 liftIO allKeysOFF
279 -- textBand videoSurface videoClipRect (SDL.Rect 0 210 0 70) font chord 291 liftIO $ smartDrawKeys colsRepeat' False Set.empty midiKeysDown' videoSurface font' axis_key_locations axis_key_size
280 -- textBand videoSurface videoClipRect (SDL.Rect 0 280 0 70) font $ 292
281 -- if keyDown SDL.SDLK_a keysDown' then "arpeggiate" else "" 293 when (keysDown' /= keysDown) $ do
282 -- return () 294 when (keyDown SDL.SDLK_BACKSPACE keysDown') $ liftIO allKeysOFF
283 -- Control.Monad.when(False) $ do 295 when (keyDown SDL.SDLK_c keysDown') $ liftIO allKeysReallyOFF
284 -- 296
285 -- mouse <- SDL.getRelativeMouseState 297 -- Control.Monad.when (keysDown' /= keysDown) $ do
286 -- let (x, y, button) = mouse 298 -- let chord = unwords $ map (\k -> drop 5 (show k)) $ Set.toList keysDown'
287 -- let text = ((show x) ++ " " ++ (show y) ++ " " ++ (show button)) 299 -- textBand videoSurface videoClipRect (SDL.Rect 0 210 0 70) font chord
288 -- textBand videoSurface videoClipRect (SDL.Rect 0 140 0 70) font text 300 -- textBand videoSurface videoClipRect (SDL.Rect 0 280 0 70) font $
289 -- Control.Monad.when (x /= 0 || y /= 0) warpMouse 301 -- if keyDown SDL.SDLK_a keysDown' then "arpeggiate" else ""
290 302 -- return ()
291 _ <- SDL.flip videoSurface 303 -- Control.Monad.when(False) $ do
292 let framerate = 30 304 --
293 let delay = 1000 `div` framerate -- TODO: subtract delta 305 -- mouse <- SDL.getRelativeMouseState
294 SDL.delay delay 306 -- let (x, y, button) = mouse
295 unless (keyDown SDL.SDLK_ESCAPE keysDown) $ 307 -- let text = ((show x) ++ " " ++ (show y) ++ " " ++ (show button))
296 loop (LoopState False colsRepeat') midiKeysDown' keysDown' resolution' font' 308 -- textBand videoSurface videoClipRect (SDL.Rect 0 140 0 70) font text
297 309 -- Control.Monad.when (x /= 0 || y /= 0) warpMouse
298 loop (LoopState True _AXIS_COLS_REPEAT) Set.empty Set.empty (sWidth, sHeight) font 310 void $ liftIO $ SDL.flip videoSurface
311 let framerate = 30
312 let delay = 1000 `div` framerate -- TODO: subtract delta
313 liftIO $ SDL.delay delay
314 unless (keyDown SDL.SDLK_ESCAPE keysDown) $ do
315 put (LoopState False colsRepeat')
316 mainLoop midiKeysDown' keysDown' resolution' font'
299 317
300zipzip ls = if null (head ls) then [] else map head ls : zipzip (map tail ls) 318zipzip ls = if null (head ls) then [] else map head ls : zipzip (map tail ls)
301 319