diff options
author | Andrew Cady <d@jerkface.net> | 2015-12-10 13:39:25 -0500 |
---|---|---|
committer | Andrew Cady <d@jerkface.net> | 2015-12-10 13:39:25 -0500 |
commit | cd9e7854db78041b7453a3d1bcfa45a95fe53604 (patch) | |
tree | 346c2e3c1dbbf2c16a69f72f81ba0ee8a965dbe6 | |
parent | 704806bc3e3ef54b3c9fbcd04c071b2af7dca59f (diff) |
Clean up triad detection somewhat
The triad detection now returns the correct type (detecting all triads
on all channels, and saving the channel). This information is still not
used; the future is to call filters for each channel separately, so
there is no point making an individual filter operate on multiple
channels simultaneously.
-rw-r--r-- | midi-dump.hs | 76 |
1 files changed, 31 insertions, 45 deletions
diff --git a/midi-dump.hs b/midi-dump.hs index 9407fae..d2b6c15 100644 --- a/midi-dump.hs +++ b/midi-dump.hs | |||
@@ -30,6 +30,7 @@ import qualified Sound.ALSA.Sequencer.RealTime as RealTime | |||
30 | 30 | ||
31 | import Midi | 31 | import Midi |
32 | import RealTimeQueue as Q hiding (null) | 32 | import RealTimeQueue as Q hiding (null) |
33 | import qualified Codec.Midi | ||
33 | 34 | ||
34 | verbose :: Bool | 35 | verbose :: Bool |
35 | verbose = False | 36 | verbose = False |
@@ -39,7 +40,8 @@ main = main' `AlsaExc.catch` handler | |||
39 | where | 40 | where |
40 | handler e = when verbose $ putStrLn $ "alsa_exception: " ++ AlsaExc.show e | 41 | handler e = when verbose $ putStrLn $ "alsa_exception: " ++ AlsaExc.show e |
41 | 42 | ||
42 | data Triad = Major Event.Pitch | Minor Event.Pitch deriving (Show, Eq) | 43 | data TriadType = Major | Minor deriving (Show, Eq) |
44 | data Triad = Triad TriadType Event.Pitch Event.Velocity deriving (Show, Eq) | ||
43 | 45 | ||
44 | data LoopState = LoopState { | 46 | data LoopState = LoopState { |
45 | _wantExit :: Bool, | 47 | _wantExit :: Bool, |
@@ -216,10 +218,10 @@ type MidiController = MidiControllerT IO | |||
216 | playRecording :: Playable p => p -> MidiController () | 218 | playRecording :: Playable p => p -> MidiController () |
217 | playRecording = playEvents . playableEvents | 219 | playRecording = playEvents . playableEvents |
218 | 220 | ||
219 | -- fixedOutputChannel :: Maybe _ | 221 | fixedOutputChannel :: Maybe Codec.Midi.Channel |
220 | fixedOutputChannel = Just 0 | 222 | fixedOutputChannel = Just 0 |
221 | 223 | ||
222 | -- setOutputChannel :: Codec.Midi.Message -> Codec.Midi.Message | 224 | setOutputChannel :: Codec.Midi.Message -> Codec.Midi.Message |
223 | setOutputChannel = case fixedOutputChannel of Just n -> setChannel n | 225 | setOutputChannel = case fixedOutputChannel of Just n -> setChannel n |
224 | Nothing -> id | 226 | Nothing -> id |
225 | 227 | ||
@@ -278,62 +280,46 @@ processMidi = do | |||
278 | 280 | ||
279 | filterTriads :: MidiPitchMap -> MidiController () | 281 | filterTriads :: MidiPitchMap -> MidiController () |
280 | filterTriads newKeys = do | 282 | filterTriads newKeys = do |
281 | let newTriad = detectTriad newKeys | 283 | let newTriad = fmap snd $ listToMaybe $ detectTriads newKeys -- TODO: handle each channel |
282 | (Just (vel, _)) = detectTriad' newKeys | ||
283 | -- vel = Event.Velocity 127 | ||
284 | oldTriad <- gets _triad | 284 | oldTriad <- gets _triad |
285 | when (newTriad /= oldTriad) $ do | 285 | when (newTriad /= oldTriad) $ do |
286 | forM_ oldTriad (sendTriadEvents Nothing) | 286 | forM_ oldTriad $ triadOff >>> sendTriadEvents |
287 | forM_ newTriad (sendTriadEvents $ Just vel) | 287 | forM_ newTriad sendTriadEvents |
288 | modify $ \s -> s { _triad = newTriad } | 288 | modify $ \s -> s { _triad = newTriad } |
289 | 289 | ||
290 | triadBase :: Triad -> Event.Pitch | 290 | triadOff :: Triad -> Triad |
291 | triadBase (Major n) = n | 291 | triadOff (Triad t p _) = Triad t p (Event.Velocity 0) |
292 | triadBase (Minor n) = n | ||
293 | 292 | ||
294 | -- TODO: set velocity based on average from triad (this requires storing that | 293 | sendTriadEvents :: Triad -> MidiController () |
295 | -- information, changing the MidiPitchMap type for one more complex than a mere | 294 | sendTriadEvents (Triad _ (Event.Pitch base) vel) = do |
296 | -- Set) | ||
297 | sendTriadEvents :: Maybe Event.Velocity -> Triad -> MidiController () | ||
298 | sendTriadEvents vel triad = do | ||
299 | liftIO $ print vel | ||
300 | forM_ notes (delayNoteEv (TimeSpec 0 0)) | 295 | forM_ notes (delayNoteEv (TimeSpec 0 0)) |
301 | return () | 296 | return () |
302 | 297 | ||
303 | where | 298 | where |
304 | base = Event.unPitch $ triadBase triad | ||
305 | notes = fromVel vel <$> fill base | 299 | notes = fromVel vel <$> fill base |
306 | fill n = [ x + y | x <- [n, n + 7], y <- [12, -12]] | 300 | fill n = [ x + y | x <- [n, n + 7], y <- [12, -12]] |
307 | fromVel (Just v) pitch = Event.NoteEv Event.NoteOn $ Event.simpleNote (Event.Channel 0) (Event.Pitch pitch) v | 301 | fromVel (Event.Velocity 0) pitch = Event.NoteEv Event.NoteOff $ Event.simpleNote (Event.Channel 0) (Event.Pitch pitch) (Event.Velocity 0) |
308 | fromVel Nothing pitch = Event.NoteEv Event.NoteOff $ Event.simpleNote (Event.Channel 0) (Event.Pitch pitch) (Event.Velocity 0) | 302 | fromVel v pitch = Event.NoteEv Event.NoteOn $ Event.simpleNote (Event.Channel 0) (Event.Pitch pitch) v |
309 | 303 | ||
310 | detectTriad' :: MidiPitchMap -> Maybe (Event.Velocity, Triad) | 304 | detectTriads :: MidiPitchMap -> [(Event.Channel, Triad)] |
311 | detectTriad' pitches = listToMaybe $ concatMap f (Map.keys pitches) | 305 | detectTriads pitches = concatMap f (Map.keys pitches) |
312 | where | 306 | where |
313 | f pitch = do | 307 | f pitch = do |
314 | let first_ = Map.lookup pitch pitches | 308 | let [first_, minor3, major3, fifth_] = map (getVelocity . getNote) [0, 3, 4, 7] |
315 | major3 = Map.lookup (addPitch 4 pitch) pitches | 309 | major = sumM [first_, major3, fifth_] |
316 | minor3 = Map.lookup (addPitch 3 pitch) pitches | 310 | minor = sumM [first_, minor3, fifth_] |
317 | fifth_ = Map.lookup (addPitch 7 pitch) pitches | 311 | getNote n = Map.lookup (addPitch n pitch) pitches |
318 | let major = foldM (fmap . (+)) (0::Int) $ (fmap . fmap) (fromIntegral . Event.unVelocity) [first_, major3, fifth_] | 312 | case (major, minor) of |
319 | let minor = foldM (fmap . (+)) (0::Int) $ (fmap . fmap) (fromIntegral . Event.unVelocity) [first_, minor3, fifth_] | 313 | (Just n, _) -> [(fst pitch, Triad Major (snd pitch) (Event.Velocity $ fromIntegral $ n `div` 3))] |
320 | case major of | 314 | (_, Just n) -> [(fst pitch, Triad Minor (snd pitch) (Event.Velocity $ fromIntegral $ n `div` 3))] |
321 | Just n -> [(Event.Velocity $ fromIntegral $ n `div` 3, Major $ snd pitch)] | 315 | _ -> [] |
322 | Nothing -> | 316 | addPitch :: Word8 -> (t, Event.Pitch) -> (t, Event.Pitch) |
323 | case minor of | 317 | addPitch n = fmap (Event.Pitch . (+ n) . Event.unPitch) |
324 | Just n -> [(Event.Velocity $ fromIntegral $ n `div` 3, Minor $ snd pitch)] | 318 | getVelocity :: Maybe Event.Velocity -> Maybe Int |
325 | Nothing -> [] | 319 | getVelocity = fmap (fromIntegral . Event.unVelocity) |
326 | addPitch n (c, Event.Pitch p) = (c, Event.Pitch $ p + n) | 320 | |
327 | 321 | sumM :: (Monad m, Num a, Foldable t) => t (m a) -> m a | |
328 | detectTriad :: MidiPitchMap -> Maybe Triad | 322 | sumM = foldM (fmap . (+)) 0 |
329 | detectTriad pitches = listToMaybe $ concatMap f (Map.keys pitches) | ||
330 | where | ||
331 | f pitch | ||
332 | | not $ Map.member (addPitch 7 pitch) pitches = [] | ||
333 | | Map.member (addPitch 4 pitch) pitches = [Major $ snd pitch] -- TODO: do not just drop the channel!! | ||
334 | | Map.member (addPitch 3 pitch) pitches = [Minor $ snd pitch] | ||
335 | | otherwise = [] | ||
336 | addPitch n (c, Event.Pitch p) = (c, Event.Pitch $ p+n) | ||
337 | 323 | ||
338 | latestEvent :: Recording -> TimeSpec | 324 | latestEvent :: Recording -> TimeSpec |
339 | latestEvent (StartRecording x) = x | 325 | latestEvent (StartRecording x) = x |