diff options
author | Andrew Cady <d@jerkface.net> | 2015-12-03 21:35:47 -0500 |
---|---|---|
committer | Andrew Cady <d@jerkface.net> | 2015-12-03 21:35:47 -0500 |
commit | 6669187d54d52b627b7dfda3dd31691b14a219f3 (patch) | |
tree | 547fc8da339069d669fb0a8b20a3329b1a67287e | |
parent | 0eb9c9ae700704332a088c394159889ecedac6e0 (diff) |
dump all midi to a database
this is too slow; there's a visible delay as the sql statement executes.
the plan is to run this in a separate thread
-rw-r--r-- | axis-of-eval.cabal | 2 | ||||
-rw-r--r-- | midi-dump.hs | 38 |
2 files changed, 33 insertions, 7 deletions
diff --git a/axis-of-eval.cabal b/axis-of-eval.cabal index 4311a85..49ee7f7 100644 --- a/axis-of-eval.cabal +++ b/axis-of-eval.cabal | |||
@@ -26,6 +26,6 @@ executable midi-dump | |||
26 | default-language: Haskell2010 | 26 | default-language: Haskell2010 |
27 | hs-source-dirs: . | 27 | hs-source-dirs: . |
28 | build-depends: | 28 | build-depends: |
29 | base, time, containers, haskore, alsa-seq, alsa-core, mtl, clock | 29 | base, time, containers, haskore, alsa-seq, alsa-core, mtl, clock, sqlite-simple, bytestring |
30 | main-is: midi-dump.hs | 30 | main-is: midi-dump.hs |
31 | other-modules: AlsaSeq | 31 | other-modules: AlsaSeq |
diff --git a/midi-dump.hs b/midi-dump.hs index 69f8480..a6fd36a 100644 --- a/midi-dump.hs +++ b/midi-dump.hs | |||
@@ -1,3 +1,6 @@ | |||
1 | {-# LANGUAGE OverloadedStrings #-} | ||
2 | {-# LANGUAGE FlexibleContexts #-} | ||
3 | |||
1 | import AlsaSeq | 4 | import AlsaSeq |
2 | import Control.Concurrent (threadDelay) | 5 | import Control.Concurrent (threadDelay) |
3 | import qualified Sound.ALSA.Exception as AlsaExc | 6 | import qualified Sound.ALSA.Exception as AlsaExc |
@@ -9,6 +12,13 @@ import Data.Maybe | |||
9 | import Data.List | 12 | import Data.List |
10 | import System.Clock | 13 | import System.Clock |
11 | 14 | ||
15 | import Control.Applicative | ||
16 | import qualified Data.ByteString as BS | ||
17 | import Database.SQLite.Simple | ||
18 | import Database.SQLite.Simple.FromRow | ||
19 | import Data.Int | ||
20 | import Data.ByteString.Char8 (pack) | ||
21 | |||
12 | verbose = False | 22 | verbose = False |
13 | 23 | ||
14 | main = main' `AlsaExc.catch` handler | 24 | main = main' `AlsaExc.catch` handler |
@@ -31,7 +41,7 @@ data LoopState = LoopState { | |||
31 | } | 41 | } |
32 | 42 | ||
33 | getAbsTime = do | 43 | getAbsTime = do |
34 | (startTime, startTimeReal, _, _, _, _, _, _) <- ask | 44 | (sqlite, startTime, startTimeReal, _, _, _, _, _, _) <- ask |
35 | now <- liftIO $ getTime Monotonic | 45 | now <- liftIO $ getTime Monotonic |
36 | return $ now - startTime + startTimeReal | 46 | return $ now - startTime + startTimeReal |
37 | 47 | ||
@@ -45,11 +55,14 @@ main' = withAlsaInit $ \h public private q publicAddr privateAddr -> do | |||
45 | startTime <- getTime Monotonic | 55 | startTime <- getTime Monotonic |
46 | startTimeReal <- getTime Realtime | 56 | startTimeReal <- getTime Realtime |
47 | 57 | ||
48 | (_, ()) <- execRWST loop (startTime, startTimeReal, h, public, private, q, publicAddr, privateAddr) (emptyLoopState startTime) | 58 | sqlite <- open "test.db" |
59 | execute_ sqlite "CREATE TABLE IF NOT EXISTS chunks (id INTEGER PRIMARY KEY, sec INTEGER, nsec INTEGER, midi BLOB)" | ||
60 | |||
61 | (_, ()) <- execRWST loop (sqlite, startTime, startTimeReal, h, public, private, q, publicAddr, privateAddr) (emptyLoopState startTime) | ||
49 | return () | 62 | return () |
50 | 63 | ||
51 | loop = do | 64 | loop = do |
52 | (startTime, startTimeReal, h, _, _, q, publicAddr, _) <- ask | 65 | (_, startTime, startTimeReal, h, _, _, q, publicAddr, _) <- ask |
53 | 66 | ||
54 | oldKeys <- gets keysDown | 67 | oldKeys <- gets keysDown |
55 | let forwardNOW = forwardNoteEvent h q publicAddr | 68 | let forwardNOW = forwardNoteEvent h q publicAddr |
@@ -62,18 +75,31 @@ loop = do | |||
62 | let newEvents = map (MidiEvent now) events | 75 | let newEvents = map (MidiEvent now) events |
63 | 76 | ||
64 | liftIO $ printChordLn newKeys | 77 | liftIO $ printChordLn newKeys |
65 | modify $ \s -> s { keysDown = newKeys, inputHistory = newEvents ++ inputHistory s } | 78 | modify $ \s -> s { keysDown = newKeys, inputHistory = newEvents ++ inputHistory s, lastTick = now } |
66 | 79 | ||
67 | when (Set.null newKeys) $ do | 80 | when (Set.null newKeys) $ do |
68 | -- hist <- gets $ takeWhile (not . isSilence) . inputHistory | 81 | chunk <- gets $ takeWhile (not . isSilence) . inputHistory |
82 | saveMidi chunk | ||
69 | hist <- gets $ filter (not . isSilence) . inputHistory | 83 | hist <- gets $ filter (not . isSilence) . inputHistory |
70 | liftIO $ print $ map (`div` 1000000) $ tsDeltas $ map getTS $ reverse hist | 84 | liftIO $ print $ map (`div` 1000000) $ tsDeltas $ map getTS $ reverse hist |
71 | liftIO $ print $ mapMaybe getMidiDesc $ reverse hist | 85 | liftIO $ print $ mapMaybe getMidiDesc $ reverse hist |
72 | modify $ \s -> s { inputHistory = Silence now:inputHistory s } | 86 | modify $ \s -> s { inputHistory = Silence now:inputHistory s } |
73 | 87 | ||
74 | modify $ \s -> s { lastTick = now } | ||
75 | loop | 88 | loop |
76 | 89 | ||
90 | data Chunk = Chunk Int64 Int64 BS.ByteString | ||
91 | instance FromRow Chunk where | ||
92 | fromRow = Chunk <$> field <*> field <*> field | ||
93 | instance ToRow Chunk where | ||
94 | toRow (Chunk s ns b) = toRow (s, ns, b) | ||
95 | |||
96 | saveMidi chunk = do | ||
97 | (sqlite, _, _, _, _, _, _, _, _) <- ask | ||
98 | (TimeSpec s ns) <- gets lastTick | ||
99 | let bytes = pack $ show chunk | ||
100 | liftIO $ execute sqlite "INSERT INTO chunks (sec, nsec, midi) VALUES (?,?,?)" (Chunk s ns bytes) | ||
101 | return () | ||
102 | |||
77 | getMidiDesc :: EVENT -> Maybe String | 103 | getMidiDesc :: EVENT -> Maybe String |
78 | getMidiDesc (MidiEvent _ (Event.Cons _ _ _ _ _ _ (Event.NoteEv Event.NoteOn ev))) = return $ ("on:" ++) $ showPitch $ unPitch $ Event.noteNote ev | 104 | getMidiDesc (MidiEvent _ (Event.Cons _ _ _ _ _ _ (Event.NoteEv Event.NoteOn ev))) = return $ ("on:" ++) $ showPitch $ unPitch $ Event.noteNote ev |
79 | getMidiDesc (MidiEvent _ (Event.Cons _ _ _ _ _ _ (Event.NoteEv Event.NoteOff ev))) = return $ ("off:" ++) $ showPitch $ unPitch $ Event.noteNote ev | 105 | getMidiDesc (MidiEvent _ (Event.Cons _ _ _ _ _ _ (Event.NoteEv Event.NoteOff ev))) = return $ ("off:" ++) $ showPitch $ unPitch $ Event.noteNote ev |