Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creation of MIDI file in Haskell

Tags:

haskell

midi

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).

like image 377
Mark Karpov Avatar asked Oct 02 '14 07:10

Mark Karpov


1 Answers

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.

like image 138
Mark Karpov Avatar answered Nov 15 '22 23:11

Mark Karpov