Created
July 19, 2025 20:54
-
-
Save aavogt/2f43ab311c566999fe08a4c6496ed5a6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {-# LANGUAGE BlockArguments #-} | |
| {-# LANGUAGE DeriveAnyClass #-} | |
| {-# LANGUAGE DeriveGeneric #-} | |
| {-# LANGUAGE OverloadedStrings #-} | |
| module Main where | |
| import Data.Binary | |
| import Data.Binary.Get | |
| import qualified Data.ByteString.Lazy as BL | |
| import Data.Foldable | |
| import Data.List | |
| import Data.Maybe | |
| import Data.Word (Word8) | |
| import GHC.Generics | |
| import System.Clock (Clock (Monotonic), getTime, toNanoSecs) | |
| import System.Directory | |
| -- MIDI Message data type | |
| data MidiMessage = MidiMessage {status, data1, data2 :: !Word8} | |
| deriving (Show, Generic, Binary) | |
| streamMidi :: BL.ByteString -> [MidiMessage] | |
| streamMidi = unfoldr f | |
| where | |
| f = either (const Nothing) (\(b, _, r) -> Just (r, b)) . runGetOrFail get | |
| midiDevs :: IO [FilePath] | |
| midiDevs = do | |
| let fs = ["/dev/midi" ++ s | s <- "" : map show [0 .. 10]] | |
| es <- mapM doesFileExist fs | |
| return $ map snd $ filter fst $ zip es fs | |
| timeStamp :: [MidiMessage] -> IO [(MidiMessage, Integer)] | |
| timeStamp = mapM addTimestamp | |
| where | |
| addTimestamp msg = do | |
| time <- getTime Monotonic | |
| let timestamp = toNanoSecs time | |
| return (msg, timestamp) | |
| -- Main function | |
| main :: IO () | |
| main = do | |
| midiDevice <- fromMaybe "inpt" . listToMaybe <$> midiDevs | |
| putStrLn midiDevice | |
| input <- streamMidi <$> BL.readFile midiDevice | |
| for_ input \p -> do | |
| t <- getTime Monotonic | |
| print (p, t) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| (MidiMessage {status = 144, data1 = 64, data2 = 39},TimeSpec {sec = 44970, nsec = 664852329}) | |
| (MidiMessage {status = 128, data1 = 64, data2 = 99},TimeSpec {sec = 44970, nsec = 827328377}) | |
| (MidiMessage {status = 144, data1 = 62, data2 = 34},TimeSpec {sec = 44970, nsec = 840932261}) | |
| (MidiMessage {status = 128, data1 = 62, data2 = 80},TimeSpec {sec = 44971, nsec = 2938759}) | |
| (MidiMessage {status = 144, data1 = 64, data2 = 42},TimeSpec {sec = 44971, nsec = 23371563}) | |
| (MidiMessage {status = 128, data1 = 64, data2 = 94},TimeSpec {sec = 44971, nsec = 192795080}) | |
| (MidiMessage {status = 144, data1 = 67, data2 = 35},TimeSpec {sec = 44971, nsec = 254004591}) | |
| (MidiMessage {status = 128, data1 = 67, data2 = 97},TimeSpec {sec = 44971, nsec = 474090783}) | |
| (MidiMessage {status = 144, data1 = 65, data2 = 43},TimeSpec {sec = 44971, nsec = 495317590}) | |
| (MidiMessage {status = 128, data1 = 65, data2 = 105},TimeSpec {sec = 44971, nsec = 720551460}) | |
| (MidiMessage {status = 144, data1 = 62, data2 = 36},TimeSpec {sec = 44971, nsec = 741445738}) | |
| (MidiMessage {status = 128, data1 = 62, data2 = 93},TimeSpec {sec = 44971, nsec = 952744586}) | |
| (MidiMessage {status = 144, data1 = 65, data2 = 42},TimeSpec {sec = 44971, nsec = 982229875}) | |
| (MidiMessage {status = 128, data1 = 65, data2 = 104},TimeSpec {sec = 44972, nsec = 174855817}) | |
| (MidiMessage {status = 144, data1 = 64, data2 = 32},TimeSpec {sec = 44972, nsec = 195286771}) | |
| (MidiMessage {status = 128, data1 = 64, data2 = 89},TimeSpec {sec = 44972, nsec = 363475679}) | |
| (MidiMessage {status = 144, data1 = 65, data2 = 35},TimeSpec {sec = 44972, nsec = 390189291}) | |
| (MidiMessage {status = 128, data1 = 65, data2 = 106},TimeSpec {sec = 44972, nsec = 601167544}) | |
| (MidiMessage {status = 144, data1 = 60, data2 = 41},TimeSpec {sec = 44972, nsec = 607958437}) | |
| (MidiMessage {status = 128, data1 = 60, data2 = 91},TimeSpec {sec = 44972, nsec = 753628202}) | |
| (MidiMessage {status = 144, data1 = 64, data2 = 39},TimeSpec {sec = 44972, nsec = 786190195}) | |
| (MidiMessage {status = 128, data1 = 64, data2 = 95},TimeSpec {sec = 44972, nsec = 939147800}) | |
| (MidiMessage {status = 144, data1 = 60, data2 = 30},TimeSpec {sec = 44972, nsec = 967580622}) | |
| (MidiMessage {status = 128, data1 = 60, data2 = 45},TimeSpec {sec = 44973, nsec = 94612671}) | |
| (MidiMessage {status = 144, data1 = 67, data2 = 36},TimeSpec {sec = 44973, nsec = 128185503}) | |
| (MidiMessage {status = 128, data1 = 67, data2 = 99},TimeSpec {sec = 44973, nsec = 283770909}) | |
| (MidiMessage {status = 144, data1 = 64, data2 = 35},TimeSpec {sec = 44973, nsec = 307265803}) | |
| (MidiMessage {status = 128, data1 = 64, data2 = 80},TimeSpec {sec = 44973, nsec = 410990805}) | |
| (MidiMessage {status = 144, data1 = 67, data2 = 26},TimeSpec {sec = 44973, nsec = 463652838}) | |
| (MidiMessage {status = 128, data1 = 67, data2 = 88},TimeSpec {sec = 44973, nsec = 630358526}) | |
| (MidiMessage {status = 144, data1 = 62, data2 = 42},TimeSpec {sec = 44973, nsec = 689158148}) | |
| (MidiMessage {status = 128, data1 = 62, data2 = 56},TimeSpec {sec = 44973, nsec = 870544375}) | |
| (MidiMessage {status = 144, data1 = 65, data2 = 48},TimeSpec {sec = 44973, nsec = 950891275}) | |
| (MidiMessage {status = 128, data1 = 65, data2 = 105},TimeSpec {sec = 44974, nsec = 163107764}) | |
| (MidiMessage {status = 144, data1 = 62, data2 = 19},TimeSpec {sec = 44974, nsec = 207561607}) | |
| (MidiMessage {status = 128, data1 = 62, data2 = 67},TimeSpec {sec = 44974, nsec = 437011758}) | |
| (MidiMessage {status = 144, data1 = 67, data2 = 43},TimeSpec {sec = 44974, nsec = 469748576}) | |
| (MidiMessage {status = 128, data1 = 67, data2 = 106},TimeSpec {sec = 44974, nsec = 714929658}) | |
| (MidiMessage {status = 144, data1 = 65, data2 = 48},TimeSpec {sec = 44974, nsec = 718283393}) | |
| (MidiMessage {status = 144, data1 = 67, data2 = 55},TimeSpec {sec = 44974, nsec = 926657320}) | |
| (MidiMessage {status = 128, data1 = 65, data2 = 108},TimeSpec {sec = 44974, nsec = 933980919}) | |
| (MidiMessage {status = 128, data1 = 67, data2 = 105},TimeSpec {sec = 44975, nsec = 85117082}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: midi-reader | |
| version: 0.1.0.0 | |
| synopsis: Real-time MIDI reader for /dev/midi2 | |
| description: Reads and parses MIDI messages from /dev/midi2 device | |
| license: BSD3 | |
| author: Your Name | |
| maintainer: [email protected] | |
| build-type: Simple | |
| cabal-version: ">=1.10" | |
| executables: | |
| midi-reader: | |
| main: main.hs | |
| ghc-options: | |
| - -threaded | |
| - -rtsopts | |
| - -with-rtsopts=-N | |
| dependencies: | |
| - base >=4.7 && <5 | |
| - bytestring >=0.10 | |
| - transformers >=0.4 | |
| - binary | |
| - directory | |
| - clock | |
| default-language: Haskell2010 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| % has a few typos | |
| \version "2.18.2" | |
| \paper { | |
| page-breaking = #ly:page-turn-breaking | |
| } | |
| mbreak = { \break } | |
| % missing numbers 46 through 54 | |
| ntwentyfour = { g16 a g a b c b c d c d c b a b a | | |
| g a b a b c d c d c b c b a g c | | |
| g a b c a b c d b c d c d c b a | | |
| b a b c d c b c b c b a g a b a | | |
| g a b g b a g b a b c a c b a c | b c d b d c b d a b c a c b a c | % end 28 | |
| g b a g b g a b a c b a c a b c | b d c b d b c d a c b a c a b c | | |
| g a g b a g b g a b a c b a c a | b c b d c b d b a b a c b a c a | % end 30 | |
| g b a b a c b c b d c d a c b c | b g b a c a c b d b c b c a b a | % end 31 | |
| g a b a g b a g a b c b a c b a | b c d c b d c b a b c b a c b a | | |
| b a g a b g a b c b a b c a b c | d c b c d b c d c b a b c a b c | | |
| } | |
| ntwentyfourl = \relative c' \ntwentyfour | |
| \score { | |
| \new PianoStaff << | |
| \new Staff \relative c'' \ntwentyfour | |
| \new Staff \ntwentyfourl | |
| >> \header{ opus = "Nr24" } | |
| } | |
| nthirtyfive = { g8 b a g a b a c b a b c | | |
| b d c b c d a c b a b c | | |
| b g a b a g c a b c b a | d b c d c b c a b c b a | g1. | % end 35 | |
| g8 b a b a g a c b c b a | b d c d c b a c b c b a | | |
| b g a d a b c a b a b c | d b c b c d c a b c b a | b1. | % end | |
| g8 a g b a g a b a c b a | b c b d c b a b a c b a | | |
| b a b g a b c b c a b c | | |
| d c d b c d c a c b d c | b1. | |
| } | |
| \score { | |
| \new PianoStaff << | |
| \time 12/8 | |
| \new Staff \relative c'' \nthirtyfive | |
| \new Staff \relative c' \nthirtyfive | |
| >> \header{ opus = "Nr35" } | |
| } | |
| nfiftysevenr = { | |
| % start 57 | |
| c16 e g e c e g e d f g f d f g f | | |
| g e c e g e c e g f d f g f d f | | |
| c g' e g c, g' e g d g d f d g d f | | |
| g c, e c g' c, e c g' d f d g d f d | % end 57 | |
| c g' e c g' e c g' d g f d g f d g c, e g c, e g c, e d f g f d f g f | | |
| e g c, g' e g c, g' f g d g f g d f g e g c, g' e g c, g' f g d g f g d | %end 58 | |
| c g' e c g' d g c, d f g f g f g d | | |
| c e g e g d g c, d f g f g e g d | | |
| c g' d g e g c, g' d g e g f g d f | | |
| g c, g' d g e g c, g' d g e g f g d | % end 59 | |
| } | |
| % almost the same, except c g picks the right | |
| % octave in the bass clef | |
| nfiftysevenl = { | |
| c16 e g e c e g e d f g f d f g f | | |
| g e c e g e c e g f d f g f d f | | |
| c g e g c g e g d g d f d g d f | | |
| g c e c g c e c g d f d g d f d | % end 57 | |
| c g e c g e c g d g f d g f d g c e g c e g c e d f g f d f g f | | |
| e g c g e g c g f g d g f g d f g e g c g e g c g f g d g f g d | %end 58 | |
| c g e c g d g c d f g f g f g d | | |
| c e g e g d g c d f g f g e g d | | |
| c g d g e g c g d g e g f g d f | | |
| g c g d g e g c g d g e g f g d | % end 59 | |
| } | |
| \score { | |
| \new PianoStaff << | |
| \new Staff \relative c' \nfiftysevenr | |
| \new Staff { \relative c' \clef bass \nfiftysevenl } | |
| >> \header{ opus = "Nr57" } | |
| } | |
| nsixtyl = { | |
| c8 e g e d e d f g f e f g e c e d e g f d f e f c e c g e g d f d g f g e c e g e g f d f g f g | % end 60 | |
| c e g e f g d f g f e d c e g e c g c f g f g c c g e c d f d g f c f g c g e c g e d g f d g f | % end 61 needs c g' on right | |
| c g c d g d e g e f g f e g e d g d f g f d g d e g e d g c f g f e g d c g e d g c d g f e g d | <c e>1. | |
| } | |
| nsixtyr = { | |
| c8 e g e d e d f g f e f g e c e d e g f d f e f c e c g' e g d f d g f g e c e g e g f d f g f g | % end 60 | |
| c, e g e f g d f g f e d c e g e c g' c, f g f g c, c g' e c d f d g f c f g c, g' e c g' e d g f d g f | % end 61 needs c g' on right | |
| c g' c, d g d e g e f g f e g e d g d f g f d g d e g e d g c, f g f e g d c g' e d g c, d g f e g d | c1. | |
| } | |
| \score { | |
| \new PianoStaff << | |
| \time 12/8 | |
| \new Staff \relative c' \nsixtyr | |
| \new Staff { \clef bass \nsixtyl } | |
| >> \header{ opus = "Nr60" } | |
| } | |
| nsixtythrer = { | |
| c4 d e c d e f d e f g e f d c2 | | |
| c1 b c b2 c | | |
| c4 c8 d e4 c | d d8 e f4 d | e e8 f g4 e | f d8 e c2 | | |
| c1 b c b2 c | % end 66 | |
| c8 d c d e4 c | d8 e d e f4 d | e8 f e f g4 e | f8 e d e c2 | | |
| c1 b c b2 c | | |
| c8 d c d e d e c | d e d e f e f d | e f e f g f g e | f e f d c2 | % end 69 | |
| c1 b c b2 c | | |
| c8 d e d c d e c | d e f e d e f d | e f g f e f g f d e f d c2 | | |
| } | |
| nsixtythrel = \relative { | |
| c'1 b c g2 c | | |
| c4 d e c d e f d e f g e f d c2 | | |
| c1 b c g2 c | | |
| c4 c8 d e4 c | d d8 e f4 d | e e8 f g4 e | f d8 e c2 | | |
| c1 b c g2 c | | |
| c8 d c d e4 c | d8 e d e f4 d | e8 f e f g4 e | f8 e d e c2 | | |
| c1 b c g2 c | | |
| c8 d c d e d e c | d e d e f e f d | e f e f g f g e f e f d c2 | | |
| c1 b c g2 c | |
| } | |
| \score { | |
| \new PianoStaff << | |
| \new Staff \relative c'' \nsixtythrer | |
| \new Staff { \relative c'' \clef bass \nsixtythrel } | |
| >> \header{ opus = "Nr63" } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment