diff options
Diffstat (limited to 'midi-dump.hs')
-rw-r--r-- | midi-dump.hs | 42 |
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 | |||
8 | import Control.Monad.RWS.Strict | 8 | import Control.Monad.RWS.Strict |
9 | import Data.List | 9 | import Data.List |
10 | import Data.Maybe | 10 | import Data.Maybe |
11 | import qualified Data.Set as Set | 11 | import qualified Data.Map.Strict as Map |
12 | import qualified Sound.ALSA.Exception as AlsaExc | 12 | import qualified Sound.ALSA.Exception as AlsaExc |
13 | import qualified Sound.ALSA.Sequencer.Event as Event | 13 | import qualified Sound.ALSA.Sequencer.Event as Event |
14 | import System.Clock | 14 | import System.Clock |
@@ -43,7 +43,7 @@ data Triad = Major Event.Pitch | Minor Event.Pitch deriving (Show, Eq) | |||
43 | 43 | ||
44 | data LoopState = LoopState { | 44 | data 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 | ||
54 | initializeState :: TimeSpec -> LoopState | 54 | initializeState :: TimeSpec -> LoopState |
55 | initializeState now = LoopState False Set.empty Nothing createQueue (StartRecording now) (StartRecording now) now | 55 | initializeState now = LoopState False Map.empty Nothing createQueue (StartRecording now) (StartRecording now) now |
56 | 56 | ||
57 | data LoopEnv = LoopEnv { | 57 | data 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 | ||
271 | filterTriads :: MidiPitchSet -> MidiController () | 271 | filterTriads :: MidiPitchMap -> MidiController () |
272 | filterTriads newKeys = do | 272 | filterTriads 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 | ||
280 | triadBase :: Triad -> Event.Pitch | 281 | triadBase :: Triad -> Event.Pitch |
@@ -282,26 +283,27 @@ triadBase (Major n) = n | |||
282 | triadBase (Minor n) = n | 283 | triadBase (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) |
287 | sendTriadEvents :: Bool -> Triad -> MidiController () | 288 | sendTriadEvents :: Maybe Event.Velocity -> Triad -> MidiController () |
288 | sendTriadEvents sendOn triad = do | 289 | sendTriadEvents 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 | ||
298 | detectTriad :: MidiPitchSet -> Maybe Triad | 300 | detectTriad :: MidiPitchMap -> Maybe Triad |
299 | detectTriad pitches = listToMaybe $ concatMap f pitches | 301 | detectTriad 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 | ||