summaryrefslogtreecommitdiff
path: root/midi-dump.hs
diff options
context:
space:
mode:
Diffstat (limited to 'midi-dump.hs')
-rw-r--r--midi-dump.hs42
1 files changed, 22 insertions, 20 deletions
diff --git a/midi-dump.hs b/midi-dump.hs
index 52fe6b2..6c2c8b8 100644
--- a/midi-dump.hs
+++ b/midi-dump.hs
@@ -8,7 +8,7 @@ import AlsaSeq
8import Control.Monad.RWS.Strict 8import Control.Monad.RWS.Strict
9import Data.List 9import Data.List
10import Data.Maybe 10import Data.Maybe
11import qualified Data.Set as Set 11import qualified Data.Map.Strict as Map
12import qualified Sound.ALSA.Exception as AlsaExc 12import qualified Sound.ALSA.Exception as AlsaExc
13import qualified Sound.ALSA.Sequencer.Event as Event 13import qualified Sound.ALSA.Sequencer.Event as Event
14import System.Clock 14import System.Clock
@@ -43,7 +43,7 @@ data Triad = Major Event.Pitch | Minor Event.Pitch deriving (Show, Eq)
43 43
44data LoopState = LoopState { 44data LoopState = LoopState {
45 _wantExit :: Bool, 45 _wantExit :: Bool,
46 _keysDown :: MidiPitchSet, 46 _keysDown :: MidiPitchMap,
47 _triad :: Maybe Triad, 47 _triad :: Maybe Triad,
48 _scheduled :: Q.Queue Event.Data, 48 _scheduled :: Q.Queue Event.Data,
49 _recording :: Recording, 49 _recording :: Recording,
@@ -52,7 +52,7 @@ data LoopState = LoopState {
52} 52}
53 53
54initializeState :: TimeSpec -> LoopState 54initializeState :: TimeSpec -> LoopState
55initializeState now = LoopState False Set.empty Nothing createQueue (StartRecording now) (StartRecording now) now 55initializeState now = LoopState False Map.empty Nothing createQueue (StartRecording now) (StartRecording now) now
56 56
57data LoopEnv = LoopEnv { 57data LoopEnv = LoopEnv {
58 _saver :: Chan CompleteRecording, 58 _saver :: Chan CompleteRecording,
@@ -233,7 +233,7 @@ processMidi = do
233 h <- asks _h 233 h <- asks _h
234 oldKeys <- gets _keysDown 234 oldKeys <- gets _keysDown
235 forwardNOW <- getMidiSender 235 forwardNOW <- getMidiSender
236 (events, newKeys) <- liftIO $ parseAlsaEvents' h oldKeys forwardNOW 236 (events, newKeys) <- liftIO $ parseAlsaEvents'' h oldKeys forwardNOW
237 237
238 238
239 if oldKeys == newKeys 239 if oldKeys == newKeys
@@ -249,18 +249,18 @@ processMidi = do
249 , _lastTick = now 249 , _lastTick = now
250 } 250 }
251 251
252 whenFlag _printChordKeys $ liftIO $ printChordLn newKeys 252 whenFlag _printChordKeys $ liftIO $ printChordLn' newKeys
253 253
254 filterTriads newKeys 254 filterTriads newKeys
255 255
256 -- Whenever no keys are pressed, flush any buffered events to the database 256 -- Whenever no keys are pressed, flush any buffered events to the database
257 when (Set.null newKeys) $ do 257 when (Map.null newKeys) $ do
258 doSave <- asks _doSave 258 doSave <- asks _doSave
259 when doSave $ gets _recording >>= saveMidi >> return () 259 when doSave $ gets _recording >>= saveMidi >> return ()
260 modify $ \s -> s { _recording = StartRecording now } 260 modify $ \s -> s { _recording = StartRecording now }
261 261
262 -- When a key is pressed after 3+ seconds of silence, overwrite the replay buffer with the new keys 262 -- When a key is pressed after 3+ seconds of silence, overwrite the replay buffer with the new keys
263 when (Set.null oldKeys) $ do 263 when (Map.null oldKeys) $ do
264 replay <- gets _replay 264 replay <- gets _replay
265 when (latestEvent replay < (now - TimeSpec 3 0)) $ do 265 when (latestEvent replay < (now - TimeSpec 3 0)) $ do
266 modify $ \s -> s { _replay = StartRecording now } 266 modify $ \s -> s { _replay = StartRecording now }
@@ -268,13 +268,14 @@ processMidi = do
268 268
269 modify $ \s -> s { _replay = recordEvents (_replay s) newEvents } 269 modify $ \s -> s { _replay = recordEvents (_replay s) newEvents }
270 270
271filterTriads :: MidiPitchSet -> MidiController () 271filterTriads :: MidiPitchMap -> MidiController ()
272filterTriads newKeys = do 272filterTriads newKeys = do
273 let newTriad = detectTriad newKeys 273 let newTriad = detectTriad newKeys
274 vel = Event.Velocity 128
274 oldTriad <- gets _triad 275 oldTriad <- gets _triad
275 when (newTriad /= oldTriad) $ do 276 when (newTriad /= oldTriad) $ do
276 forM_ oldTriad (sendTriadEvents False) 277 forM_ oldTriad (sendTriadEvents Nothing)
277 forM_ newTriad (sendTriadEvents True) 278 forM_ newTriad (sendTriadEvents $ Just vel)
278 modify $ \s -> s { _triad = newTriad } 279 modify $ \s -> s { _triad = newTriad }
279 280
280triadBase :: Triad -> Event.Pitch 281triadBase :: Triad -> Event.Pitch
@@ -282,26 +283,27 @@ triadBase (Major n) = n
282triadBase (Minor n) = n 283triadBase (Minor n) = n
283 284
284-- TODO: set velocity based on average from triad (this requires storing that 285-- TODO: set velocity based on average from triad (this requires storing that
285-- information, changing the MidiPitchSet type for one more complex than a mere 286-- information, changing the MidiPitchMap type for one more complex than a mere
286-- Set) 287-- Set)
287sendTriadEvents :: Bool -> Triad -> MidiController () 288sendTriadEvents :: Maybe Event.Velocity -> Triad -> MidiController ()
288sendTriadEvents sendOn triad = do 289sendTriadEvents vel triad = do
289 forM_ notes (delayNoteEv (TimeSpec 0 0)) 290 forM_ notes (delayNoteEv (TimeSpec 0 0))
290 return () 291 return ()
291 292
292 where 293 where
293 onoff = bool Event.NoteOff Event.NoteOn sendOn
294 base = Event.unPitch $ triadBase triad 294 base = Event.unPitch $ triadBase triad
295 notes = (Event.NoteEv onoff . mkNote) <$> fill base 295 notes = fromVel vel <$> fill base
296 fill n = [ x + y | x <- [n, n + 7], y <- [12, -12]] 296 fill n = [ x + y | x <- [n, n + 7], y <- [12, -12]]
297 fromVel (Just v) pitch = Event.NoteEv Event.NoteOn $ Event.simpleNote (Event.Channel 0) (Event.Pitch pitch) v
298 fromVel Nothing pitch = Event.NoteEv Event.NoteOff $ Event.simpleNote (Event.Channel 0) (Event.Pitch pitch) (Event.Velocity 0)
297 299
298detectTriad :: MidiPitchSet -> Maybe Triad 300detectTriad :: MidiPitchMap -> Maybe Triad
299detectTriad pitches = listToMaybe $ concatMap f pitches 301detectTriad pitches = listToMaybe $ concatMap f (Map.keys pitches)
300 where 302 where
301 f pitch 303 f pitch
302 | not $ Set.member (addPitch 7 pitch) pitches = [] 304 | not $ Map.member (addPitch 7 pitch) pitches = []
303 | Set.member (addPitch 4 pitch) pitches = [Major $ snd pitch] -- TODO: do not just drop the channel!! 305 | Map.member (addPitch 4 pitch) pitches = [Major $ snd pitch] -- TODO: do not just drop the channel!!
304 | Set.member (addPitch 3 pitch) pitches = [Minor $ snd pitch] 306 | Map.member (addPitch 3 pitch) pitches = [Minor $ snd pitch]
305 | otherwise = [] 307 | otherwise = []
306 addPitch n (c, Event.Pitch p) = (c, Event.Pitch $ p+n) 308 addPitch n (c, Event.Pitch p) = (c, Event.Pitch $ p+n)
307 309