summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2015-12-03 21:35:47 -0500
committerAndrew Cady <d@jerkface.net>2015-12-03 21:35:47 -0500
commit6669187d54d52b627b7dfda3dd31691b14a219f3 (patch)
tree547fc8da339069d669fb0a8b20a3329b1a67287e
parent0eb9c9ae700704332a088c394159889ecedac6e0 (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.cabal2
-rw-r--r--midi-dump.hs38
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
1import AlsaSeq 4import AlsaSeq
2import Control.Concurrent (threadDelay) 5import Control.Concurrent (threadDelay)
3import qualified Sound.ALSA.Exception as AlsaExc 6import qualified Sound.ALSA.Exception as AlsaExc
@@ -9,6 +12,13 @@ import Data.Maybe
9import Data.List 12import Data.List
10import System.Clock 13import System.Clock
11 14
15import Control.Applicative
16import qualified Data.ByteString as BS
17import Database.SQLite.Simple
18import Database.SQLite.Simple.FromRow
19import Data.Int
20import Data.ByteString.Char8 (pack)
21
12verbose = False 22verbose = False
13 23
14main = main' `AlsaExc.catch` handler 24main = main' `AlsaExc.catch` handler
@@ -31,7 +41,7 @@ data LoopState = LoopState {
31} 41}
32 42
33getAbsTime = do 43getAbsTime = 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
51loop = do 64loop = 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
90data Chunk = Chunk Int64 Int64 BS.ByteString
91instance FromRow Chunk where
92 fromRow = Chunk <$> field <*> field <*> field
93instance ToRow Chunk where
94 toRow (Chunk s ns b) = toRow (s, ns, b)
95
96saveMidi 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
77getMidiDesc :: EVENT -> Maybe String 103getMidiDesc :: EVENT -> Maybe String
78getMidiDesc (MidiEvent _ (Event.Cons _ _ _ _ _ _ (Event.NoteEv Event.NoteOn ev))) = return $ ("on:" ++) $ showPitch $ unPitch $ Event.noteNote ev 104getMidiDesc (MidiEvent _ (Event.Cons _ _ _ _ _ _ (Event.NoteEv Event.NoteOn ev))) = return $ ("on:" ++) $ showPitch $ unPitch $ Event.noteNote ev
79getMidiDesc (MidiEvent _ (Event.Cons _ _ _ _ _ _ (Event.NoteEv Event.NoteOff ev))) = return $ ("off:" ++) $ showPitch $ unPitch $ Event.noteNote ev 105getMidiDesc (MidiEvent _ (Event.Cons _ _ _ _ _ _ (Event.NoteEv Event.NoteOff ev))) = return $ ("off:" ++) $ showPitch $ unPitch $ Event.noteNote ev