diff options
author | Andrew Cady <d@jerkface.net> | 2015-12-04 11:12:17 -0500 |
---|---|---|
committer | Andrew Cady <d@jerkface.net> | 2015-12-04 11:12:17 -0500 |
commit | 2c7fa00813d51cf5a8436b459b62f2d343b75cde (patch) | |
tree | 3dbc2e26f5c4eeb8f1a872680e153a673729263f | |
parent | a65931fd13a4c7f50b3bc5f99a8d80aacd3503d0 (diff) |
Change database schema
Start and end times, and leading silence duration, are all available
through SQL.
-rw-r--r-- | midi-dump.hs | 43 |
1 files changed, 31 insertions, 12 deletions
diff --git a/midi-dump.hs b/midi-dump.hs index e950653..c47e8bf 100644 --- a/midi-dump.hs +++ b/midi-dump.hs | |||
@@ -1,4 +1,5 @@ | |||
1 | {-# LANGUAGE FlexibleContexts #-} | 1 | {-# LANGUAGE FlexibleContexts #-} |
2 | {-# LANGUAGE FlexibleInstances #-} | ||
2 | {-# LANGUAGE OverloadedStrings #-} | 3 | {-# LANGUAGE OverloadedStrings #-} |
3 | 4 | ||
4 | import AlsaSeq | 5 | import AlsaSeq |
@@ -40,6 +41,8 @@ data Recording = Recording { | |||
40 | _recordingEvents :: RecordedEvents | 41 | _recordingEvents :: RecordedEvents |
41 | } | 42 | } |
42 | 43 | ||
44 | data FinishedRecording = FinishedRecording Recording TimeSpec | ||
45 | |||
43 | recordEvents :: Recording -> RecordedEvents -> Recording | 46 | recordEvents :: Recording -> RecordedEvents -> Recording |
44 | recordEvents (Recording s orig) new = Recording s (new ++ orig) | 47 | recordEvents (Recording s orig) new = Recording s (new ++ orig) |
45 | 48 | ||
@@ -53,7 +56,7 @@ data LoopState = LoopState { | |||
53 | initializeState now = LoopState False Set.empty (emptyRecording now) now | 56 | initializeState now = LoopState False Set.empty (emptyRecording now) now |
54 | 57 | ||
55 | data LoopEnv = LoopEnv { | 58 | data LoopEnv = LoopEnv { |
56 | _saver :: Chan Recording, | 59 | _saver :: Chan FinishedRecording, |
57 | _sqlite :: Connection, | 60 | _sqlite :: Connection, |
58 | _startTime :: TimeSpec, | 61 | _startTime :: TimeSpec, |
59 | _startTimeReal :: TimeSpec, | 62 | _startTimeReal :: TimeSpec, |
@@ -73,6 +76,16 @@ getAbsTime = do | |||
73 | now <- liftIO $ getTime Monotonic | 76 | now <- liftIO $ getTime Monotonic |
74 | return $ now - startTime + startTimeReal | 77 | return $ now - startTime + startTimeReal |
75 | 78 | ||
79 | createTable = fromString $ concat | ||
80 | ["CREATE TABLE IF NOT EXISTS axis_input", | ||
81 | " (id INTEGER PRIMARY KEY,", | ||
82 | " start_sec INTEGER,", | ||
83 | " start_nsec INTEGER,", | ||
84 | " end_sec INTEGER,", | ||
85 | " end_nsec INTEGER,", | ||
86 | " leading_silence INTEGER,", | ||
87 | " midi BLOB)"] | ||
88 | |||
76 | main' = withAlsaInit $ \h public private q publicAddr privateAddr -> do | 89 | main' = withAlsaInit $ \h public private q publicAddr privateAddr -> do |
77 | cmdlineAlsaConnect h public | 90 | cmdlineAlsaConnect h public |
78 | 91 | ||
@@ -81,7 +94,7 @@ main' = withAlsaInit $ \h public private q publicAddr privateAddr -> do | |||
81 | startTimeReal <- getTime Realtime | 94 | startTimeReal <- getTime Realtime |
82 | 95 | ||
83 | sqlite <- open "test.db" | 96 | sqlite <- open "test.db" |
84 | execute_ sqlite "CREATE TABLE IF NOT EXISTS axis_input (id INTEGER PRIMARY KEY, sec INTEGER, nsec INTEGER, silence INTEGER, midi BLOB)" | 97 | execute_ sqlite createTable |
85 | saver <- startSaver sqlite | 98 | saver <- startSaver sqlite |
86 | lineReader <- startLineReader | 99 | lineReader <- startLineReader |
87 | 100 | ||
@@ -134,16 +147,23 @@ startLineReader = do | |||
134 | thread <- liftIO $ forkIO (forever $ getLine >>= putMVar mv) | 147 | thread <- liftIO $ forkIO (forever $ getLine >>= putMVar mv) |
135 | return mv | 148 | return mv |
136 | 149 | ||
137 | data Chunk = Chunk Int64 Int64 Int64 {- duration of silence in nanoseconds -} BS.ByteString | 150 | data Chunk = Chunk Int64 Int64 Int64 Int64 Int64 BS.ByteString |
138 | instance FromRow Chunk where | 151 | instance FromRow Chunk where |
139 | fromRow = Chunk <$> field <*> field <*> field <*> field | 152 | fromRow = Chunk <$> field <*> field <*> field <*> field <*> field <*> field |
140 | instance ToRow Chunk where | 153 | instance ToRow Chunk where |
141 | toRow (Chunk s ns b pre) = toRow (s, ns, b, pre) | 154 | toRow (Chunk s ns s' ns' d m) = toRow (s, ns, s', ns', d, m) |
155 | |||
156 | data Chunkable = MkChunk FinishedRecording TimeSpec | ||
157 | instance ToRow Chunkable where | ||
158 | toRow (MkChunk reco ts) = toRow (s, ns, s', ns', leadingSilence :: Int64, pack $ show midi) | ||
159 | where | ||
160 | (FinishedRecording (Recording start@(TimeSpec s ns) midi) (TimeSpec s' ns')) = reco | ||
161 | leadingSilence = fromIntegral $ timeSpecAsNanoSecs $ ts - start | ||
142 | 162 | ||
143 | saveMidi recording = do | 163 | saveMidi recording = do |
144 | saver <- asks _saver | 164 | saver <- asks _saver |
145 | (TimeSpec s ns) <- gets lastTick | 165 | end <- gets lastTick |
146 | liftIO $ writeChan saver recording | 166 | liftIO $ writeChan saver $ FinishedRecording recording end |
147 | 167 | ||
148 | startSaver sqlite = do | 168 | startSaver sqlite = do |
149 | chan <- liftIO newChan | 169 | chan <- liftIO newChan |
@@ -151,11 +171,10 @@ startSaver sqlite = do | |||
151 | return chan | 171 | return chan |
152 | where | 172 | where |
153 | saver chan = forever $ do | 173 | saver chan = forever $ do |
154 | (Recording silenceStart events) <- readChan chan | 174 | reco@(FinishedRecording (Recording _ events) _) <- readChan chan |
155 | let bytes = pack $ show events | 175 | let start = fst $ head events |
156 | ts@(TimeSpec s ns) = fst $ head events | 176 | sqlInsert = "INSERT INTO axis_input (start_sec, start_nsec, end_sec, end_nsec, leading_silence, midi) VALUES (?,?,?,?,?,?)" |
157 | silence = fromIntegral $ timeSpecAsNanoSecs $ ts - silenceStart | 177 | liftIO $ execute sqlite sqlInsert (MkChunk reco start) |
158 | liftIO $ execute sqlite "INSERT INTO axis_input (sec, nsec, silence, midi) VALUES (?,?,?,?)" (Chunk s ns silence bytes) | ||
159 | return () | 178 | return () |
160 | 179 | ||
161 | 180 | ||