diff options
author | Andrew Cady <d@jerkface.net> | 2015-12-05 09:21:11 -0500 |
---|---|---|
committer | Andrew Cady <d@jerkface.net> | 2015-12-05 11:45:44 -0500 |
commit | 7477265c3c91341bcc96181fd876de0231bd667f (patch) | |
tree | 89319b262a86a55069563b2d5cde637beb4c5004 | |
parent | 9a15e58ff786aaef0fbb673d14de562f37bbc596 (diff) |
start to move midi serialization into separate file
-rw-r--r-- | Midi.hs | 59 | ||||
-rw-r--r-- | axis-of-eval.cabal | 3 | ||||
-rw-r--r-- | midi-dump.hs | 51 | ||||
-rw-r--r-- | stack.yaml | 2 |
4 files changed, 72 insertions, 43 deletions
@@ -0,0 +1,59 @@ | |||
1 | module Midi where | ||
2 | import BasePrelude | ||
3 | import qualified Data.ByteString as BS | ||
4 | import Data.ByteString.Char8 (pack) | ||
5 | import Prelude hiding (id, (.)) | ||
6 | -- import Sound.MIDI.ALSA | ||
7 | import System.Clock | ||
8 | import Database.SQLite.Simple | ||
9 | import Database.SQLite.Simple.FromRow () | ||
10 | |||
11 | import 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 | |||
20 | type RecordedEvent = (TimeSpec, Event.T) | ||
21 | |||
22 | data Recording = StartRecording TimeSpec | | ||
23 | RecordingInProgress TimeSpec TimeSpec [RecordedEvent] | ||
24 | deriving Show | ||
25 | |||
26 | data CompleteRecording = CompleteRecording { | ||
27 | _recStart :: TimeSpec, | ||
28 | _recEnd :: TimeSpec, | ||
29 | _recFirst :: TimeSpec, | ||
30 | _recLast :: TimeSpec, | ||
31 | _recEvents :: [RecordedEvent] | ||
32 | } deriving Show | ||
33 | |||
34 | instance 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 | |||
39 | instance 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 | |||
45 | recordEvents :: Recording -> [RecordedEvent]-> Recording | ||
46 | recordEvents (RecordingInProgress x y orig) new = RecordingInProgress x y $ new ++ orig | ||
47 | recordEvents i@(StartRecording _) [] = i | ||
48 | recordEvents (StartRecording x) new@(_:_) = RecordingInProgress x y new | ||
49 | where y = fst $ last new | ||
50 | |||
51 | stopRecording :: Recording -> TimeSpec -> Maybe CompleteRecording | ||
52 | stopRecording (RecordingInProgress x y ls@((z,_):_)) end = Just $ CompleteRecording x end y z ls | ||
53 | stopRecording _ _ = Nothing | ||
54 | |||
55 | |||
56 | midiToBytes :: [RecordedEvent] -> BS.ByteString | ||
57 | midiToBytes = pack . show | ||
58 | bytesToMidi :: BS.ByteString -> [RecordedEvent] | ||
59 | bytesToMidi = 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 | |||
14 | import System.Clock | 14 | import System.Clock |
15 | 15 | ||
16 | import Control.Applicative | 16 | import Control.Applicative |
17 | import qualified Data.ByteString as BS | ||
18 | import Data.ByteString.Char8 (pack) | ||
19 | import Data.Int | 17 | import Data.Int |
20 | import Database.SQLite.Simple | 18 | import Database.SQLite.Simple |
21 | import Database.SQLite.Simple.FromRow () | 19 | import Database.SQLite.Simple.FromRow () |
@@ -31,6 +29,8 @@ import qualified Sound.ALSA.Sequencer.Queue | |||
31 | import qualified Sound.ALSA.Sequencer.Time as Time | 29 | import qualified Sound.ALSA.Sequencer.Time as Time |
32 | import qualified Sound.ALSA.Sequencer.RealTime as RealTime | 30 | import qualified Sound.ALSA.Sequencer.RealTime as RealTime |
33 | 31 | ||
32 | import Midi | ||
33 | |||
34 | verbose :: Bool | 34 | verbose :: Bool |
35 | verbose = False | 35 | verbose = 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 | ||
42 | type RecordedEvent = (TimeSpec, Event.T) | ||
43 | |||
44 | data Recording = StartRecording TimeSpec | | ||
45 | RecordingInProgress TimeSpec TimeSpec [RecordedEvent] | ||
46 | |||
47 | data CompleteRecording = CompleteRecording { | ||
48 | _recStart :: TimeSpec, | ||
49 | _recEnd :: TimeSpec, | ||
50 | _recFirst :: TimeSpec, | ||
51 | _recLast :: TimeSpec, | ||
52 | _recEvents :: [RecordedEvent] | ||
53 | } | ||
54 | |||
55 | recordEvents :: Recording -> [RecordedEvent]-> Recording | ||
56 | recordEvents (RecordingInProgress x y orig) new = RecordingInProgress x y $ new ++ orig | ||
57 | recordEvents i@(StartRecording _) [] = i | ||
58 | recordEvents (StartRecording x) new@(_:_) = RecordingInProgress x y new | ||
59 | where y = fst $ last new | ||
60 | |||
61 | stopRecording :: Recording -> TimeSpec -> Maybe CompleteRecording | ||
62 | stopRecording (RecordingInProgress x y ls@((z,_):_)) end = Just $ CompleteRecording x end y z ls | ||
63 | stopRecording _ _ = Nothing | ||
64 | |||
65 | |||
66 | data LoopState = LoopState { | 42 | data 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 () | |||
176 | playNoteEv nevdata = do | 152 | playNoteEv 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 } |
167 | processCommand "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 } | ||
191 | processCommand str = liftIO $ putStrLn $ "Unknown command: " ++ str | 173 | processCommand str = liftIO $ putStrLn $ "Unknown command: " ++ str |
192 | 174 | ||
193 | getMidiSender :: RWST LoopEnv () LoopState IO MidiHook | 175 | getMidiSender :: 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 | ||
242 | midiToBytes :: [RecordedEvent] -> BS.ByteString | ||
243 | midiToBytes = pack . show | ||
244 | bytesToMidi :: BS.ByteString -> [RecordedEvent] | ||
245 | bytesToMidi = undefined | ||
246 | |||
247 | instance 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 | |||
252 | instance 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 | |||
257 | saveMidi :: forall (m :: * -> *). (MonadIO m, MonadState LoopState m, MonadReader LoopEnv m) => Recording -> m () | 224 | saveMidi :: forall (m :: * -> *). (MonadIO m, MonadState LoopState m, MonadReader LoopEnv m) => Recording -> m () |
258 | saveMidi recording = do | 225 | saveMidi recording = do |
259 | saver <- asks _saver | 226 | saver <- asks _saver |
@@ -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 | |||
24 | resolver: lts-3.7 | 26 | resolver: lts-3.7 |
25 | system-ghc: false | 27 | system-ghc: false |