zmidi-core 0.2.1 → 0.3.0
raw patch · 10 files changed
+352/−227 lines, 10 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- ZMidi.Core.Datatypes: Data1 :: TagByte -> DataEvent
- ZMidi.Core.Datatypes: Header :: Format -> Word16 -> TimeDivision -> Header
- ZMidi.Core.Datatypes: SB :: Word8 -> Word8 -> SplitByte
- ZMidi.Core.Datatypes: Track :: [Message] -> Track
- ZMidi.Core.Datatypes: V1 :: !Word8 -> Varlen
- ZMidi.Core.Datatypes: V2 :: !Word8 -> !Word8 -> Varlen
- ZMidi.Core.Datatypes: V3 :: !Word8 -> !Word8 -> !Word8 -> Varlen
- ZMidi.Core.Datatypes: V4 :: !Word8 -> !Word8 -> !Word8 -> !Word8 -> Varlen
- ZMidi.Core.Datatypes: data DataEvent
- ZMidi.Core.Datatypes: data Event
- ZMidi.Core.Datatypes: data Format
- ZMidi.Core.Datatypes: data Header
- ZMidi.Core.Datatypes: data MetaEvent
- ZMidi.Core.Datatypes: data ScaleType
- ZMidi.Core.Datatypes: data SplitByte
- ZMidi.Core.Datatypes: data SysCommonEvent
- ZMidi.Core.Datatypes: data SysExEvent
- ZMidi.Core.Datatypes: data SysRealTimeEvent
- ZMidi.Core.Datatypes: data TextType
- ZMidi.Core.Datatypes: data TimeDivision
- ZMidi.Core.Datatypes: data Varlen
- ZMidi.Core.Datatypes: data VoiceEvent
- ZMidi.Core.Datatypes: fromVarlen :: Varlen -> Word32
- ZMidi.Core.Datatypes: getMessages :: Track -> [Message]
- ZMidi.Core.Datatypes: hexStr :: (Show a, Integral a) => a -> String
- ZMidi.Core.Datatypes: instance Enum Format
- ZMidi.Core.Datatypes: instance Enum ScaleType
- ZMidi.Core.Datatypes: instance Enum TextType
- ZMidi.Core.Datatypes: instance Eq DataEvent
- ZMidi.Core.Datatypes: instance Eq Event
- ZMidi.Core.Datatypes: instance Eq Format
- ZMidi.Core.Datatypes: instance Eq Header
- ZMidi.Core.Datatypes: instance Eq MetaEvent
- ZMidi.Core.Datatypes: instance Eq ScaleType
- ZMidi.Core.Datatypes: instance Eq SplitByte
- ZMidi.Core.Datatypes: instance Eq SysCommonEvent
- ZMidi.Core.Datatypes: instance Eq SysExEvent
- ZMidi.Core.Datatypes: instance Eq SysRealTimeEvent
- ZMidi.Core.Datatypes: instance Eq TextType
- ZMidi.Core.Datatypes: instance Eq TimeDivision
- ZMidi.Core.Datatypes: instance Eq Track
- ZMidi.Core.Datatypes: instance Eq Varlen
- ZMidi.Core.Datatypes: instance Eq VoiceEvent
- ZMidi.Core.Datatypes: instance Ord DataEvent
- ZMidi.Core.Datatypes: instance Ord Event
- ZMidi.Core.Datatypes: instance Ord MetaEvent
- ZMidi.Core.Datatypes: instance Ord ScaleType
- ZMidi.Core.Datatypes: instance Ord SplitByte
- ZMidi.Core.Datatypes: instance Ord SysCommonEvent
- ZMidi.Core.Datatypes: instance Ord SysExEvent
- ZMidi.Core.Datatypes: instance Ord SysRealTimeEvent
- ZMidi.Core.Datatypes: instance Ord TextType
- ZMidi.Core.Datatypes: instance Ord Varlen
- ZMidi.Core.Datatypes: instance Ord VoiceEvent
- ZMidi.Core.Datatypes: instance Show DataEvent
- ZMidi.Core.Datatypes: instance Show Event
- ZMidi.Core.Datatypes: instance Show Format
- ZMidi.Core.Datatypes: instance Show Header
- ZMidi.Core.Datatypes: instance Show MetaEvent
- ZMidi.Core.Datatypes: instance Show ScaleType
- ZMidi.Core.Datatypes: instance Show SplitByte
- ZMidi.Core.Datatypes: instance Show SysCommonEvent
- ZMidi.Core.Datatypes: instance Show SysExEvent
- ZMidi.Core.Datatypes: instance Show SysRealTimeEvent
- ZMidi.Core.Datatypes: instance Show TextType
- ZMidi.Core.Datatypes: instance Show TimeDivision
- ZMidi.Core.Datatypes: instance Show Track
- ZMidi.Core.Datatypes: instance Show Varlen
- ZMidi.Core.Datatypes: instance Show VoiceEvent
- ZMidi.Core.Datatypes: joinByte :: SplitByte -> Word8
- ZMidi.Core.Datatypes: lower4 :: SplitByte -> Word8
- ZMidi.Core.Datatypes: newtype Track
- ZMidi.Core.Datatypes: splitByte :: Word8 -> SplitByte
- ZMidi.Core.Datatypes: toVarlen :: Word32 -> Varlen
- ZMidi.Core.Datatypes: type DeltaTime = Word32
- ZMidi.Core.Datatypes: type Message = (DeltaTime, Event)
- ZMidi.Core.Datatypes: upper4 :: SplitByte -> Word8
- ZMidi.Core.Pretty: header :: Header -> [String]
- ZMidi.Core.Pretty: track :: Track -> [String]
+ ZMidi.Core.Datatypes: MidiDataEvent :: TagByte -> MidiDataEvent
+ ZMidi.Core.Datatypes: MidiHeader :: MidiFormat -> Word16 -> MidiTimeDivision -> MidiHeader
+ ZMidi.Core.Datatypes: MidiTrack :: [MidiMessage] -> MidiTrack
+ ZMidi.Core.Datatypes: data DeltaTime
+ ZMidi.Core.Datatypes: data MidiEvent
+ ZMidi.Core.Datatypes: data MidiFormat
+ ZMidi.Core.Datatypes: data MidiHeader
+ ZMidi.Core.Datatypes: data MidiMetaEvent
+ ZMidi.Core.Datatypes: data MidiScaleType
+ ZMidi.Core.Datatypes: data MidiSysCommonEvent
+ ZMidi.Core.Datatypes: data MidiSysExEvent
+ ZMidi.Core.Datatypes: data MidiSysRealTimeEvent
+ ZMidi.Core.Datatypes: data MidiTextType
+ ZMidi.Core.Datatypes: data MidiTimeDivision
+ ZMidi.Core.Datatypes: data MidiVoiceEvent
+ ZMidi.Core.Datatypes: getTagByte :: MidiDataEvent -> TagByte
+ ZMidi.Core.Datatypes: getTrackMessages :: MidiTrack -> [MidiMessage]
+ ZMidi.Core.Datatypes: instance Enum DeltaTime
+ ZMidi.Core.Datatypes: instance Enum MidiFormat
+ ZMidi.Core.Datatypes: instance Enum MidiScaleType
+ ZMidi.Core.Datatypes: instance Enum MidiTextType
+ ZMidi.Core.Datatypes: instance Eq DeltaTime
+ ZMidi.Core.Datatypes: instance Eq MidiDataEvent
+ ZMidi.Core.Datatypes: instance Eq MidiEvent
+ ZMidi.Core.Datatypes: instance Eq MidiFormat
+ ZMidi.Core.Datatypes: instance Eq MidiHeader
+ ZMidi.Core.Datatypes: instance Eq MidiMetaEvent
+ ZMidi.Core.Datatypes: instance Eq MidiScaleType
+ ZMidi.Core.Datatypes: instance Eq MidiSysCommonEvent
+ ZMidi.Core.Datatypes: instance Eq MidiSysExEvent
+ ZMidi.Core.Datatypes: instance Eq MidiSysRealTimeEvent
+ ZMidi.Core.Datatypes: instance Eq MidiTextType
+ ZMidi.Core.Datatypes: instance Eq MidiTimeDivision
+ ZMidi.Core.Datatypes: instance Eq MidiTrack
+ ZMidi.Core.Datatypes: instance Eq MidiVoiceEvent
+ ZMidi.Core.Datatypes: instance Integral DeltaTime
+ ZMidi.Core.Datatypes: instance Num DeltaTime
+ ZMidi.Core.Datatypes: instance Ord DeltaTime
+ ZMidi.Core.Datatypes: instance Ord MidiDataEvent
+ ZMidi.Core.Datatypes: instance Ord MidiEvent
+ ZMidi.Core.Datatypes: instance Ord MidiMetaEvent
+ ZMidi.Core.Datatypes: instance Ord MidiScaleType
+ ZMidi.Core.Datatypes: instance Ord MidiSysCommonEvent
+ ZMidi.Core.Datatypes: instance Ord MidiSysExEvent
+ ZMidi.Core.Datatypes: instance Ord MidiSysRealTimeEvent
+ ZMidi.Core.Datatypes: instance Ord MidiTextType
+ ZMidi.Core.Datatypes: instance Ord MidiVoiceEvent
+ ZMidi.Core.Datatypes: instance Real DeltaTime
+ ZMidi.Core.Datatypes: instance Show DeltaTime
+ ZMidi.Core.Datatypes: instance Show MidiDataEvent
+ ZMidi.Core.Datatypes: instance Show MidiEvent
+ ZMidi.Core.Datatypes: instance Show MidiFormat
+ ZMidi.Core.Datatypes: instance Show MidiHeader
+ ZMidi.Core.Datatypes: instance Show MidiMetaEvent
+ ZMidi.Core.Datatypes: instance Show MidiScaleType
+ ZMidi.Core.Datatypes: instance Show MidiSysCommonEvent
+ ZMidi.Core.Datatypes: instance Show MidiSysExEvent
+ ZMidi.Core.Datatypes: instance Show MidiSysRealTimeEvent
+ ZMidi.Core.Datatypes: instance Show MidiTextType
+ ZMidi.Core.Datatypes: instance Show MidiTimeDivision
+ ZMidi.Core.Datatypes: instance Show MidiTrack
+ ZMidi.Core.Datatypes: instance Show MidiVoiceEvent
+ ZMidi.Core.Datatypes: newtype MidiDataEvent
+ ZMidi.Core.Datatypes: newtype MidiTrack
+ ZMidi.Core.Datatypes: type MidiMessage = (DeltaTime, MidiEvent)
+ ZMidi.Core.Datatypes: type TagByte = Word8
+ ZMidi.Core.Pretty: printMidiHeader :: MidiHeader -> [String]
+ ZMidi.Core.Pretty: printMidiTrack :: MidiTrack -> [String]
- ZMidi.Core.Datatypes: ActiveSensing :: SysRealTimeEvent
+ ZMidi.Core.Datatypes: ActiveSensing :: MidiSysRealTimeEvent
- ZMidi.Core.Datatypes: COPYRIGHT_NOTICE :: TextType
+ ZMidi.Core.Datatypes: COPYRIGHT_NOTICE :: MidiTextType
- ZMidi.Core.Datatypes: CUE_POINT :: TextType
+ ZMidi.Core.Datatypes: CUE_POINT :: MidiTextType
- ZMidi.Core.Datatypes: ChanAftertouch :: Word8 -> Word8 -> VoiceEvent
+ ZMidi.Core.Datatypes: ChanAftertouch :: Word8 -> Word8 -> MidiVoiceEvent
- ZMidi.Core.Datatypes: ChannelPrefix :: Word8 -> Word8 -> MetaEvent
+ ZMidi.Core.Datatypes: ChannelPrefix :: Word8 -> Word8 -> MidiMetaEvent
- ZMidi.Core.Datatypes: Common_undefined :: TagByte -> SysCommonEvent
+ ZMidi.Core.Datatypes: Common_undefined :: TagByte -> MidiSysCommonEvent
- ZMidi.Core.Datatypes: ContinueSequence :: SysRealTimeEvent
+ ZMidi.Core.Datatypes: ContinueSequence :: MidiSysRealTimeEvent
- ZMidi.Core.Datatypes: Controller :: Word8 -> Word8 -> Word8 -> VoiceEvent
+ ZMidi.Core.Datatypes: Controller :: Word8 -> Word8 -> Word8 -> MidiVoiceEvent
- ZMidi.Core.Datatypes: DataEvent :: DataEvent -> Event
+ ZMidi.Core.Datatypes: DataEvent :: MidiDataEvent -> MidiEvent
- ZMidi.Core.Datatypes: EOX :: SysCommonEvent
+ ZMidi.Core.Datatypes: EOX :: MidiSysCommonEvent
- ZMidi.Core.Datatypes: EndOfTrack :: MetaEvent
+ ZMidi.Core.Datatypes: EndOfTrack :: MidiMetaEvent
- ZMidi.Core.Datatypes: FPS :: Word16 -> TimeDivision
+ ZMidi.Core.Datatypes: FPS :: Word16 -> MidiTimeDivision
- ZMidi.Core.Datatypes: GENERIC_TEXT :: TextType
+ ZMidi.Core.Datatypes: GENERIC_TEXT :: MidiTextType
- ZMidi.Core.Datatypes: INSTRUMENT_NAME :: TextType
+ ZMidi.Core.Datatypes: INSTRUMENT_NAME :: MidiTextType
- ZMidi.Core.Datatypes: KeySignature :: Int8 -> ScaleType -> MetaEvent
+ ZMidi.Core.Datatypes: KeySignature :: Int8 -> MidiScaleType -> MidiMetaEvent
- ZMidi.Core.Datatypes: LYRICS :: TextType
+ ZMidi.Core.Datatypes: LYRICS :: MidiTextType
- ZMidi.Core.Datatypes: MAJOR :: ScaleType
+ ZMidi.Core.Datatypes: MAJOR :: MidiScaleType
- ZMidi.Core.Datatypes: MARKER :: TextType
+ ZMidi.Core.Datatypes: MARKER :: MidiTextType
- ZMidi.Core.Datatypes: MF0 :: Format
+ ZMidi.Core.Datatypes: MF0 :: MidiFormat
- ZMidi.Core.Datatypes: MF1 :: Format
+ ZMidi.Core.Datatypes: MF1 :: MidiFormat
- ZMidi.Core.Datatypes: MF2 :: Format
+ ZMidi.Core.Datatypes: MF2 :: MidiFormat
- ZMidi.Core.Datatypes: MINOR :: ScaleType
+ ZMidi.Core.Datatypes: MINOR :: MidiScaleType
- ZMidi.Core.Datatypes: MetaEvent :: MetaEvent -> Event
+ ZMidi.Core.Datatypes: MetaEvent :: MidiMetaEvent -> MidiEvent
- ZMidi.Core.Datatypes: MidiFile :: Header -> [Track] -> MidiFile
+ ZMidi.Core.Datatypes: MidiFile :: MidiHeader -> [MidiTrack] -> MidiFile
- ZMidi.Core.Datatypes: NoteAftertouch :: Word8 -> Word8 -> Word8 -> VoiceEvent
+ ZMidi.Core.Datatypes: NoteAftertouch :: Word8 -> Word8 -> Word8 -> MidiVoiceEvent
- ZMidi.Core.Datatypes: NoteOff :: Word8 -> Word8 -> Word8 -> VoiceEvent
+ ZMidi.Core.Datatypes: NoteOff :: Word8 -> Word8 -> Word8 -> MidiVoiceEvent
- ZMidi.Core.Datatypes: NoteOn :: Word8 -> Word8 -> Word8 -> VoiceEvent
+ ZMidi.Core.Datatypes: NoteOn :: Word8 -> Word8 -> Word8 -> MidiVoiceEvent
- ZMidi.Core.Datatypes: PitchBend :: Word8 -> Word16 -> VoiceEvent
+ ZMidi.Core.Datatypes: PitchBend :: Word8 -> Word16 -> MidiVoiceEvent
- ZMidi.Core.Datatypes: ProgramChange :: Word8 -> Word8 -> VoiceEvent
+ ZMidi.Core.Datatypes: ProgramChange :: Word8 -> Word8 -> MidiVoiceEvent
- ZMidi.Core.Datatypes: QuarterFrame :: SplitByte -> SysCommonEvent
+ ZMidi.Core.Datatypes: QuarterFrame :: Word8 -> MidiSysCommonEvent
- ZMidi.Core.Datatypes: RT_undefined :: TagByte -> SysRealTimeEvent
+ ZMidi.Core.Datatypes: RT_undefined :: TagByte -> MidiSysRealTimeEvent
- ZMidi.Core.Datatypes: SEQUENCE_NAME :: TextType
+ ZMidi.Core.Datatypes: SEQUENCE_NAME :: MidiTextType
- ZMidi.Core.Datatypes: SMPTEOffset :: Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> MetaEvent
+ ZMidi.Core.Datatypes: SMPTEOffset :: Word8 -> Word8 -> Word8 -> Word8 -> Word8 -> MidiMetaEvent
- ZMidi.Core.Datatypes: SSME :: Word32 -> [Word8] -> MetaEvent
+ ZMidi.Core.Datatypes: SSME :: Word32 -> [Word8] -> MidiMetaEvent
- ZMidi.Core.Datatypes: SequenceNumber :: Word16 -> MetaEvent
+ ZMidi.Core.Datatypes: SequenceNumber :: Word16 -> MidiMetaEvent
- ZMidi.Core.Datatypes: SetTempo :: Word32 -> MetaEvent
+ ZMidi.Core.Datatypes: SetTempo :: Word32 -> MidiMetaEvent
- ZMidi.Core.Datatypes: SongPosPointer :: Word8 -> Word8 -> SysCommonEvent
+ ZMidi.Core.Datatypes: SongPosPointer :: Word8 -> Word8 -> MidiSysCommonEvent
- ZMidi.Core.Datatypes: SongSelect :: Word8 -> SysCommonEvent
+ ZMidi.Core.Datatypes: SongSelect :: Word8 -> MidiSysCommonEvent
- ZMidi.Core.Datatypes: StartSequence :: SysRealTimeEvent
+ ZMidi.Core.Datatypes: StartSequence :: MidiSysRealTimeEvent
- ZMidi.Core.Datatypes: StopSequence :: SysRealTimeEvent
+ ZMidi.Core.Datatypes: StopSequence :: MidiSysRealTimeEvent
- ZMidi.Core.Datatypes: SysCommonEvent :: SysCommonEvent -> Event
+ ZMidi.Core.Datatypes: SysCommonEvent :: MidiSysCommonEvent -> MidiEvent
- ZMidi.Core.Datatypes: SysEx :: Word32 -> [Word8] -> SysExEvent
+ ZMidi.Core.Datatypes: SysEx :: Word32 -> [Word8] -> MidiSysExEvent
- ZMidi.Core.Datatypes: SysExEvent :: SysExEvent -> Event
+ ZMidi.Core.Datatypes: SysExEvent :: MidiSysExEvent -> MidiEvent
- ZMidi.Core.Datatypes: SysRealTimeEvent :: SysRealTimeEvent -> Event
+ ZMidi.Core.Datatypes: SysRealTimeEvent :: MidiSysRealTimeEvent -> MidiEvent
- ZMidi.Core.Datatypes: SystemReset :: SysRealTimeEvent
+ ZMidi.Core.Datatypes: SystemReset :: MidiSysRealTimeEvent
- ZMidi.Core.Datatypes: TPB :: Word16 -> TimeDivision
+ ZMidi.Core.Datatypes: TPB :: Word16 -> MidiTimeDivision
- ZMidi.Core.Datatypes: TextEvent :: TextType -> String -> MetaEvent
+ ZMidi.Core.Datatypes: TextEvent :: MidiTextType -> String -> MidiMetaEvent
- ZMidi.Core.Datatypes: TimeSignature :: Word8 -> Word8 -> Word8 -> Word8 -> MetaEvent
+ ZMidi.Core.Datatypes: TimeSignature :: Word8 -> Word8 -> Word8 -> Word8 -> MidiMetaEvent
- ZMidi.Core.Datatypes: TimingClock :: SysRealTimeEvent
+ ZMidi.Core.Datatypes: TimingClock :: MidiSysRealTimeEvent
- ZMidi.Core.Datatypes: TuneRequest :: SysCommonEvent
+ ZMidi.Core.Datatypes: TuneRequest :: MidiSysCommonEvent
- ZMidi.Core.Datatypes: VoiceEvent :: VoiceEvent -> Event
+ ZMidi.Core.Datatypes: VoiceEvent :: MidiVoiceEvent -> MidiEvent
- ZMidi.Core.Datatypes: hdr_format :: Header -> Format
+ ZMidi.Core.Datatypes: hdr_format :: MidiHeader -> MidiFormat
- ZMidi.Core.Datatypes: mf_header :: MidiFile -> Header
+ ZMidi.Core.Datatypes: mf_header :: MidiFile -> MidiHeader
- ZMidi.Core.Datatypes: mf_tracks :: MidiFile -> [Track]
+ ZMidi.Core.Datatypes: mf_tracks :: MidiFile -> [MidiTrack]
- ZMidi.Core.Datatypes: num_tracks :: Header -> Word16
+ ZMidi.Core.Datatypes: num_tracks :: MidiHeader -> Word16
- ZMidi.Core.Datatypes: time_division :: Header -> TimeDivision
+ ZMidi.Core.Datatypes: time_division :: MidiHeader -> MidiTimeDivision
Files
- CHANGES +15/−0
- demo/MidiCopy.hs +3/−5
- demo/MidiTune.hs +51/−0
- src/ZMidi/Core/Datatypes.hs +66/−145
- src/ZMidi/Core/Internal/ExtraTypes.hs +115/−0
- src/ZMidi/Core/Pretty.hs +26/−23
- src/ZMidi/Core/ReadFile.hs +29/−27
- src/ZMidi/Core/VersionNumber.hs +2/−2
- src/ZMidi/Core/WriteFile.hs +24/−23
- zmidi-core.cabal +21/−2
CHANGES view
@@ -1,3 +1,18 @@+0.2.1 to 0.3.0:++ * Revised naming of the MIDI data types. All data types now have + the prefix Midi (previously only MidiFile followed this scheme).+ The rationale for this is client software, that might want a + higher-level representation, is then free to use the more + generic names Track, Message, etc.++ * @DeltaTime@ made a newtype wrapper rather than a type synonym.++ * Renamed the pretty print functions @track@ to @printMidiTrack@ + and @header@ to @printMidiHeader@.++ * Moved internal dataypes (SplitByte, Varlen) into a private + module. 0.2.0 to 0.2.1:
demo/MidiCopy.hs view
@@ -6,9 +6,7 @@ module Main where -import ZMidi.Core.ReadFile-import ZMidi.Core.WriteFile-+import ZMidi.Core import System.Environment @@ -31,7 +29,7 @@ ans <- readMidi filename case ans of Left err -> print err- Right a -> writeMidi (filename ++ ".001") a- putStrLn $ take 1000 $ show ans -- not very good, need a pretty printer...+ Right a -> do { mapM_ putStrLn $ printMidiHeader $ mf_header a+ ; writeMidi (filename ++ ".001") a }
+ demo/MidiTune.hs view
@@ -0,0 +1,51 @@+{-# OPTIONS -Wall #-}++--+-- Write a MIDI \"tune\".+--+-- The MIDI AST should be considered too low level to work with +-- directly...+--++module Main where++import ZMidi.Core++import System.Directory++++main :: IO ()+main = do + createDirectoryIfMissing True "./out/"+ writeMidi "./out/midi_tune.mid" midi_tune01+ ++midi_tune01 :: MidiFile+midi_tune01 = MidiFile+ { mf_header = MidiHeader { hdr_format = MF1+ , num_tracks = 2+ , time_division = TPB 480+ }+ , mf_tracks = [ meta_track, sound_track ]+ }+ where+ meta_track = MidiTrack [ (0, MetaEvent $ TextEvent SEQUENCE_NAME "Track 0")+ , (0, MetaEvent $ EndOfTrack) + ]++ sound_track = MidiTrack [ (0, MetaEvent $ TextEvent SEQUENCE_NAME "Track 1")+ , (0, MetaEvent $ SetTempo 500000)+ , (0, VoiceEvent $ NoteOn 0 60 127)+ , (480, VoiceEvent $ NoteOff 0 60 15)+ , (0, VoiceEvent $ NoteOn 0 62 127)+ , (480, VoiceEvent $ NoteOff 0 62 15)+ , (0, VoiceEvent $ NoteOn 0 64 127)+ , (480, VoiceEvent $ NoteOff 0 64 15)+ , (0, VoiceEvent $ NoteOn 0 66 127)+ , (480, VoiceEvent $ NoteOff 0 66 15)+ , (0, MetaEvent $ EndOfTrack) + ]+ ++
src/ZMidi/Core/Datatypes.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# OPTIONS -Wall #-} --------------------------------------------------------------------------------@@ -8,7 +9,7 @@ -- -- Maintainer : Stephen Tetley <stephen.tetley@gmail.com> -- Stability : unstable--- Portability : As per dependencies.+-- Portability : GHC (at least generalized newtype deriving) -- -- Concrete syntax tree for MIDI files. --@@ -26,45 +27,47 @@ module ZMidi.Core.Datatypes (- -- * MidiFile representation.- MidiFile(..)- , Header(..) - , Track(..)- , Format(..)- , DeltaTime- , Message- , Event(..)- , DataEvent(..)- , VoiceEvent(..)- , SysExEvent(..)- , SysCommonEvent(..)- , SysRealTimeEvent(..)- , MetaEvent(..)- , TimeDivision(..)- , TextType(..)- , ScaleType(..)+ -- * MidiFile syntax.+ DeltaTime+ , TagByte - -- * Interim types.- -- ** SplitByte- , SplitByte(..)- , splitByte- , joinByte- - -- ** Varlen- , Varlen(..)- , fromVarlen- , toVarlen+ , MidiFile(..)+ , MidiHeader(..) + , MidiTrack(..)+ , MidiFormat(..)+ , MidiMessage+ , MidiEvent(..) - , hexStr+ , MidiDataEvent(..)+ , MidiVoiceEvent(..)+ , MidiSysExEvent(..)+ , MidiSysCommonEvent(..)+ , MidiSysRealTimeEvent(..)+ , MidiMetaEvent(..)+ , MidiTimeDivision(..)+ , MidiTextType(..)+ , MidiScaleType(..) ) where -import Data.Bits import Data.Int import Data.Word-import Numeric (showHex) ++-- | All time values in a MIDI track are represented as a \delta\ +-- from the previous event rather than an absolute time. +--+-- DeltaTime is a newtype wrapper over Word32, note that in MIDI +-- files it is represented as a @varlen@ to save space rather than +-- a four byte number. +--+newtype DeltaTime = DeltaTime { getDeltaTime :: Word32 }+ deriving (Enum,Eq,Ord,Num,Integral,Real)++instance Show DeltaTime where+ showsPrec p = showsPrec p . getDeltaTime+ -- | TagByte is an alias to 'Word8'. -- type TagByte = Word8@@ -73,8 +76,8 @@ -- | 'MidiFile' : @ header * tracks @ -- data MidiFile = MidiFile - { mf_header :: Header- , mf_tracks :: [Track]+ { mf_header :: MidiHeader+ , mf_tracks :: [MidiTrack] } deriving (Eq,Show) @@ -85,11 +88,11 @@ -- The header is the start of a MIDI file, it is indicated by the -- 4 character marker @MThd@. ---data Header = Header - { hdr_format :: Format+data MidiHeader = MidiHeader + { hdr_format :: MidiFormat , num_tracks :: Word16- , time_division :: TimeDivision- }+ , time_division :: MidiTimeDivision+ } deriving (Eq,Show) -- | 'Track' : @ [message] @@@ -97,13 +100,13 @@ -- In MIDI files, the start of a track is indicated by the 4 -- character marker @MTrk@. ---newtype Track = Track { getMessages :: [Message] }+newtype MidiTrack = MidiTrack { getTrackMessages :: [MidiMessage] } deriving (Eq,Show) -- | The file format - in a MIDI file this is a big-endian -- word16 with 0,1 or 2 being the only valid values. ---data Format +data MidiFormat -- | Format 0 file - single multi-channel track. = MF0 -- | Format 1 file - 1 or more tracks, played simultaneously.@@ -114,12 +117,12 @@ -- | Default unit of time in the MIDI file. ---data TimeDivision +data MidiTimeDivision -- | Frames-per-second. -- = FPS Word16 - -- | Ticks-per-beat, i.e. the number of units for a quater + -- | Ticks-per-beat, i.e. the number of units for a quarter -- note. -- | TPB Word16 @@ -127,7 +130,7 @@ -- | Enumeration of the text meta event types. ---data TextType +data MidiTextType = GENERIC_TEXT | COPYRIGHT_NOTICE | SEQUENCE_NAME @@ -137,13 +140,6 @@ | CUE_POINT deriving (Eq,Enum,Ord,Show) --- | All time values in a MIDI track are represented as a \delta\ --- from the previous event rather than an absolute time. ------ Although DeltaTime is a type synonym for Word32, in MIDI --- files it is represented as a @varlen@ to save space. ----type DeltaTime = Word32 -- | MIDI messages are pairs of 'DeltaTime' and 'Event' wrapped in -- a newtype. @@ -151,7 +147,7 @@ -- Sequential messages with delta time 0 are played -- simultaneously. ---type Message = (DeltaTime, Event)+type MidiMessage = (DeltaTime, MidiEvent) -- Note, the Ord instance for pairs is very useful for rendering.@@ -165,38 +161,38 @@ -- | Recognised event types - some types ('DataEvent' and -- 'SysEx') are not interpreted. ---data Event +data MidiEvent -- | Data event - just initial tag byte, -- uninterpreted --- = DataEvent DataEvent+ = DataEvent MidiDataEvent -- | Voice event (e.g @note-on@, @note-off@) are relayed to specific -- channels. --- | VoiceEvent VoiceEvent+ | VoiceEvent MidiVoiceEvent -- | SysEx - system exclusive event. Usually synthesizer -- specific, not interpreted. --- | SysExEvent SysExEvent+ | SysExEvent MidiSysExEvent -- | SysCommon - system common event. --- | SysCommonEvent SysCommonEvent+ | SysCommonEvent MidiSysCommonEvent -- | SysRealTime - system realtime event. --- | SysRealTimeEvent SysRealTimeEvent+ | SysRealTimeEvent MidiSysRealTimeEvent -- | Meta event - interpreted (e.g. @end-of-track@, -- @set-tempo@). --- | MetaEvent MetaEvent+ | MetaEvent MidiMetaEvent deriving (Eq,Show,Ord)@@ -206,7 +202,7 @@ -- Data events have no payload - they are represented only by the -- tag byte. ---data DataEvent = Data1 TagByte+newtype MidiDataEvent = MidiDataEvent { getTagByte :: TagByte } deriving (Eq,Ord,Show) -- | Voice events control the output of the synthesizer.@@ -221,7 +217,7 @@ -- delta-time. Changing the order of the constructors helps to -- sort for this. ---data VoiceEvent +data MidiVoiceEvent -- | @ channel * controller_number * value @ -- -- Controller change, e.g. by a footswitch.@@ -269,7 +265,7 @@ -- | \SysEx\ - system exclusive event. ---data SysExEvent+data MidiSysExEvent -- | @ length * data @ -- -- An uninterpreted sys-ex event.@@ -286,10 +282,13 @@ -- computer (as opposed to MIDI generated by a synthesizer or -- sequencer). ---data SysCommonEvent+data MidiSysCommonEvent -- | Time code quarter frame.+ -- + -- Note the payload is really a byte split into two 4-bit + -- values, however here it is uninterpreted. --- = QuarterFrame SplitByte+ = QuarterFrame Word8 -- | Song position pointer. --@@ -323,7 +322,7 @@ -- computer (as opposed to MIDI generated by a synthesizer or -- sequencer). ---data SysRealTimeEvent+data MidiSysRealTimeEvent -- | Timing signal. -- = TimingClock@@ -367,14 +366,14 @@ -- only appear in track 1. Certain events (e.g. end-of-track) -- can appear in any track where necessary. ---data MetaEvent+data MidiMetaEvent -- | @ text_type * contents @ -- -- Free text field (e.g. copyright statement). The contents -- can notionally be any length. --- = TextEvent TextType String+ = TextEvent MidiTextType String -- | @ value @ -- @@ -424,7 +423,7 @@ -- -- @scale_type@ indicates major or minor. --- | KeySignature Int8 ScaleType+ | KeySignature Int8 MidiScaleType -- | @ length * data@ -- @@ -436,85 +435,7 @@ -- | Scale type - @major@ or @minor@. ---data ScaleType = MAJOR | MINOR+data MidiScaleType = MAJOR | MINOR deriving (Eq,Enum,Ord,Show) -------------------------------------------------------------------------------------- | SplitByte - divide a byte into the upper four and lower --- 4 bits.--- -data SplitByte = SB { upper4 :: Word8, lower4 :: Word8 }- deriving (Eq,Ord,Show)--splitByte :: Word8 -> SplitByte-splitByte i = SB ((i .&. 0xF0) `shiftR` 4) (i .&. 0x0F)--joinByte :: SplitByte -> Word8-joinByte (SB a b) = (a `shiftL` 4) + (b .&. 0x0F)-------------------------------------------------------------------------------------- helper for varlen------------------------------------------------------------------------------------- | Space efficient representation of length fields.--- --- This data type is not used directly in the syntax tree where--- it would be cumbersome. But it is used as an intermediate type--- in the parser and emitter.----data Varlen = V1 !Word8- | V2 !Word8 !Word8- | V3 !Word8 !Word8 !Word8- | V4 !Word8 !Word8 !Word8 !Word8- deriving (Eq,Ord,Show)---up :: Word8 -> Word32-up = fromIntegral . (0x7f .&.)--down :: Word32 -> Word8-down = (0x80 .|.) . fromIntegral--downl :: Word32 -> Word8-downl = (0x7f .&.) . fromIntegral- --fromVarlen :: Varlen -> Word32-fromVarlen (V1 a) = up a-fromVarlen (V2 a b) = (left7 $ up a) + up b-fromVarlen (V3 a b c) = (left14 $ up a) + (left7 $ up b) + up c-fromVarlen (V4 a b c d) = (left21 $ up a) + (left14 $ up b) - + (left7 $ up c) + up d--left7 :: Word32 -> Word32-left7 = (`shiftL` 7)--left14 :: Word32 -> Word32-left14 = (`shiftL` 14)--left21 :: Word32 -> Word32-left21 = (`shiftL` 21)--right7 :: Word32 -> Word32-right7 = (`shiftR` 7)--right14 :: Word32 -> Word32-right14 = (`shiftR` 14)--right21 :: Word32 -> Word32-right21 = (`shiftR` 21)--toVarlen :: Word32 -> Varlen-toVarlen i - | i < 0x80 = V1 (downl i)- | i < 0x4000 = V2 (down $ right7 i) (downl i)- | i < 0x200000 = V3 (down $ right14 i) (down $ right7 i) (downl i)- | otherwise = V4 (down $ right21 i) (down $ right14 i)- (down $ right7 i) (downl i)--hexStr :: (Show a, Integral a) => a -> String-hexStr i = (showString "0x" . showHex i) ""
+ src/ZMidi/Core/Internal/ExtraTypes.hs view
@@ -0,0 +1,115 @@+{-# OPTIONS -Wall #-}++--------------------------------------------------------------------------------+-- |+-- Module : ZMidi.Core.Internal.ExtraTypes+-- Copyright : (c) Stephen Tetley 2010+-- License : BSD3+--+-- Maintainer : Stephen Tetley <stephen.tetley@gmail.com>+-- Stability : unstable+-- Portability : As per dependencies.+--+-- Internal types not exported by the package.+--+--------------------------------------------------------------------------------+++module ZMidi.Core.Internal.ExtraTypes+ (++ -- * SplitByte+ SplitByte(..)+ , splitByte+ , joinByte+ + -- * Varlen+ , Varlen(..)+ , fromVarlen+ , toVarlen++ , hexStr+ + ) where++import Data.Bits+import Data.Word+import Numeric (showHex)++++-- | SplitByte - divide a byte into the upper four and lower +-- 4 bits.+-- +data SplitByte = SB { upper4 :: Word8, lower4 :: Word8 }+ deriving (Eq,Ord,Show)++splitByte :: Word8 -> SplitByte+splitByte i = SB ((i .&. 0xF0) `shiftR` 4) (i .&. 0x0F)++joinByte :: SplitByte -> Word8+joinByte (SB a b) = (a `shiftL` 4) + (b .&. 0x0F)+++--------------------------------------------------------------------------------+-- helper for varlen+--------------------------------------------------------------------------------++-- | Space efficient representation of length fields.+-- +-- This data type is not used directly in the syntax tree where+-- it would be cumbersome. But it is used as an intermediate type+-- in the parser and emitter.+--+data Varlen = V1 !Word8+ | V2 !Word8 !Word8+ | V3 !Word8 !Word8 !Word8+ | V4 !Word8 !Word8 !Word8 !Word8+ deriving (Eq,Ord,Show)+++up :: Word8 -> Word32+up = fromIntegral . (0x7f .&.)++down :: Word32 -> Word8+down = (0x80 .|.) . fromIntegral++downl :: Word32 -> Word8+downl = (0x7f .&.) . fromIntegral+ ++fromVarlen :: Varlen -> Word32+fromVarlen (V1 a) = up a+fromVarlen (V2 a b) = (left7 $ up a) + up b+fromVarlen (V3 a b c) = (left14 $ up a) + (left7 $ up b) + up c+fromVarlen (V4 a b c d) = (left21 $ up a) + (left14 $ up b) + + (left7 $ up c) + up d++left7 :: Word32 -> Word32+left7 = (`shiftL` 7)++left14 :: Word32 -> Word32+left14 = (`shiftL` 14)++left21 :: Word32 -> Word32+left21 = (`shiftL` 21)++right7 :: Word32 -> Word32+right7 = (`shiftR` 7)++right14 :: Word32 -> Word32+right14 = (`shiftR` 14)++right21 :: Word32 -> Word32+right21 = (`shiftR` 21)++toVarlen :: Word32 -> Varlen+toVarlen i + | i < 0x80 = V1 (downl i)+ | i < 0x4000 = V2 (down $ right7 i) (downl i)+ | i < 0x200000 = V3 (down $ right14 i) (down $ right7 i) (downl i)+ | otherwise = V4 (down $ right21 i) (down $ right14 i)+ (down $ right7 i) (downl i)++hexStr :: (Show a, Integral a) => a -> String+hexStr i = (showString "0x" . showHex i) ""
src/ZMidi/Core/Pretty.hs view
@@ -20,8 +20,8 @@ printMidi - , header- , track+ , printMidiHeader+ , printMidiTrack ) where @@ -40,10 +40,10 @@ printMidi :: MidiFile -> IO () printMidi (MidiFile hdr tracks) = do column_break- mapM_ putStrLn (header hdr) + mapM_ putStrLn (printMidiHeader hdr) mapM_ (\t -> column_break >> putTrack t) tracks where- putTrack = (mapM_ putStrLn) . track+ putTrack = (mapM_ putStrLn) . printMidiTrack column_break = putStrLn $ replicate 60 '-' @@ -52,8 +52,8 @@ -- Results are returned as a list of String to avoid extraneous -- concatenation. -- -header :: Header -> [String]-header (Header fmt tcount td) = +printMidiHeader :: MidiHeader -> [String]+printMidiHeader (MidiHeader fmt tcount td) = map output [ppFormat fmt, ppNumTracks tcount, ppTimeDivision td] -- | Print a track.@@ -61,9 +61,10 @@ -- Results are returned as a list of String to avoid extraneous -- concatenation. ---track :: Track -> [String]-track = snd . mapAccumL (\acc b -> msnd output $ message acc b) 0 . getMessages +printMidiTrack :: MidiTrack -> [String]+printMidiTrack = snd . mapAccumL fn 0 . getTrackMessages where+ fn acc b = msnd output $ message acc b msnd f (a,b) = (a,f b) --------------------------------------------------------------------------------@@ -71,7 +72,7 @@ column2 :: String -> Doc -> Doc column2 s d2 = padr 20 (text s) `sep` char '|' `ssep` d2 -ppFormat :: Format -> Doc+ppFormat :: MidiFormat -> Doc ppFormat = column2 "MIDI Format" . step where step MF0 = text "Type 0 MIDI File"@@ -81,7 +82,7 @@ ppNumTracks :: Word16 -> Doc ppNumTracks = column2 "Number of tracks" . integral -ppTimeDivision :: TimeDivision -> Doc+ppTimeDivision :: MidiTimeDivision -> Doc ppTimeDivision = column2 "Time Division" . step where step (FPS i) = text "fps" `ssep` integral i@@ -92,15 +93,15 @@ dashsep :: Doc -> Doc -> Doc dashsep d1 d2 = d1 `ssep` char '-' `ssep` d2 -message :: Word32 -> Message -> (Word32,Doc)+message :: Word32 -> MidiMessage -> (Word32,Doc) message acc (delta,evt) = (n, acctime `dashsep` dtime `dashsep` ppEvent evt) where- n = acc + delta + n = acc + fromIntegral delta acctime = padl 12 (integral n) dtime = padl 6 (integral delta) -ppEvent :: Event -> Doc+ppEvent :: MidiEvent -> Doc ppEvent (DataEvent e) = ppDataEvent e ppEvent (VoiceEvent e) = ppVoiceEvent e ppEvent (SysExEvent e) = ppSysExEvent e@@ -112,10 +113,10 @@ event :: String -> Doc -> Doc event s d = padr 18 (text s) `dashsep` d -ppDataEvent :: DataEvent -> Doc-ppDataEvent (Data1 tag) = event "data" (hex2 tag)+ppDataEvent :: MidiDataEvent -> Doc+ppDataEvent (MidiDataEvent tag) = event "data" (hex2 tag) -ppVoiceEvent :: VoiceEvent -> Doc+ppVoiceEvent :: MidiVoiceEvent -> Doc ppVoiceEvent (Controller c n v) = event "controller" (hex2 c `ssep` hex2 n `ssep` hex2 v) @@ -138,12 +139,13 @@ event "pitch-bend" (hex2 c `ssep` hex4 v) -ppSysExEvent :: SysExEvent -> Doc+ppSysExEvent :: MidiSysExEvent -> Doc ppSysExEvent (SysEx n ws) = event "sys-ex" $ byteList n ws -ppSysCommonEvent :: SysCommonEvent -> Doc++ppSysCommonEvent :: MidiSysCommonEvent -> Doc ppSysCommonEvent (QuarterFrame sb) = - event "time-code-quarter-frame" (hex2 $ joinByte sb)+ event "time-code-quarter-frame" (hex2 sb) ppSysCommonEvent (SongPosPointer a b) = event "sys-common song pos. pointer" (hex2 a `ssep` hex2 b)@@ -157,7 +159,7 @@ ppSysCommonEvent EOX = text "end-of-sys-ex" -ppSysRealTimeEvent :: SysRealTimeEvent -> Doc+ppSysRealTimeEvent :: MidiSysRealTimeEvent -> Doc ppSysRealTimeEvent TimingClock = text "sys-real-time timing-clock" ppSysRealTimeEvent (RT_undefined tag) = event "sys-real-time" (hex2 tag) ppSysRealTimeEvent StartSequence = text "sys-real-time start"@@ -166,7 +168,8 @@ ppSysRealTimeEvent ActiveSensing = text "sys-real-time active sensing" ppSysRealTimeEvent SystemReset = text "system-reset" -ppMetaEvent :: MetaEvent -> Doc++ppMetaEvent :: MidiMetaEvent -> Doc ppMetaEvent (TextEvent ty s) = event (textType ty) (text s) ppMetaEvent (SequenceNumber w) = event "sequence-number" (hex4 w)@@ -195,7 +198,7 @@ | otherwise = integral n `sep` multiply 10 '.' -textType :: TextType -> String+textType :: MidiTextType -> String textType GENERIC_TEXT = "generic-text" textType COPYRIGHT_NOTICE = "copyright-notice" textType SEQUENCE_NAME = "sequence-name"@@ -205,6 +208,6 @@ textType CUE_POINT = "cue-point" -ppScale :: ScaleType -> Doc+ppScale :: MidiScaleType -> Doc ppScale MAJOR = text "major" ppScale MINOR = text "minor"
src/ZMidi/Core/ReadFile.hs view
@@ -27,6 +27,7 @@ ) where import ZMidi.Core.Datatypes+import ZMidi.Core.Internal.ExtraTypes import ZMidi.Core.Internal.ParserMonad @@ -46,41 +47,41 @@ midiFile :: ParserM MidiFile -midiFile = do+midiFile = {- printHexAll >> -} do hdr <- header let i = trackCount hdr trks <- count i track return $ MidiFile hdr trks where- trackCount :: Header -> Int - trackCount (Header _ n _) = fromIntegral n+ trackCount :: MidiHeader -> Int + trackCount (MidiHeader _ n _) = fromIntegral n -header :: ParserM Header -header = Header <$> (assertString "MThd" *> assertWord32 (6::Int) *> format)- <*> word16be- <*> timeDivision+header :: ParserM MidiHeader +header = MidiHeader <$> (assertString "MThd" *> assertWord32 (6::Int) *> format)+ <*> word16be+ <*> timeDivision -track :: ParserM Track-track = liftM Track (trackHeader >>= messages)+track :: ParserM MidiTrack+track = liftM MidiTrack (trackHeader >>= messages) trackHeader :: ParserM Word32 trackHeader = assertString "MTrk" >> word32be -messages :: Word32 -> ParserM [Message]+messages :: Word32 -> ParserM [MidiMessage] messages i = boundRepeat (fromIntegral i) message -message :: ParserM Message+message :: ParserM MidiMessage message = (,) <$> deltaTime <*> event -deltaTime :: ParserM Word32-deltaTime = "delta time" <??> getVarlen+deltaTime :: ParserM DeltaTime+deltaTime = "delta time" <??> fmap fromIntegral getVarlen -event :: ParserM Event+event :: ParserM MidiEvent event = word8 >>= step where -- 00..7f -- /data/@@ -91,12 +92,12 @@ | 0x80 <= n = VoiceEvent <$> voiceEvent (splitByte n) | otherwise = DataEvent <$> dataEvent n -dataEvent :: Word8 -> ParserM DataEvent-dataEvent tag = pure $ Data1 tag+dataEvent :: Word8 -> ParserM MidiDataEvent+dataEvent tag = pure $ MidiDataEvent tag -voiceEvent :: SplitByte -> ParserM VoiceEvent+voiceEvent :: SplitByte -> ParserM MidiVoiceEvent voiceEvent (SB 0x8 ch) = "note-off" <??> (NoteOff ch) <$> word8 <*> word8 @@ -121,9 +122,10 @@ voiceEvent (SB z _ ) = reportError $ "voiceEvent " ++ hexStr z -sysCommonEvent :: Word8 -> ParserM SysCommonEvent++sysCommonEvent :: Word8 -> ParserM MidiSysCommonEvent sysCommonEvent 0xF1 = - "quarter frame" <??> QuarterFrame . splitByte <$> word8+ "quarter frame" <??> QuarterFrame <$> word8 sysCommonEvent 0xF2 = "song pos. pointer" <??> SongPosPointer <$> word8 <*> word8@@ -142,7 +144,7 @@ sysCommonEvent tag = pure $ Common_undefined tag -sysRealTimeEvent :: Word8 -> ParserM SysRealTimeEvent+sysRealTimeEvent :: Word8 -> ParserM MidiSysRealTimeEvent sysRealTimeEvent 0xF8 = pure TimingClock sysRealTimeEvent 0xF9 = pure $ RT_undefined 0xF9 sysRealTimeEvent 0xFA = pure StartSequence@@ -154,12 +156,12 @@ sysRealTimeEvent tag = pure $ RT_undefined tag -sysExEvent :: ParserM SysExEvent+sysExEvent :: ParserM MidiSysExEvent sysExEvent = "sys-ex" <??> (uncurry SysEx) <$> getVarlenBytes -metaEvent :: Word8 -> ParserM MetaEvent+metaEvent :: Word8 -> ParserM MidiMetaEvent metaEvent 0x00 = "sequence number" <??> SequenceNumber <$> (assertWord8 2 *> word16be) @@ -202,7 +204,7 @@ -format :: ParserM Format+format :: ParserM MidiFormat format = word16be >>= fn where fn 0 = return MF0@@ -211,13 +213,13 @@ fn z = reportError $ "getFormat - unrecognized file format " ++ hexStr z -timeDivision :: ParserM TimeDivision+timeDivision :: ParserM MidiTimeDivision timeDivision = division <$> word16be where division i | i `testBit` 15 = FPS (i `clearBit` 15) | otherwise = TPB i -scale :: ParserM ScaleType+scale :: ParserM MidiScaleType scale = word8 >>= fn where fn 0 = return MAJOR@@ -225,7 +227,7 @@ fn z = reportError $ "scale expecting 0 or 1, got " ++ hexStr z -textEvent :: TextType -> ParserM MetaEvent+textEvent :: MidiTextType -> ParserM MidiMetaEvent textEvent ty = (TextEvent ty . snd) <$> getVarlenText --------------------------------------------------------------------------------@@ -237,7 +239,7 @@ where msg = "assertWord8 - input did not match " ++ show i -assertWord32 :: (Show a, Integral a) => a -> ParserM Word32+assertWord32 :: (Integral a, Show a) => a -> ParserM Word32 assertWord32 i = postCheck word32be ((==i) . fromIntegral) msg where msg = "assertWord32 - input did not match " ++ show i
src/ZMidi/Core/VersionNumber.hs view
@@ -22,7 +22,7 @@ -- | Version number ----- > (0,2,1)+-- > (0,3,0) -- zmidi_core_version :: (Int,Int,Int)-zmidi_core_version = (0,2,1)+zmidi_core_version = (0,3,0)
src/ZMidi/Core/WriteFile.hs view
@@ -14,7 +14,6 @@ -- -------------------------------------------------------------------------------- - module ZMidi.Core.WriteFile ( -- * Write a Midi structure to file@@ -22,7 +21,7 @@ ) where import ZMidi.Core.Datatypes-+import ZMidi.Core.Internal.ExtraTypes import Data.Binary.Put -- package: binary @@ -46,35 +45,35 @@ putMidiFile (MidiFile hdr trks) = putHeader hdr *> mapM_ putTrack trks -putHeader :: Header -> PutM ()-putHeader (Header fmt n td) =+putHeader :: MidiHeader -> PutM ()+putHeader (MidiHeader fmt n td) = putString "MThd" *> putWord32be 6 *> putFormat fmt *> putWord16be n *> putTimeDivision td -putTrack :: Track -> PutM ()-putTrack (Track ms) = +putTrack :: MidiTrack -> PutM ()+putTrack (MidiTrack ms) = putString "MTrk" *> (putWord32be $ fromIntegral $ L.length bs) *> putLazyByteString bs where bs = runPut (mapM_ putMessage ms) -putFormat :: Format -> PutM ()+putFormat :: MidiFormat -> PutM () putFormat MF0 = putWord16be 0 putFormat MF1 = putWord16be 1 putFormat MF2 = putWord16be 2 -putTimeDivision :: TimeDivision -> PutM ()+putTimeDivision :: MidiTimeDivision -> PutM () putTimeDivision (FPS n) = putWord16be (n `setBit` 15) putTimeDivision (TPB n) = putWord16be (n `clearBit` 15) -putMessage :: Message -> PutM () -putMessage (dt,evt) = putVarlen dt *> putEvent evt+putMessage :: MidiMessage -> PutM () +putMessage (dt,evt) = putVarlen (fromIntegral dt) *> putEvent evt -putEvent :: Event -> PutM ()+putEvent :: MidiEvent -> PutM () putEvent (DataEvent e) = putDataEvent e putEvent (VoiceEvent e) = putVoiceEvent e putEvent (SysExEvent e) = putSysExEvent e@@ -83,10 +82,10 @@ putEvent (MetaEvent e) = putMetaEvent e -putDataEvent :: DataEvent -> PutM ()-putDataEvent (Data1 tag) = putWord8 tag+putDataEvent :: MidiDataEvent -> PutM ()+putDataEvent (MidiDataEvent tag) = putWord8 tag -putVoiceEvent :: VoiceEvent -> PutM ()+putVoiceEvent :: MidiVoiceEvent -> PutM () putVoiceEvent (NoteOff c n v) = putWord8 (0x8 `u4l4` c) *> putWord8 n *> putWord8 v @@ -108,13 +107,15 @@ putVoiceEvent (PitchBend c v) = putWord8 (0xE `u4l4` c) *> putWord16be v -putSysExEvent :: SysExEvent -> PutM ()++putSysExEvent :: MidiSysExEvent -> PutM () putSysExEvent (SysEx n ws) = putWord8 0xF0 *> putVarlen n *> mapM_ putWord8 ws -putSysCommonEvent :: SysCommonEvent -> PutM ()++putSysCommonEvent :: MidiSysCommonEvent -> PutM () putSysCommonEvent (QuarterFrame sb) = - putWord8 0xF1 *> putSplitByte sb+ putWord8 0xF1 *> putWord8 sb putSysCommonEvent (SongPosPointer lsb msb) = putWord8 0xF2 *> putWord8 lsb *> putWord8 msb@@ -131,7 +132,8 @@ putSysCommonEvent EOX = putWord8 0xF7 -putSysRealTimeEvent :: SysRealTimeEvent -> PutM ()++putSysRealTimeEvent :: MidiSysRealTimeEvent -> PutM () putSysRealTimeEvent TimingClock = putWord8 0xF8 putSysRealTimeEvent (RT_undefined tag) = putWord8 tag putSysRealTimeEvent StartSequence = putWord8 0xFA@@ -140,7 +142,8 @@ putSysRealTimeEvent ActiveSensing = putWord8 0xFE putSysRealTimeEvent SystemReset = putWord8 0xFF -putMetaEvent :: MetaEvent -> PutM ()++putMetaEvent :: MidiMetaEvent -> PutM () putMetaEvent (TextEvent ty ss) = putWord8 0xFF *> putWord8 (texttype ty) *> putVarlen (fromIntegral $ length ss) @@ -189,8 +192,6 @@ prefixLen :: Word8 -> PutM () -> PutM () prefixLen n out = putWord8 n *> out -putSplitByte :: SplitByte -> PutM ()-putSplitByte a = putWord8 (joinByte a) infixr 5 `u4l4` @@ -205,7 +206,7 @@ i' :: Int i' = fromIntegral i -wscale :: ScaleType -> Word8+wscale :: MidiScaleType -> Word8 wscale MAJOR = 0x00 wscale MINOR = 0x01 @@ -239,7 +240,7 @@ -texttype :: TextType -> Word8+texttype :: MidiTextType -> Word8 texttype GENERIC_TEXT = 0x01 texttype COPYRIGHT_NOTICE = 0x02 texttype SEQUENCE_NAME = 0x03
zmidi-core.cabal view
@@ -1,5 +1,5 @@ name: zmidi-core-version: 0.2.1+version: 0.3.0 license: BSD3 license-file: LICENSE copyright: Stephen Tetley <stephen.tetley@gmail.com>@@ -8,11 +8,28 @@ category: Music synopsis: Read and write MIDI files. description:+ . Minimalist library to read and write MIDI files, with dependencies only on ByteString and Data.Binary. . Changelog: .+ v0.2.1 to v0.3.0:+ .+ * Revised naming of the MIDI data types. All data types now have + the prefix Midi (previously only MidiFile followed this scheme).+ The rationale for this is client software, that might want a + higher-level representation, is then free to use the more + generic names Track, Message, etc.+ .+ * @DeltaTime@ made a newtype wrapper rather than a type synonym.+ .+ * Renamed the pretty print functions @track@ to @printMidiTrack@ + and @header@ to @printMidiHeader@.+ .+ * Moved internal dataypes (SplitByte, Varlen) into a private + module.+ . v0.2.0 to v0.2.1: . * Added Show class constraints to various type signatures to @@ -31,8 +48,9 @@ extra-source-files: CHANGES,+ demo/MidiCopy.hs, demo/MidiPrint.hs,- demo/MidiCopy.hs+ demo/MidiTune.hs library@@ -50,6 +68,7 @@ ZMidi.Core.WriteFile other-modules:+ ZMidi.Core.Internal.ExtraTypes, ZMidi.Core.Internal.ParserMonad, ZMidi.Core.Internal.SimpleFormat