8

I would like to create a simple program that will generate MIDI files. No, I don't want to use Haskore, because it is kinda overkill for this project. I think something like this library will be sufficient.

What I want to be able to do:

  • create new MIDI file;
  • write some events into it (I want to control velocity, pitch, and position in time);
  • save the MIDI file.

It is as simple as that, I bet it is not hard, but I cannot find any good example how to do it.

Please provide a basic example or point out where I can find information regarding creation of MIDI files in Haskell.

Note: I'm not asking you about good library to do it, I'm asking you how to do it in Haskell (with any library that you deem good for using in example).

Mark Karpov
  • 7,499
  • 2
  • 27
  • 62
  • 3
    I don't know Haskell, but the stuff in the test and example directories looks interesting. – CL. Oct 02 '14 at 08:08
  • 1
    Have you already tried simpler programs that are available on the Web (like [this one](http://www.increpare.com/2008/10/basic-haskell-midi-file-output/) or [others by the same author](http://www.increpare.com/?s=midi))? – Aurélien Bénel Oct 04 '14 at 07:49
  • @Aurélien, I saw this program when I tried to Google the topic. Unfortunately I don't know if this is how it should be done in a decent program (it uses `Codec.Midi`, is it really good?). If that code had detailed comments, it would be much more useful. – Mark Karpov Oct 04 '14 at 07:56
  • -1 -- *give me teh codez* questions aren't welcome on SO. Your question is too broad to fit the SO format. – Bakuriu Oct 05 '14 at 13:57
  • 1
    @Bakuriu, too broad? requested answer is about 16 lines of code actually, this information will be useful for many future readers, you can think whatever you want, but there is no good documented examples of how to do it, at least it is not easy to find. 'give me teh codez' questions is not about giving canonical examples. – Mark Karpov Oct 05 '14 at 14:00
  • @Mark Yes it is too broad. It doesn't matter the size of the code you request. It matters *how many* possible solutions exists. With a simple task like this there could be hundreds if not thousands of different way to implement those operations using various libraries (or re-implementing the operations "by hand") which makes your question way too broad. Questions in the form "I have to draw a picture using language X" are **not** good questions. – Bakuriu Oct 05 '14 at 14:03
  • @Vektorweg, thanks for your suggestion, I'm kina sleepy now and it seems like those examples are undocumented too. I think I have to work through them (and others) anyway. Maybe I should write a tutorial myself ;-) – Mark Karpov Oct 05 '14 at 15:44

1 Answers1

7

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.

Mark Karpov
  • 7,499
  • 2
  • 27
  • 62