Foreword
OK, I'm not sure that it was a good question, but I cannot wait anymore, so here is how to write some MIDI using Haskell. I should note that the topic is barely documented except for some package descriptions that look rather cryptic.
Most minimalistic package which suits our needs is HCodecs and it seems to be updated regularly. We're interested in module Codec.Midi.
MIDI Events
In this library events are expected to be represented as tuples:
(time-offset, message)
Where time-offset
is elapsed time in ticks (see below how to set number of ticks per beat) between the last event and new one. message
must be of type Message
, full list of constructors can be found here. These constructors correspond to all basic MIDI events.
Creating a Track
Track is a list of events. So we can write something very simplistic now:
track0 = [(0, NoteOn 0 60 80),
(24, NoteOff 0 60 0),
(0, TrackEnd)]
It is one note (60 = middle C), we have used here events NoteOn
and NoteOff
(it is the same as NoteOn
of 0
velocity, so in practice people tend to use only NoteOn
). For more information about what one can do here Google about MIDI format!
Let's create one more track containing E:
track1 = [(0, NoteOn 0 64 80),
(24, NoteOn 0 64 0),
(0, TrackEnd)]
Great! It's time to put the data into MIDI container.
Come Together!
Let's create object that represents entire MIDI file. We will use constructor of Midi
datatype.
myMidi = Midi { fileType = MultiTrack,
timeDiv = TicksPerBeat 24,
tracks = [track0, track1] }
That's it! timeDiv
defines quantization of the track, if we have 24
ticks per beat, our notes will sound exactly for one beat (sure, you can add some events to set tempo and stuff, try it!).
Saving the Stuff
To save a Midi
we should use exportFile
(click the link for more information... OK, just kidding there is no even a one-line description):
exportFile "my-midi.mid" myMidi
Done.