zmidi-core-0.3.0: Read and write MIDI files.

PortabilityGHC (at least generalized newtype deriving)
MaintainerStephen Tetley <>
Safe HaskellNone




Concrete syntax tree for MIDI files.

Values are sometimes not interpreted. This means that the the data types do not fully represent the sematics of the data, but all the data is either stored in the tree or synthesizeable.

readFile >>= writeFile will produce an identical binary [1].

[1] Or it should, failure indicates a bug...


MidiFile syntax.

data DeltaTime Source

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.

type TagByte = Word8Source

TagByte is an alias to Word8.

data MidiFile Source

MidiFile : header * tracks




data MidiHeader Source

Header : format * num_tracks * time_division

TimeDivision is often 384 or 480 ticks per beat.

The header is the start of a MIDI file, it is indicated by the 4 character marker MThd.

newtype MidiTrack Source

Track : [message]

In MIDI files, the start of a track is indicated by the 4 character marker MTrk.



data MidiFormat Source

The file format - in a MIDI file this is a big-endian word16 with 0,1 or 2 being the only valid values.



Format 0 file - single multi-channel track.


Format 1 file - 1 or more tracks, played simultaneously.


Format 2 file - 1 or more independent tracks.

type MidiMessage = (DeltaTime, MidiEvent)Source

MIDI messages are pairs of DeltaTime and Event wrapped in a newtype.

Sequential messages with delta time 0 are played simultaneously.

data MidiEvent Source

Recognised event types - some types (DataEvent and SysEx) are not interpreted.


DataEvent MidiDataEvent

Data event - just initial tag byte, uninterpreted

VoiceEvent MidiVoiceEvent

Voice event (e.g note-on, note-off) are relayed to specific channels.

SysExEvent MidiSysExEvent

SysEx - system exclusive event. Usually synthesizer specific, not interpreted.

SysCommonEvent MidiSysCommonEvent

SysCommon - system common event.

SysRealTimeEvent MidiSysRealTimeEvent

SysRealTime - system realtime event.

MetaEvent MidiMetaEvent

Meta event - interpreted (e.g. end-of-track, set-tempo).

newtype MidiDataEvent Source

Data events are events with tags from 0x00 to 0x7F.

Data events have no payload - they are represented only by the tag byte.




getTagByte :: TagByte

data MidiVoiceEvent Source

Voice events control the output of the synthesizer.

Note - the constructors are not in the the same order as their byte values. Controller and ProgramChange are higher than they naturally occur so the will come first after a comparison or sort.

When generating MIDI, Controller and ProgramChange events should be signalled before NoteOn or NoteOff events at the same delta-time. Changing the order of the constructors helps to sort for this.


Controller Word8 Word8 Word8
 channel * controller_number * value

Controller change, e.g. by a footswitch.

ProgramChange Word8 Word8

channel * program_number - change the instrument playing on the specified channel. For playback on computers (rather than synthesizers) the program numbers will correspond to the General MIDI instrument numbers.

NoteOff Word8 Word8 Word8
 channel * note * velocity

Turn off a sounding note.

NoteOn Word8 Word8 Word8
 channel * note * velocity

Start playing a note.

NoteAftertouch Word8 Word8 Word8
 channel * note * pressure_value

Change of pressure applied to the synthesizer key.

ChanAftertouch Word8 Word8
 channel * pressure_value
PitchBend Word8 Word16
 channel * value

Change the pitch of a sounding note. Often used to approximate microtonal tunings.

NOTE - currently value is uninterpreted.

data MidiSysExEvent Source

SysEx - system exclusive event.


SysEx Word32 [Word8]
 length * data

An uninterpreted sys-ex event.

data MidiSysCommonEvent Source

System common event.

Common information for all channels in a system.

These events may not be pertinent to MIDI files generated on a computer (as opposed to MIDI generated by a synthesizer or sequencer).


QuarterFrame Word8

Time code quarter frame.

Note the payload is really a byte split into two 4-bit values, however here it is uninterpreted.

SongPosPointer Word8 Word8

Song position pointer.

SongSelect Word8

Song number should be in the range 0..127.

Common_undefined TagByte

Tag should be limited to 0xF4 or 0xF5.

Other values would indicate either a badly formed MIDI file or a failure with the parser.


Tune request message for analogue synthesizers.


End-of-system-exclusive message.

data MidiSysRealTimeEvent Source

System real-time event.

These events may not be pertinent to MIDI files generated on a computer (as opposed to MIDI generated by a synthesizer or sequencer).



Timing signal.

RT_undefined TagByte

Tag should be limited to either 0xF9 or 0xFD.

Other values would indicate either a badly formed MIDI file or a failure with the parser.


Start playing a sequence.


Continue playing a stopped sequence.


Stop playing a sequence.


Synchronization pulse...


Reset to power-up status.

data MidiMetaEvent Source

Meta event

In Format 1 files general events (e.g. text events) should only appear in track 1. Certain events (e.g. end-of-track) can appear in any track where necessary.


TextEvent MidiTextType String
 text_type * contents

Free text field (e.g. copyright statement). The contents can notionally be any length.

SequenceNumber Word16

Format 1 files - only track 1 should have a sequence number.

Format 2 files - a sequence number should identify each track.

The sequence number event should occur at the start of a track, before any non-zero time events.

ChannelPrefix Word8 Word8
 1 * channel

Relay all meta and sys-ex events to the given channel.

The first byte should always be 1.


End-of-track event.

SetTempo Word32
SMPTEOffset Word8 Word8 Word8 Word8 Word8
 hour * minute * second * frac * subfrac

The SMPTE time when a track should start. This event should occur at the start of a track, before any non-zero time events.

TimeSignature Word8 Word8 Word8 Word8
 numerator * denominator * metro * num_32nd_notes
KeySignature Int8 MidiScaleType
 key_type * scale_type

key_type is the number of sharps (postive numbers) or flats (negative numbers), e.g. (-1) is 1 flat.

scale_type indicates major or minor.

SSME Word32 [Word8]
 length * data

Sequencer specific meta-event - uninterpreted.

data MidiTimeDivision Source

Default unit of time in the MIDI file.


FPS Word16


TPB Word16

Ticks-per-beat, i.e. the number of units for a quarter note.

data MidiScaleType Source

Scale type - major or minor.