summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2015-12-05 09:21:11 -0500
committerAndrew Cady <d@jerkface.net>2015-12-05 11:45:44 -0500
commit7477265c3c91341bcc96181fd876de0231bd667f (patch)
tree89319b262a86a55069563b2d5cde637beb4c5004
parent9a15e58ff786aaef0fbb673d14de562f37bbc596 (diff)
start to move midi serialization into separate file
-rw-r--r--Midi.hs59
-rw-r--r--axis-of-eval.cabal3
-rw-r--r--midi-dump.hs51
-rw-r--r--stack.yaml2
4 files changed, 72 insertions, 43 deletions
diff --git a/Midi.hs b/Midi.hs
new file mode 100644
index 0000000..4609d04
--- /dev/null
+++ b/Midi.hs
@@ -0,0 +1,59 @@
1module Midi where
2import BasePrelude
3import qualified Data.ByteString as BS
4import Data.ByteString.Char8 (pack)
5import Prelude hiding (id, (.))
6-- import Sound.MIDI.ALSA
7import System.Clock
8import Database.SQLite.Simple
9import Database.SQLite.Simple.FromRow ()
10
11import qualified Sound.ALSA.Sequencer.Event as Event
12
13-- import qualified Sound.ALSA.Sequencer
14-- import qualified Sound.ALSA.Sequencer.Address
15-- import qualified Sound.ALSA.Sequencer.Port
16-- import qualified Sound.ALSA.Sequencer.Queue
17-- import qualified Sound.ALSA.Sequencer.Time as Time
18-- import qualified Sound.ALSA.Sequencer.RealTime as RealTime
19
20type RecordedEvent = (TimeSpec, Event.T)
21
22data Recording = StartRecording TimeSpec |
23 RecordingInProgress TimeSpec TimeSpec [RecordedEvent]
24 deriving Show
25
26data CompleteRecording = CompleteRecording {
27 _recStart :: TimeSpec,
28 _recEnd :: TimeSpec,
29 _recFirst :: TimeSpec,
30 _recLast :: TimeSpec,
31 _recEvents :: [RecordedEvent]
32} deriving Show
33
34instance FromRow CompleteRecording where
35 fromRow = cons <$> field <*> field <*> field <*> field <*> field <*> field <*> field <*> field <*> field
36 where
37 cons a a' b b' c c' d d' z = CompleteRecording (TimeSpec a a') (TimeSpec b b') (TimeSpec c c') (TimeSpec d d') (bytesToMidi z)
38
39instance ToRow CompleteRecording where
40 toRow reco = toRow (s, ns, s', ns', s'', ns'', s''', ns''', midiToBytes midi)
41 where
42 (CompleteRecording (TimeSpec s ns) (TimeSpec s' ns') (TimeSpec s'' ns'') (TimeSpec s''' ns''') midi) = reco
43
44
45recordEvents :: Recording -> [RecordedEvent]-> Recording
46recordEvents (RecordingInProgress x y orig) new = RecordingInProgress x y $ new ++ orig
47recordEvents i@(StartRecording _) [] = i
48recordEvents (StartRecording x) new@(_:_) = RecordingInProgress x y new
49 where y = fst $ last new
50
51stopRecording :: Recording -> TimeSpec -> Maybe CompleteRecording
52stopRecording (RecordingInProgress x y ls@((z,_):_)) end = Just $ CompleteRecording x end y z ls
53stopRecording _ _ = Nothing
54
55
56midiToBytes :: [RecordedEvent] -> BS.ByteString
57midiToBytes = pack . show
58bytesToMidi :: BS.ByteString -> [RecordedEvent]
59bytesToMidi = undefined
diff --git a/axis-of-eval.cabal b/axis-of-eval.cabal
index f69d3f5..acafc72 100644
--- a/axis-of-eval.cabal
+++ b/axis-of-eval.cabal
@@ -26,7 +26,8 @@ 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, sqlite-simple, bytestring, base-prelude 29 base, time, containers, haskore, alsa-seq, alsa-core, mtl, clock,
30 sqlite-simple, bytestring, base-prelude, midi-alsa, midi
30 main-is: midi-dump.hs 31 main-is: midi-dump.hs
31 other-modules: AlsaSeq 32 other-modules: AlsaSeq
32 ghc-options: -threaded -W -Wall -O2 33 ghc-options: -threaded -W -Wall -O2
diff --git a/midi-dump.hs b/midi-dump.hs
index f053e28..07281f5 100644
--- a/midi-dump.hs
+++ b/midi-dump.hs
@@ -14,8 +14,6 @@ import qualified Sound.ALSA.Sequencer.Event as Event
14import System.Clock 14import System.Clock
15 15
16import Control.Applicative 16import Control.Applicative
17import qualified Data.ByteString as BS
18import Data.ByteString.Char8 (pack)
19import Data.Int 17import Data.Int
20import Database.SQLite.Simple 18import Database.SQLite.Simple
21import Database.SQLite.Simple.FromRow () 19import Database.SQLite.Simple.FromRow ()
@@ -31,6 +29,8 @@ import qualified Sound.ALSA.Sequencer.Queue
31import qualified Sound.ALSA.Sequencer.Time as Time 29import qualified Sound.ALSA.Sequencer.Time as Time
32import qualified Sound.ALSA.Sequencer.RealTime as RealTime 30import qualified Sound.ALSA.Sequencer.RealTime as RealTime
33 31
32import Midi
33
34verbose :: Bool 34verbose :: Bool
35verbose = False 35verbose = False
36 36
@@ -39,30 +39,6 @@ main = main' `AlsaExc.catch` handler
39 where 39 where
40 handler e = when verbose $ putStrLn $ "alsa_exception: " ++ AlsaExc.show e 40 handler e = when verbose $ putStrLn $ "alsa_exception: " ++ AlsaExc.show e
41 41
42type RecordedEvent = (TimeSpec, Event.T)
43
44data Recording = StartRecording TimeSpec |
45 RecordingInProgress TimeSpec TimeSpec [RecordedEvent]
46
47data CompleteRecording = CompleteRecording {
48 _recStart :: TimeSpec,
49 _recEnd :: TimeSpec,
50 _recFirst :: TimeSpec,
51 _recLast :: TimeSpec,
52 _recEvents :: [RecordedEvent]
53}
54
55recordEvents :: Recording -> [RecordedEvent]-> Recording
56recordEvents (RecordingInProgress x y orig) new = RecordingInProgress x y $ new ++ orig
57recordEvents i@(StartRecording _) [] = i
58recordEvents (StartRecording x) new@(_:_) = RecordingInProgress x y new
59 where y = fst $ last new
60
61stopRecording :: Recording -> TimeSpec -> Maybe CompleteRecording
62stopRecording (RecordingInProgress x y ls@((z,_):_)) end = Just $ CompleteRecording x end y z ls
63stopRecording _ _ = Nothing
64
65
66data LoopState = LoopState { 42data LoopState = LoopState {
67 _wantExit :: Bool, 43 _wantExit :: Bool,
68 keysDown :: MidiPitchSet, 44 keysDown :: MidiPitchSet,
@@ -176,7 +152,7 @@ playNoteEv :: Event.Data -> RWST LoopEnv () LoopState IO ()
176playNoteEv nevdata = do 152playNoteEv nevdata = do
177 ms <- getMidiSender 153 ms <- getMidiSender
178 publicAddr <- asks _publicAddr 154 publicAddr <- asks _publicAddr
179 liftIO $ ms $ Event.simple publicAddr nevdata `delayEvent` (10 * 10^(9::Int)) 155 liftIO $ ms $ Event.simple publicAddr nevdata `delayEvent` (2 * 10^(9::Int))
180 156
181_whenFlag :: forall (m :: * -> *) s. MonadState s m => (s -> Bool) -> m () -> m () 157_whenFlag :: forall (m :: * -> *) s. MonadState s m => (s -> Bool) -> m () -> m ()
182_whenFlag flag f = gets flag >>= flip when f 158_whenFlag flag f = gets flag >>= flip when f
@@ -188,6 +164,12 @@ processCommand "C" = do
188 let mkNote pitch = Event.simpleNote (Event.Channel 0) (Event.Pitch pitch) (Event.Velocity 128) 164 let mkNote pitch = Event.simpleNote (Event.Channel 0) (Event.Pitch pitch) (Event.Velocity 128)
189 let notes = (Event.NoteEv Event.NoteOn . mkNote) <$> [60, 64, 67] 165 let notes = (Event.NoteEv Event.NoteOn . mkNote) <$> [60, 64, 67]
190 modify $ \s -> s { _playNOW = notes } 166 modify $ \s -> s { _playNOW = notes }
167processCommand "C'" = do
168 -- changing the duration seems to do nothing
169 let mkNote pitch = Event.simpleNote (Event.Channel 0) (Event.Pitch pitch) (Event.Velocity 128)
170 setDuration d note = note { Event.noteDuration = Event.Duration d }
171 let notes = (Event.NoteEv Event.NoteOn . setDuration 4290000000 . mkNote) <$> [60, 64, 67]
172 modify $ \s -> s { _playNOW = notes }
191processCommand str = liftIO $ putStrLn $ "Unknown command: " ++ str 173processCommand str = liftIO $ putStrLn $ "Unknown command: " ++ str
192 174
193getMidiSender :: RWST LoopEnv () LoopState IO MidiHook 175getMidiSender :: RWST LoopEnv () LoopState IO MidiHook
@@ -239,21 +221,6 @@ startLineReader = do
239 _thread <- liftIO $ forkIO (forever $ tryIOError getLine >>= either (const $ putMVar mv "exit") (putMVar mv)) 221 _thread <- liftIO $ forkIO (forever $ tryIOError getLine >>= either (const $ putMVar mv "exit") (putMVar mv))
240 return mv 222 return mv
241 223
242midiToBytes :: [RecordedEvent] -> BS.ByteString
243midiToBytes = pack . show
244bytesToMidi :: BS.ByteString -> [RecordedEvent]
245bytesToMidi = undefined
246
247instance FromRow CompleteRecording where
248 fromRow = cons <$> field <*> field <*> field <*> field <*> field <*> field <*> field <*> field <*> field
249 where
250 cons a a' b b' c c' d d' z = CompleteRecording (TimeSpec a a') (TimeSpec b b') (TimeSpec c c') (TimeSpec d d') (bytesToMidi z)
251
252instance ToRow CompleteRecording where
253 toRow reco = toRow (s, ns, s', ns', s'', ns'', s''', ns''', midiToBytes midi)
254 where
255 (CompleteRecording (TimeSpec s ns) (TimeSpec s' ns') (TimeSpec s'' ns'') (TimeSpec s''' ns''') midi) = reco
256
257saveMidi :: forall (m :: * -> *). (MonadIO m, MonadState LoopState m, MonadReader LoopEnv m) => Recording -> m () 224saveMidi :: forall (m :: * -> *). (MonadIO m, MonadState LoopState m, MonadReader LoopEnv m) => Recording -> m ()
258saveMidi recording = do 225saveMidi recording = do
259 saver <- asks _saver 226 saver <- asks _saver
diff --git a/stack.yaml b/stack.yaml
index abcd766..0fa3f39 100644
--- a/stack.yaml
+++ b/stack.yaml
@@ -21,5 +21,7 @@ extra-deps:
21- monoid-transformer-0.0.3 21- monoid-transformer-0.0.3
22- storable-record-0.0.3 22- storable-record-0.0.3
23 23
24- midi-alsa-0.2.1
25
24resolver: lts-3.7 26resolver: lts-3.7
25system-ghc: false 27system-ghc: false