diff options
author | Andrew Cady <d@jerkface.net> | 2015-12-17 18:06:40 -0500 |
---|---|---|
committer | Andrew Cady <d@jerkface.net> | 2015-12-17 18:06:40 -0500 |
commit | 9a065c35ecdf3cc78d08d4b785762d7c5cc51466 (patch) | |
tree | 2039d78ccaba5a9b2fe13625e393ba897c0d32a3 | |
parent | 4c1e311e6b267eacee2b1a240024d9210827538b (diff) |
axis.hs: start to move mainloop into RWST
-rw-r--r-- | axis-of-eval.cabal | 7 | ||||
-rw-r--r-- | axis.hs | 188 |
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 | ||
25 | executable rtq | 26 | executable 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 |
@@ -1,4 +1,5 @@ | |||
1 | {-# LANGUAGE StandaloneDeriving #-} | 1 | {-# LANGUAGE StandaloneDeriving #-} |
2 | {-# LANGUAGE FlexibleContexts #-} | ||
2 | import Prelude () | 3 | import Prelude () |
3 | import BasePrelude | 4 | import BasePrelude |
4 | import Data.Time.Clock | 5 | import Data.Time.Clock |
@@ -18,6 +19,11 @@ import Data.Bits | |||
18 | import qualified Sound.ALSA.Sequencer.Event as Event | 19 | import qualified Sound.ALSA.Sequencer.Event as Event |
19 | import qualified Graphics.UI.SDL.Utilities as SDL.Util | 20 | import qualified Graphics.UI.SDL.Utilities as SDL.Util |
20 | import qualified Data.Map as Map | 21 | import qualified Data.Map as Map |
22 | import Control.Monad.RWS.Strict | ||
23 | |||
24 | import qualified Sound.ALSA.Sequencer | ||
25 | import qualified Sound.ALSA.Sequencer.Queue | ||
26 | import qualified Sound.ALSA.Sequencer.Address | ||
21 | 27 | ||
22 | smartShowPitch = showPitch -- TODO: use flat for Eb, Bb; use unicode flat/sharp chars | 28 | smartShowPitch = 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 | |||
188 | firstDigitDown k = if Set.null digitsDown then Nothing else Just $ (-48 +) $ fromIntegral $ SDL.Util.fromEnum $ Set.findMin digitsDown | 194 | firstDigitDown 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 | ||
197 | data 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 | |||
191 | main = | 203 | main = |
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 | 231 | mainLoop :: (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 | 233 | mainLoop 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 | ||
300 | zipzip ls = if null (head ls) then [] else map head ls : zipzip (map tail ls) | 318 | zipzip ls = if null (head ls) then [] else map head ls : zipzip (map tail ls) |
301 | 319 | ||