summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2015-12-06 03:56:57 -0500
committerAndrew Cady <d@jerkface.net>2015-12-06 03:56:57 -0500
commitf8ac45371bff74034205fec65a9e69c0a527e8a4 (patch)
tree3b60e505e4d05a027e0f5ec0baec14dab8599857
parentb6a53650153ba5f0b6cab3679d582c0788107e9c (diff)
use RealTimeQueue for queuing midi output to ALSA
-rw-r--r--axis-of-eval.cabal5
-rw-r--r--midi-dump.hs37
2 files changed, 31 insertions, 11 deletions
diff --git a/axis-of-eval.cabal b/axis-of-eval.cabal
index 7a879dd..fa1049d 100644
--- a/axis-of-eval.cabal
+++ b/axis-of-eval.cabal
@@ -36,7 +36,8 @@ executable midi-dump
36 hs-source-dirs: . 36 hs-source-dirs: .
37 build-depends: 37 build-depends:
38 base, time, containers, haskore, alsa-seq, alsa-core, mtl, clock, 38 base, time, containers, haskore, alsa-seq, alsa-core, mtl, clock,
39 sqlite-simple, bytestring, base-prelude, midi-alsa, midi 39 sqlite-simple, bytestring, base-prelude, midi-alsa, midi, psqueues,
40 transformers, semigroups
40 main-is: midi-dump.hs 41 main-is: midi-dump.hs
41 other-modules: AlsaSeq 42 other-modules: AlsaSeq, Midi, RealTimeQueue
42 ghc-options: -threaded -W -Wall -O2 43 ghc-options: -threaded -W -Wall -O2
diff --git a/midi-dump.hs b/midi-dump.hs
index f332482..536d78d 100644
--- a/midi-dump.hs
+++ b/midi-dump.hs
@@ -29,6 +29,7 @@ import qualified Sound.ALSA.Sequencer.Time as Time
29import qualified Sound.ALSA.Sequencer.RealTime as RealTime 29import qualified Sound.ALSA.Sequencer.RealTime as RealTime
30 30
31import Midi 31import Midi
32import RealTimeQueue as Q hiding (null)
32 33
33verbose :: Bool 34verbose :: Bool
34verbose = False 35verbose = False
@@ -42,13 +43,14 @@ data LoopState = LoopState {
42 _wantExit :: Bool, 43 _wantExit :: Bool,
43 keysDown :: MidiPitchSet, 44 keysDown :: MidiPitchSet,
44 _playNOW :: [Event.Data], 45 _playNOW :: [Event.Data],
46 _scheduled :: Q.Queue Event.Data,
45 _recording :: Recording, 47 _recording :: Recording,
46 _replay :: Recording, 48 _replay :: Recording,
47 _lastTick :: TimeSpec 49 _lastTick :: TimeSpec
48} 50}
49 51
50initializeState :: TimeSpec -> LoopState 52initializeState :: TimeSpec -> LoopState
51initializeState now = LoopState False Set.empty [] (StartRecording now) (StartRecording now) now 53initializeState now = LoopState False Set.empty [] createQueue (StartRecording now) (StartRecording now) now
52 54
53data LoopEnv = LoopEnv { 55data LoopEnv = LoopEnv {
54 _saver :: Chan CompleteRecording, 56 _saver :: Chan CompleteRecording,
@@ -131,14 +133,23 @@ mainLoop = do
131 maybeReadLine >>= maybe processMidi processCommand 133 maybeReadLine >>= maybe processMidi processCommand
132 wantExit <- gets _wantExit 134 wantExit <- gets _wantExit
133 135
134 scheduled <- gets _playNOW 136 playImmediates
135 unless (null scheduled) $ do 137 playScheduled
136 forM_ scheduled playNoteEv
137 -- TODO: flush ALSA output here (and remove flush from playNoteEv)
138 modify $ \s -> s { _playNOW = [] }
139 138
140 unless wantExit mainLoop 139 unless wantExit mainLoop
141 140
141playScheduled :: MidiController ()
142playScheduled = queueAction $ runScheduledIO (TimeSpec 1 0) $ uncurry alsaDelayNoteEv
143-- TODO: flush ALSA output here (and remove flush from playNoteEv)
144
145playImmediates :: MidiController ()
146playImmediates = do
147 immediate <- gets _playNOW
148 unless (null immediate) $ do
149 forM_ immediate playNoteEv
150 -- TODO: flush ALSA output here (and remove flush from playNoteEv)
151 modify $ \s -> s { _playNOW = [] }
152
142_playNote :: Bool -> Event.Note -> RWST LoopEnv () LoopState IO () 153_playNote :: Bool -> Event.Note -> RWST LoopEnv () LoopState IO ()
143_playNote noteOn note = 154_playNote noteOn note =
144 playNoteEv $ Event.NoteEv onoff note 155 playNoteEv $ Event.NoteEv onoff note
@@ -149,14 +160,22 @@ delayEvent evt ts = evt {Event.time = Time.consRel $ Time.Real (RealTime.fromInt
149 where nanosecs = timeSpecAsNanoSecs ts 160 where nanosecs = timeSpecAsNanoSecs ts
150 161
151playNoteEv :: Event.Data -> RWST LoopEnv () LoopState IO () 162playNoteEv :: Event.Data -> RWST LoopEnv () LoopState IO ()
152playNoteEv = delayNoteEv (TimeSpec 0 0) 163playNoteEv = alsaDelayNoteEv (TimeSpec 0 0)
153 164
154delayNoteEv :: TimeSpec -> Event.Data -> RWST LoopEnv () LoopState IO () 165alsaDelayNoteEv :: TimeSpec -> Event.Data -> RWST LoopEnv () LoopState IO ()
155delayNoteEv delay nevdata = do 166alsaDelayNoteEv delay nevdata = do
156 ms <- getMidiSender 167 ms <- getMidiSender
157 publicAddr <- asks _publicAddr 168 publicAddr <- asks _publicAddr
158 liftIO $ ms $ Event.simple publicAddr nevdata `delayEvent` delay 169 liftIO $ ms $ Event.simple publicAddr nevdata `delayEvent` delay
159 170
171queueAction :: (Queue Event.Data -> MidiController (Queue Event.Data)) -> MidiController ()
172queueAction act = do
173 q <- gets _scheduled
174 act q >>= \q' -> modify $ \s -> s { _scheduled = q' }
175
176delayNoteEv :: TimeSpec -> Event.Data -> RWST LoopEnv () LoopState IO ()
177delayNoteEv delay nevdata = queueAction $ scheduleEventIO (delay, nevdata)
178
160_whenFlag :: forall (m :: * -> *) s. MonadState s m => (s -> Bool) -> m () -> m () 179_whenFlag :: forall (m :: * -> *) s. MonadState s m => (s -> Bool) -> m () -> m ()
161_whenFlag flag f = gets flag >>= flip when f 180_whenFlag flag f = gets flag >>= flip when f
162 181