summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2015-12-06 01:49:08 -0500
committerAndrew Cady <d@jerkface.net>2015-12-06 01:49:08 -0500
commit3f83abf93d0870f3420b6efe900949fc3f6f74ba (patch)
tree7ed02755414fb531805beccc35571f82fecef2f1
parent9207096755c1db24b81115fe02ca6e97e21e48bf (diff)
implement module RealTimeQueue
-rw-r--r--RealTimeQueue.hs52
-rw-r--r--axis-of-eval.cabal11
-rw-r--r--rtq.hs46
3 files changed, 108 insertions, 1 deletions
diff --git a/RealTimeQueue.hs b/RealTimeQueue.hs
new file mode 100644
index 0000000..dc40c84
--- /dev/null
+++ b/RealTimeQueue.hs
@@ -0,0 +1,52 @@
1module RealTimeQueue where
2import BasePrelude hiding ((<>))
3import System.Clock
4import Data.IntPSQ as Q
5import Control.Monad.IO.Class
6import Data.Semigroup
7
8scheduleEvent :: (TimeSpec, event) -> Queue event -> Queue event
9scheduleEvent (ts, ev) (Queue q i) = Queue (Q.insert i ts ev q) (i+1)
10
11instance Semigroup (Queue event) where
12 _ <> q = q
13
14extractScheduledEvents :: TimeSpec -> TimeSpec -> Queue event -> ([(TimeSpec, event)], Queue event)
15extractScheduledEvents currentTime timeSpan = getAllScheduled
16 where
17 getAllScheduled :: Queue event -> ([(TimeSpec, event)], Queue event)
18 getAllScheduled queue@(Queue q i)
19 | isNothing $ getFirstScheduled queue = ([], queue)
20 | otherwise = let (Just (_, p, v, q')) = minView q
21 queue' = Queue q' i
22 in ([(p, v)], queue') <> getAllScheduled queue'
23
24
25 getFirstScheduled :: Queue event -> Maybe (TimeSpec, event)
26 getFirstScheduled (Queue x _) = case findMin x of
27 Nothing -> Nothing
28 Just (_, ts, _) | ts > currentTime + timeSpan -> Nothing
29 Just (_, ts, ev) -> Just (ts - currentTime, ev)
30
31type QueueRunner m event = TimeSpec -> event -> m ()
32
33scheduleEventIO :: MonadIO m => (TimeSpec, event) -> Queue event -> m (Queue event)
34scheduleEventIO (ts, ev) queue = do
35 now <- liftIO $ getTime Monotonic
36 return $ scheduleEvent (ts + now, ev) queue
37
38runScheduledIO :: MonadIO m => TimeSpec -> QueueRunner m event -> Queue event -> m (Queue event)
39runScheduledIO timeSpan runner queue = do
40 now <- liftIO $ getTime Monotonic
41 let (events, queue') = extractScheduledEvents now timeSpan queue
42 forM_ events $ \(ts, ev) -> runner (ts - now) ev
43 return queue'
44
45
46createQueue :: Queue event
47createQueue = Queue Q.empty 0
48
49data Queue event = Queue {
50 intQueue :: IntPSQ TimeSpec event,
51 nextKey :: Int
52}
diff --git a/axis-of-eval.cabal b/axis-of-eval.cabal
index acafc72..7a879dd 100644
--- a/axis-of-eval.cabal
+++ b/axis-of-eval.cabal
@@ -14,7 +14,7 @@ category: Sound
14build-type: Simple 14build-type: Simple
15cabal-version: >=1.10 15cabal-version: >=1.10
16 16
17executable axis-of-eval 17executable axis
18 default-language: Haskell2010 18 default-language: Haskell2010
19 hs-source-dirs: . 19 hs-source-dirs: .
20 build-depends: 20 build-depends:
@@ -22,6 +22,15 @@ executable axis-of-eval
22 main-is: axis.hs 22 main-is: axis.hs
23 other-modules: AlsaSeq 23 other-modules: AlsaSeq
24 24
25executable rtq
26 default-language: Haskell2010
27 hs-source-dirs: .
28 build-depends:
29 base, time, clock, base-prelude, psqueues, transformers, mtl, semigroups
30 main-is: rtq.hs
31 other-modules: RealTimeQueue
32 ghc-options: -threaded -W -Wall -O2
33
25executable midi-dump 34executable midi-dump
26 default-language: Haskell2010 35 default-language: Haskell2010
27 hs-source-dirs: . 36 hs-source-dirs: .
diff --git a/rtq.hs b/rtq.hs
new file mode 100644
index 0000000..a47491a
--- /dev/null
+++ b/rtq.hs
@@ -0,0 +1,46 @@
1{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE ExplicitForAll #-}
3{-# LANGUAGE KindSignatures #-}
4
5import BasePrelude hiding ((.))
6import RealTimeQueue
7import Control.Monad.IO.Class
8import Control.Monad.State
9import System.Clock
10
11data LoopState = LoopState {
12 _queue :: Queue String
13}
14
15main :: IO ()
16main = void $ runStateT main' (LoopState createQueue)
17
18main' :: StateT LoopState IO ()
19main' = do
20 queueAction $ scheduleEventIO (TimeSpec 1 0, "hello world")
21 queueAction $ scheduleEventIO (TimeSpec 2 0, "hello world")
22 queueAction $ scheduleEventIO (TimeSpec 3 0, "hello world")
23 queueAction $ scheduleEventIO (TimeSpec 4 0, "hello world")
24 mainLoop
25
26queueAction :: forall (m :: * -> *). MonadState LoopState m => (Queue String -> m (Queue String)) -> m ()
27queueAction act = do
28 q <- gets _queue
29 act q >>= modify . const . LoopState
30
31tickTime :: TimeSpec
32tickTime = TimeSpec 0 15000
33
34threadDelay' :: TimeSpec -> IO ()
35threadDelay' = threadDelay . fromIntegral . timeSpecAsNanoSecs
36
37runner :: TimeSpec -> String -> StateT LoopState IO ()
38runner delay str = liftIO $ do
39 threadDelay' delay
40 putStrLn str
41
42mainLoop :: StateT LoopState IO ()
43mainLoop = do
44 queueAction $ runScheduledIO tickTime runner
45 liftIO $ threadDelay' tickTime
46 mainLoop