diff options
author | Andrew Cady <d@jerkface.net> | 2015-12-06 07:53:56 -0500 |
---|---|---|
committer | Andrew Cady <d@jerkface.net> | 2015-12-06 07:53:56 -0500 |
commit | 52bc07bc5a70ac43b0e1070d7fbb0d468d4e8139 (patch) | |
tree | 98057e48c24d40bc6d520bc420b44cc2345a72fe | |
parent | b4f30bddff95f56d3418db0a130331d9666a706e (diff) |
Store recordings as Sound.MIDI.Message.T
My intent in doing this was to have a format suitable for reading
and writing to the database; the old format (using "show" on the
Sound.ALSA.Sequencer.Event.T) could not be read back.
Unfortunately, this new format cannot be read back _OR WRITTEN_!
At least not without more conversion (of my list of pairs into a
Thielemann's specialized event-list).
My new plan is to use HCodec's Codec.Midi.Message instead. But I'll
commit this before I get to that.
-rw-r--r-- | Midi.hs | 39 | ||||
-rw-r--r-- | midi-dump.hs | 4 |
2 files changed, 32 insertions, 11 deletions
@@ -1,7 +1,8 @@ | |||
1 | {-# LANGUAGE ExplicitForAll #-} | ||
1 | module Midi where | 2 | module Midi where |
2 | import BasePrelude | 3 | import BasePrelude |
3 | import qualified Data.ByteString as BS | 4 | import qualified Data.ByteString as BS |
4 | import Data.ByteString.Char8 (pack) | 5 | -- import Data.ByteString.Char8 (pack) |
5 | import Prelude hiding (id, (.)) | 6 | import Prelude hiding (id, (.)) |
6 | -- import Sound.MIDI.ALSA | 7 | -- import Sound.MIDI.ALSA |
7 | import System.Clock | 8 | import System.Clock |
@@ -9,6 +10,10 @@ import Database.SQLite.Simple | |||
9 | import Database.SQLite.Simple.FromRow () | 10 | import Database.SQLite.Simple.FromRow () |
10 | 11 | ||
11 | import qualified Sound.ALSA.Sequencer.Event as Event | 12 | import qualified Sound.ALSA.Sequencer.Event as Event |
13 | -- import Sound.MIDI.ALSA | ||
14 | import Sound.MIDI.ALSA.Query | ||
15 | import qualified Sound.MIDI.ALSA.Construct as Construct | ||
16 | import Sound.MIDI.Message | ||
12 | 17 | ||
13 | -- import qualified Sound.ALSA.Sequencer | 18 | -- import qualified Sound.ALSA.Sequencer |
14 | -- import qualified Sound.ALSA.Sequencer.Address | 19 | -- import qualified Sound.ALSA.Sequencer.Address |
@@ -17,11 +22,11 @@ import qualified Sound.ALSA.Sequencer.Event as Event | |||
17 | -- import qualified Sound.ALSA.Sequencer.Time as Time | 22 | -- import qualified Sound.ALSA.Sequencer.Time as Time |
18 | -- import qualified Sound.ALSA.Sequencer.RealTime as RealTime | 23 | -- import qualified Sound.ALSA.Sequencer.RealTime as RealTime |
19 | 24 | ||
20 | type RecordedEvent = (TimeSpec, Event.T) | 25 | -- type RecordedEvent = (TimeSpec, Event.Data) |
26 | type RecordedEvent = (TimeSpec, Sound.MIDI.Message.T) | ||
21 | 27 | ||
22 | data Recording = StartRecording TimeSpec | | 28 | data Recording = StartRecording TimeSpec | |
23 | RecordingInProgress TimeSpec TimeSpec [RecordedEvent] | 29 | RecordingInProgress TimeSpec TimeSpec [RecordedEvent] |
24 | deriving Show | ||
25 | 30 | ||
26 | data CompleteRecording = CompleteRecording { | 31 | data CompleteRecording = CompleteRecording { |
27 | _recStart :: TimeSpec, | 32 | _recStart :: TimeSpec, |
@@ -29,7 +34,7 @@ data CompleteRecording = CompleteRecording { | |||
29 | _recFirst :: TimeSpec, | 34 | _recFirst :: TimeSpec, |
30 | _recLast :: TimeSpec, | 35 | _recLast :: TimeSpec, |
31 | _recEvents :: [RecordedEvent] | 36 | _recEvents :: [RecordedEvent] |
32 | } deriving Show | 37 | } |
33 | 38 | ||
34 | instance FromRow CompleteRecording where | 39 | instance FromRow CompleteRecording where |
35 | fromRow = cons <$> field <*> field <*> field <*> field <*> field <*> field <*> field <*> field <*> field | 40 | fromRow = cons <$> field <*> field <*> field <*> field <*> field <*> field <*> field <*> field <*> field |
@@ -41,19 +46,35 @@ instance ToRow CompleteRecording where | |||
41 | where | 46 | where |
42 | (CompleteRecording (TimeSpec s ns) (TimeSpec s' ns') (TimeSpec s'' ns'') (TimeSpec s''' ns''') midi) = reco | 47 | (CompleteRecording (TimeSpec s ns) (TimeSpec s' ns') (TimeSpec s'' ns'') (TimeSpec s''' ns''') midi) = reco |
43 | 48 | ||
49 | maybesnd :: forall t t1. (t, Maybe t1) -> Maybe (t, t1) | ||
50 | maybesnd (_, Nothing) = Nothing | ||
51 | maybesnd (x, Just y) = Just (x, y) | ||
44 | 52 | ||
45 | recordEvents :: Recording -> [RecordedEvent]-> Recording | 53 | convertEvents :: [(TimeSpec, Event.Data)] -> [(TimeSpec, Sound.MIDI.Message.T)] |
46 | recordEvents (RecordingInProgress x y orig) new = RecordingInProgress x y $ new ++ orig | 54 | convertEvents = mapMaybe (maybesnd . fmap conv) |
55 | where | ||
56 | conv :: Event.Data -> Maybe Sound.MIDI.Message.T | ||
57 | conv x@(Event.NoteEv _ _) = uncurry Construct.note <$> note x | ||
58 | conv _ = Nothing | ||
59 | |||
60 | unConvertEvents :: [(TimeSpec, Sound.MIDI.Message.T)] -> [(TimeSpec, Event.Data)] | ||
61 | unConvertEvents = mapMaybe (maybesnd . fmap conv) | ||
62 | where | ||
63 | conv :: Sound.MIDI.Message.T -> Maybe Event.Data | ||
64 | conv msg = uncurry Construct.note <$> note msg | ||
65 | |||
66 | recordEvents :: Recording -> [(TimeSpec, Event.Data)]-> Recording | ||
67 | recordEvents (RecordingInProgress x y orig) new = RecordingInProgress x y $ convertEvents new ++ orig | ||
47 | recordEvents i@(StartRecording _) [] = i | 68 | recordEvents i@(StartRecording _) [] = i |
48 | recordEvents (StartRecording x) new@(_:_) = RecordingInProgress x y new | 69 | recordEvents (StartRecording x) new@(_:_) = RecordingInProgress x y (convertEvents new) |
49 | where y = fst $ last new | 70 | where y = fst $ last new |
50 | 71 | ||
51 | stopRecording :: Recording -> TimeSpec -> Maybe CompleteRecording | 72 | stopRecording :: Recording -> TimeSpec -> Maybe CompleteRecording |
52 | stopRecording (RecordingInProgress x y ls@((z,_):_)) end = Just $ CompleteRecording x end y z ls | 73 | stopRecording (RecordingInProgress x y ls@((z,_):_)) end = Just $ CompleteRecording x end y z ls |
53 | stopRecording _ _ = Nothing | 74 | stopRecording _ _ = Nothing |
54 | 75 | ||
55 | |||
56 | midiToBytes :: [RecordedEvent] -> BS.ByteString | 76 | midiToBytes :: [RecordedEvent] -> BS.ByteString |
57 | midiToBytes = pack . show | 77 | -- midiToBytes = pack . show |
78 | midiToBytes = undefined | ||
58 | bytesToMidi :: BS.ByteString -> [RecordedEvent] | 79 | bytesToMidi :: BS.ByteString -> [RecordedEvent] |
59 | bytesToMidi = undefined | 80 | bytesToMidi = undefined |
diff --git a/midi-dump.hs b/midi-dump.hs index e6d2aca..b531b97 100644 --- a/midi-dump.hs +++ b/midi-dump.hs | |||
@@ -197,7 +197,7 @@ type MidiController = MidiControllerT IO | |||
197 | playRecording :: Recording -> MidiController () | 197 | playRecording :: Recording -> MidiController () |
198 | playRecording (RecordingInProgress _ _ evts@(_:_)) = | 198 | playRecording (RecordingInProgress _ _ evts@(_:_)) = |
199 | mapM_ (uncurry delayNoteEv) (zip (subtract (head delays) <$> delays) events) | 199 | mapM_ (uncurry delayNoteEv) (zip (subtract (head delays) <$> delays) events) |
200 | where (delays, events) = unzip $ fmap Event.body <$> reverse evts | 200 | where (delays, events) = unzip $ reverse $ unConvertEvents evts |
201 | playRecording _ = return () | 201 | playRecording _ = return () |
202 | 202 | ||
203 | getMidiSender :: MidiController MidiHook | 203 | getMidiSender :: MidiController MidiHook |
@@ -219,7 +219,7 @@ processMidi = do | |||
219 | liftIO $ threadDelay 15000 -- 15ms. Seems like a lot, but it sounds OK. Cuts CPU down to 2%. | 219 | liftIO $ threadDelay 15000 -- 15ms. Seems like a lot, but it sounds OK. Cuts CPU down to 2%. |
220 | else do | 220 | else do |
221 | now <- getAbsTime | 221 | now <- getAbsTime |
222 | let newEvents = map ((,) now) events | 222 | let newEvents = map ((,) now . Event.body) events |
223 | 223 | ||
224 | liftIO $ printChordLn newKeys | 224 | liftIO $ printChordLn newKeys |
225 | modify $ \s -> s { keysDown = newKeys, _recording = recordEvents (_recording s) newEvents, _lastTick = now } | 225 | modify $ \s -> s { keysDown = newKeys, _recording = recordEvents (_recording s) newEvents, _lastTick = now } |