Skip to content

mxm, IT's mad science

Sections
Personal tools
You are here: Home » Products » Open Source » Python Midi Package
Downloads
You can download mxm products here.

Due to it's technical and international nature, this section is in english.

Max M Has a blog too.

og er glad for mad

 

Python Midi Package

The Python Midi package is a collection of classes handling Midi in and output in the Python programming language.

The python midi package is currently released in an experimental version. So there is little documentation, and the software might change as new needs arises.

It does work though. It can read and write any midi file that I have tested it on. If you find a Midi file it cannot read, please send me a copy, so that I can update the package.

Currently it cannot read and write to midi ports. So no real time event handling is possible.

Examples

This is an example of how to create the smallest possible type 0 midi file, where all the midi events are in the same track.:

        from MidiOutFile import MidiOutFile

        out_file = 'midiout/minimal_type0.mid'
        midi = MidiOutFile(out_file)

        # non optional midi framework
        midi.header()
        midi.start_of_track() 

        # musical events

        midi.update_time(0)
        midi.note_on(channel=0, note=0x40)

        midi.update_time(192)
        midi.note_off(channel=0, note=0x40)

        # non optional midi framework
        midi.update_time(0)
        midi.end_of_track() # not optional!

        midi.eof()

This prints all note_on events on midi channel 0. It's a short example of creating your own event handler by subclassing the MidiOutStream.:

        from MidiOutStream import MidiOutStream
        from MidiInFile import MidiInFile

        class NoteOnPrinter(MidiOutStream):

            "Prints all note_on events on channel 0"

            def note_on(self, channel=0, note=0x40, velocity=0x40):
                if channel == 0:
                    print channel, note, velocity, self.rel_time()

        event_handler = NoteOnPrinter()

        in_file = 'midiout/minimal_type0.mid'
        midi_in = MidiInFile(event_handler, in_file)
        midi_in.read()

Download

get it from the download section

License

GPL

Contact

maxm@mxm.dk

Created by maxm
Last modified 2005-02-04 12:34 PM

Using Python Midi package

Posted by Anonymous User at 2004-03-15 02:47 PM
Hello, Max.

I'm playing with your beatiful module. It is what I'm looking for.

I have a doubt: how I can write chords in a track?

I've tried to write three notes simultaneously:

m.start_of_track(1)
m.sequence_name('Piano')
m.instrument_name('Piano')
m.update_time(0)
m.note_on(channel=1, note=0x3C)
m.note_on(channel=1, note=0x3E)
m.note_on(channel=1, note=0x43)
m.update_time(96)
m.note_off(channel=1, note=0x3C)
m.note_off(channel=1, note=0x3E)
m.note_off(channel=1, note=0x43)
m.end_of_track()


but it generates some strange note durations in my sequencer: each note has a different duration.
(I've used different sequencers: AnvilStudio (win32), Jazz++, Muse and Rosegarden).

How can I solve it?
I thank your time and work.

Regards.

David

Replies to this comment

pydrums

Posted by Anonymous User at 2004-07-11 05:20 AM
i made an attempt to create a small drumming module which is a python script used to add drumnotes to patterns and finally to a midi song. It's just a little plaything, but maybe somebody wants to check it out.

The pythonmidi module is really cool, i have no clue about midi, but it works. (THAT'S what i call the python way...).

So, thank you for it. Feedback is appreciated.

http://www.jesterea.com/pydrums.zip

mixing midi

Posted by Anonymous User at 2004-07-29 10:03 AM
hello,

i want to use this package to mix several midi files, i get a tempo and the midi files for each bar - like so: infiles=[['1.mid','5.mid','3.mid'],['1.mid','5.mid','3.mid'],['1.mid','5.mid','3.mid','5.mid','3.mid'],['3.mid','3.mid']]
then convert the mids into txt and write it out as midi again

is it possible to do that? i looped through the files but i only got concatenation, maybe relative vs absolute time?

any help would be appreciated,
best regards
wern

playing midi from within python

Posted by Anonymous User at 2004-08-12 05:32 PM
looks great, but I don't see any way to process and play sounds simultaneously (while doing graphics on each note for example).

am I missing something?

python midi with excel

Posted by Anonymous User at 2004-10-04 01:58 AM
Thanks for your cool python midi package. I hacked and tweaked it a bit and I can now generate a midifile from excel.

Using this nifty little program and ableton, I'm having a whole lot of fun.

I'm making my modifications available here for whoever is interested:

http://www.geocities.com/alia_khouri/python-midi-xl.zip

Enjoy!

alia_khouri@yahoo.com

Great Module!

Posted by Anonymous User at 2005-10-07 06:38 PM
Thanks alot for this great module. Its been a complete pleasure to use, so far.

Blender and Midi

Posted by Anonymous User at 2005-11-04 09:53 PM
I am looking at using this great looking module to allow the Blender3d (www.blender3d.org) to import and sychronize 3d animation to midi files. I do have a question. I noticed that channels are sequential, does that mean that time starts over at 0 which each channel?

Johnny Matthews

typo

Posted by Anonymous User at 2005-11-10 12:24 AM
i found a typo which causes no attribute 'sysex_events' error. MidiFileParser.py line 129 should be

dispatch.sysex_event(sysex_data)

Playing midi

Posted by Anonymous User at 2005-12-29 04:41 PM
Hi,

I'm a newer python user. I was working on a my own small program for the managing of the birthdays. I would like to make a pop up window that highlights a birthday with a midi sound in background.

Is Python Midi Package for me? which commands Do I have to use?

Thanks in advance Davideok

How to create more then 1 track.

Posted by Anonymous User at 2006-02-11 06:02 PM
I am not sure, how to create more then 1 track in the midi song. I was trying the following:
start_of_track(0)
... (some note_on and note_off events)
end_of_track()
start_of_track(1)
... (some note_on and note_off events) ...
end_of_track()
Did not work.
Then I tried:
start_of_track(0)
start_of_track(1)
set_current_track(0)
... (some note_on and note_off events) ...
set_current_track(1)
... (some note_on and note_off events)
end_of_track()
Still does not work. In both cases only 1 track is created and all notes are on the same track.
Would greatly appreciate, if anybody could give me a short example, how to create multiple tracks.
Thanks so much.

Thanks for the Python MIDI Package

Posted by Anonymous User at 2006-10-12 10:37 PM
Just wanted to drop you a quick "thank you" note for your work on the Python MIDI Package. We used it in our game, Frets On Fire, and it worked beautifully.

- Sami Kyostila

Midi out to another program

Posted by Anonymous User at 2006-12-09 10:27 PM
Hi, would it be possible using your package to send a midi out stream to another program on the same computer, for example Max/MSP ?

Problem with flats in Key Signature

Posted by Anonymous User at 2007-02-20 07:40 PM
Hi,

I'm having a problem with your module: when I add a negative value as the first argument to midi.key_signature(), to indicate flats, it gives me this:

File "./xml2midi.py", line 131, in xml2midi
midi.key_signature(-3,0)
File "midi/MidiOutFile.py", line 381, in key_signature
self.meta_slice(KEY_SIGNATURE, fromBytes([sf, mi]))
File "midi/DataTypeConverters.py", line 143, in fromBytes
return pack('%sB' % len(value), *value)
File "/usr/lib/python2.5/struct.py", line 63, in pack
return o.pack(*args)
struct.error: ubyte format requires 0 <= number <= 255

Is this a bug, or am I doing something wrong?

Thanks, for any help and for the otherwise great module!

Absolute time

Posted by Anonymous User at 2007-03-31 12:43 AM
Is there a way for me to retrieve the time of a note in absolute time rather than relative ?
I'd like to know at which point in seconds a note is to be played.

Thanks

abs_time

Posted by Anonymous User at 2007-03-31 04:17 PM
What does abs_time return in?
There is no documentation that I am aware of.
Is it the absolute time in beats per minute relative to the start of the file?

Lola.mid

Posted by Anonymous User at 2007-05-11 02:37 PM
Hy,

I tried to accomplish MidiFileParser.py. But there is no Lola.mid. Can sombody tell where ican find this?

error message:

Traceback (most recent call last):
File "MidiFileParser.py", line 189, in ?
midi_in = MidiFileParser(RawInstreamFile(test_file), MidiToText())
File "/home/mirakulix/Desktop/Dilomarbeit/Midi_Python_package/midi/RawInstreamFile.py", line 32, in __init__
infile = open(infile, 'rb')
IOError: [Errno 2] No such file or directory: 'test/midifiles/Lola.mid'

In hope for your help.

Jana

do somebody want wave??

Posted by Anonymous User at 2007-05-26 11:34 PM
The program I've made to generate wavefiles with math functions...as there's almost no information about it, I put it here (and this is french...)

"pure synthesis":

#----------------------------------imports def et autres------------------------------------------------------------------------------
from math import pi, sin, cos, floor
import wave,struct


kamp=32000.0
#-----------------------------------------------------------------------------------------------------------------------------------------



#-----------------------------fonctions de distorsion----------------------------------------------------------------------------


def hardclip(x,seuil):
if (x < seuil):
return x
else:
return seuil

def softclip(x):
fx= 35*x-35*x**3+21*x**5-5*x**7
dimfx= fx/25.
return dimfx
#hardclip: ecretage au dessus d'une valeur seuil
#softclip: ecretage progressif

def tcheby(x):
fx= 16*x**5-20*x**3+5*x
return fx
#-----------------------------------------------------------------------------------------------------------------------------------


#------------------------------partie synthese----------------------------------------------------------------------------------
freq=440.0
long=120000
fech=11025.0



tliste=[]
sinliste=[]
cosliste=[]
fnliste1=[]
fnliste2=[]
fnliste3=[]

for i in range(long):
t=(i/fech)
tliste.append(t)
for i in range(long):
t=tliste[i]
cosliste.append( cos(2*pi*freq*t) )
for i in range(long):
x=cosliste[i]
fx=tcheby((i/(long*1.0))*x)
fnliste3.append(fx)


wavfile = wave.open('tcheby.wav','w')
wavfile.setparams ((1, 2, 11025 , 32000, 'NONE', 'not compressed'))
for s in fnliste3:
wavfile.writeframes(struct.pack('h',((kamp/2)*s)))
wavfile.close()



"extraction:"

#----------------------------------imports def et autres------------------------------------------------------------------------------
from math import pi, sin, cos, floor
import wave,struct

#pour voir les messages d'erreur:
print 'messages d erreur:'

kamp=32000.0
#-----------------------------------------------------------------------------------------------------------------------------------------


#-----------------------------------------------utilitaires-------------------------------------------------------------------------------
def findmax(lst,range):
max=0
for i in range(range):
if (tab[i]>max):
max=tab[i]
return max

def findfreq(lst):
max1=0
max2=0
for i in range(1000):
if (lst[i+1]>lst[i]) and (lst[i+1]>lst[i+2]):
max1=i
while (max2<1):
if (lst[i+1]>lst[i+1]) and (lst[i+1]>lst[i+2]):
max2=i
freq=(max2-max1)/fech
return freq
#---------------------------------------------------------------------------------------------------------------------------------------




#-----------------------------fonctions de distorsion----------------------------------------------------------------------------
seuil=0.5

def hardclip(x,seuil):
if (x < seuil):
return x
else:
return seuil

def softclip(x):
fx= 35*x-35*x**3+21*x**5-5*x**7
dimfx= fx/25.
return dimfx
#hardclip: ecretage parfait
#softclip: ecretage progressif

def tcheby(x):
fx= 2*x**2-1
return fx
#-----------------------------------------------------------------------------------------------------------------------------------


#------------------------------partie synthese----------------------------------------------------------------------------------
freq=440.0
long=10000
fech=11025.0
kamp=32000
param1=(freq,10,(freq*2.),0,(freq/2.),0)
#freq: frequence du son produit
#long: longueur de la chaine
#fech: frequence d'echantillonage
#kamp: coefficient multiplicateur (a determiner)

def timbre(t,(fbase,volb,fh1,vol1,fh2,vol2)):
sinb = volb*sin (2*pi*fbase*t)
sin1 = vol1*sin (2*pi*fh1*t)
sin2 = vol2*sin (2*pi*fh2*t)
moy = (sinb+sin1+sin2) / (volb + vol1 +vol2 )
return (moy)

tliste=[]
sinliste=[]
cosliste=[]
fnliste1=[]
fnliste2=[]
fnliste3=[]

for i in range(long):
t=(i/fech)
tliste.append(t)
for i in range(long):
t=tliste[i]
sinliste.append( timbre(t,param1) )
for i in range(long):
t=tliste[i]
cosliste.append( cos(pi*freq*t) )
for i in range(long):
x=sinliste[i]
fx=hardclip(x,seuil)
fnliste1.append(fx)
for i in range(long):
x=sinliste[i]
fx=softclip(x)
fnliste2.append(fx)
for i in range(long):
x=cosliste[i]
fx=tcheby(x)
fnliste3.append(fx)
#------------------------------------------------------------------------------------------------------------------------



#-------------------------------partie distorsion d'echantillon--------------------------------------------------------
longueur=32000
dim=6000.0
#dim: pour avoir x inf a 1 pour utiliser les fn de disto

fwav = wave.open('guitare.wav')
wavparams=fwav.getparams()


echliste=[]
distoliste=[]

for i in range(longueur):
vhex=fwav.readframes(1)
vnum=struct.unpack('h',vhex)[0]
echliste.append(vnum)

for i in range(longueur):
x=echliste[i]/dim
fx=tcheby(x)
kfx=kamp*fx
distoliste.append(kfx)

#-------------------------------------------------------------------------------------------------------------------------




#-------------------------------generation des fichiers wav-----------------------------------------------------------

wavfile = wave.open('echgratte.wav','w')
wavfile.setparams (wavparams)
for s in echliste:
wavfile.writeframes(struct.pack('h',s))
wavfile.close()


wavfile = wave.open('distogratte.wav','w')
wavfile.setparams (wavparams)
for s in distoliste:
wavfile.writeframes(struct.pack('h',s))
wavfile.close()


#just replace the wavfile "guitare" by any wavefile you want

enjoy

License

Posted by Anonymous User at 2007-08-08 12:49 AM
Hello, max. Can you clarify the license? Which version of the GPL do you want to use? I think you should put that in the source package itself. The gpl instructions are here: http://www.fsf.org/licensing/licenses/gpl-howto.html .

Now supporting midi ports

Posted by Anonymous User at 2007-12-02 01:35 AM
The top of your page here says that your module does not support reading/writing to midi ports.

But then when I look at the code I find this:


This makes it extremely easy to take input from one stream and
send it to another. Ie. if you want to read a Midi file, do some
processing, and send it to a midiport.

Which has me hoping that you added stuff to your module and haven't had time to update the site?

I'm trying to write something like guitar hero for keyboard.

alex

Bug in pitch bend output

Posted by Anonymous User at 2008-01-10 10:51 PM
MidiOutFile.py has a bug in the pitch bend output. This causes corruption in all pitch bends generated. The solution is below in the form of a diff.

@@ -107,8 +107,8 @@
value: 0-16383
"""
msb = (value>>7) & 0xFF
- lsb = value & 0xFF
- slc = fromBytes([PITCH_BEND + channel, msb, lsb])
+ lsb = value & 0x7F
+ slc = fromBytes([PITCH_BEND + channel, lsb, msb])
self.event_slice(slc)


@@ -445,4 +445,4 @@
midi.eof() # currently optional, should it do the write instead of write??

rests

Posted by Anonymous User at 2008-04-18 04:15 AM
Thank you, first and foremost, for making this... I've been looking for something like this for a long time, and the "Frets on Fire" guy below got me here via Google Cache.

Anyways, to my problem: I am writing a program which reads a text file of 0's and 1's, then converts them into 16th notes in a MIDI file (1 is a note, 0 is a rest). For some reason, the output file shows the correct number of notes, but they are placed next to each other with none of the rests between. Here is a sample of the code (the list is made of the first 16 characters of each line in the text file, eliminating newlines):


for line in text:
beat = list(line)
if int(beat[0]):
midi.update_time(0)
midi.note_on(channel=0, note=0x40)
midi.update_time(24)
midi.note_off(channel=0, note=0x40)
else:
midi.update_time(24)
if int(beat[1]):
midi.note_on(channel=0, note=0x40)
midi.update_time(24)
midi.note_off(channel=0, note=0x40)
else:
midi.update_time(24)

# ... continues to "if int(beat[15]):", then goes on to


midi.update_time(0)
midi.end_of_track()

midi.eof()

I am baffled as to why the rests don't appear, but perhaps I just don't have a good enough understanding of update_time(n).

Instrument

Posted by Anonymous User at 2008-07-17 06:28 PM
Hey Guys,

i'm unable to switch the instrument. I tried midi.instrument_name('Piano'), midi.instrument_name('Bass'), ... but nothing happened. What's wrong with my code?

Thanks!

Simple math operations with MIDI

Posted by Anonymous User at 2008-09-04 04:55 PM
Hi,
I have some python classes to represent notes, scales, intervals. What I need is to istantiate such classes after reading a MIDI file. So, if the file contains a short melody (e.g. C - E - G), I have to istantiate the note class three times, then interval and so on.

Do you think I can use your module for this?
And if in a file there is a melody and a drum pattern, is it possible to identify the two instruments?

Thanks,
Carlo

I have question about create piano midi

Posted by Anonymous User at 2008-12-27 11:40 PM
Hello...I have question, please help me
I'm very stupid and stupid at python, it's the first time to use it and I want to create a program that generate piano MIDI, here is questions...

1. What's method update_time() and what's integer in () ?
2. What's methods note_on() and note_off and how to use ?
3. How can i set type of MIDI for 1 instead of 0

Hope anyone could help me, Thank you for Python Midi Package, it's very useful
** If anyone have example code of create piano midi please send it to me to
canurecognize@hotmail.com
thank you

Python Package Index

Posted by Anonymous User at 2009-02-16 06:45 PM
You should put this in the PYPI (PYthon Package Index) on python.org. It's a collection of Python modules, and I think that this needs to be more well-known. Here it is: http://pypi.python.org/

update for Python v3.0?

Posted by Anonymous User at 2009-02-28 10:02 AM
Hello Max-
I was wondering if you're planning to update these MIDI packages to work with Python v3.0? There seems to be a few things that are broken now with some of the new Python v3 stuff.

Thank you for writing these MIDI packages.
-marc

Bug?

Posted by Anonymous User at 2010-03-13 05:27 PM
Hi,

First of all, thanks a lot for this module! I don't know if you check this page anymore, but I've been having trouble running some of your code, specifically example_transpose_octave.py . It fails because it can't find the files you refer to, but when I change it in order to use my files, it fails with the following message:

Traceback (most recent call last):
File "example_transpose_octave.py", line 39, in <module>
midi_in.read()
File "/home/anthony/Software/python/midi/midi/MidiInFile.py", line 48, in read
p.parseMTrkChunks()
File "/home/anthony/Software/python/midi/midi/MidiFileParser.py", line 169, in parseMTrkChunks
self.parseMTrkChunk() # this is where it's at!
File "/home/anthony/Software/python/midi/midi/MidiFileParser.py", line 118, in parseMTrkChunk
dispatch.meta_event(meta_type, meta_data)
File "/home/anthony/Software/python/midi/midi/EventDispatcher.py", line 269, in meta_event
stream.sequencer_specific(meta_data)
File "/home/anthony/Software/python/midi/midi/MidiOutFile.py", line 390, in sequencer_specific
self.meta_slice(SEQUENCER_SPECIFIC, data)
NameError: global name 'SEQUENCER_SPECIFIC' is not defined

I have no idea about the purpose of MidiOutFile.sequencer_specific(...), but commenting the code it contains fixes that problem. Hope this is useful to someone.

Absolute/Relative Time issue with update_time()

Posted by Anonymous User at 2010-05-22 02:19 AM
Hi all,

Can anyone explain why the below doesn't work? I'm essentially doing note_on()'s out of order, but the resulting out-put .mid file doesn't seem to take notice of the out-of-order-notes.
For example, I first do: (abstracted some non-important details away)

update_time(0)
note_on(note="C4")
note_on(note="G4")

update_time(200)
note_off(note="C4")
note_off(note="G4")

The above is all fine and dandy - however, say I add the following line in:

update_time(0, relative=0) # To make it absolute-time
note_on(note="E4")

The resulting output file doesn't have the E! What am I doing wrong?

Thanks!

====== If you want, here's the whole file:

from MidiOutFile import MidiOutFile

out_file = 'midiout/newtest_type0.mid'
m = MidiOutFile(out_file)

# non optional midi framework
m.header()
m.start_of_track()

# musical events

m.start_of_track(1)
m.sequence_name('Piano')
m.instrument_name('Piano')

m.update_time(0)
m.note_on(channel=1, note=0x3C)
m.note_on(channel=1, note=0x43)


m.update_time(150)
m.note_off(channel=1, note=0x3C)
m.note_off(channel=1, note=0x40)
m.note_off(channel=1, note=0x43)

m.update_time(0,relative=0)
m.note_on(channel=1, note=0x40)


# non optional midi framework
m.update_time(0)
m.end_of_track() # not optional!

m.eof()

Using the module to make a song monophone

Posted by Anonymous User at 2010-08-03 08:41 PM
Hey.

I have a song with chords and single notes. I want to load this midi file and output a song, which always takes the highest note only and exports it.

Can you show me how to do it using your module?

bugs

Posted by Anonymous User at 2010-12-13 04:49 PM
Hi,
This package is excellent,but I'm just wondering is it no longer maintained?
there're some bugs in pitch bending as someone post 3 years ago but haven't been fixed yet.
I've found some bugs currently in MidiOutFile.py:
1)@Ln 323,midi_port:
self.meta_slice(MIDI_CH_PREFIX, chr(value))
=>
self.meta_slice(MIDI_PORT, chr(value))
2)@Ln 390,sequencer_specific:
self.meta_slice(SEQUENCER_SPECIFIC, data)
=>
self.meta_slice(SPECIFIC, data)

there might be more.

And where to find MidiTime and MidiDeltaTime classes you mentioned in MidiOutStream.py?

regards,
explogit

MIDI 2 Text / Text to MIDI

Posted by Anonymous User at 2010-12-23 07:13 AM
Hi

have been browsing & testing this code a little bit, & seems to work ok.

in particular, the example_print_file.py does 95% of what i am actually hoping to achieve.

But instead of rendering the text translation of the MIDI file to the terminal window, i want to output to a text file - the format of the text presentation is fine (although i may need to do a little investigation re the header info....)

Ideally converting an identically formatted text file back to MIDI would then give me 100% of what I am after

There is a similar .exe for windows that runs on XP, but I'm hoping to create something with greater longevity & cross platform - as it's something that i use a lot.

I have some basic python experience, but the level of complexity of these modules is stretching me a little bit. I would simply like to pair this code down to the bare minimum & alter it a bit to achieve the desired outcome.

This could be quite trivial I imagine for someone who knows what they are doing. Can anyone assist?

with thanks

Tim Mortimer
Adelaide - Australia

Thanks

Posted by Anonymous User at 2011-04-26 04:58 PM
Thanks for these nice classes. I'm using them in the 2.0 version of Frescobaldi, a GPL LilyPond editor.
Wilbert Berendsen

time stamping time_signature events

Posted by Anonymous User at 2011-11-02 02:14 AM
Hi

I have managed to get my head around the class structure here (more or less) to create a MidiToTextFile.py based on MidiToText.py

However i have added the facility to report the time of time signature events in the stream, in addition to simply their appearance, as this will assist me in making the text based representation of the score i want to make, with bar markers inserted.

However the times that are being reported do not seem to correlate with their actual positions in the "score time"

For example, I have a time signature of 3/4 occurring after a bar of 2/4, & yet the time signature message reports as being at a point in time not corresponding to duration of the 2/4 bar length or division.

here is the message i create on report of a time signature event in my MidiToText.py

s = "time_signature %i %i %i %i time:%s" % (nn,dd,cc,bb,self.abs_time())


self.textoutfile.write(s + "\n")

assumedly the abs_time() is reporting either:

* a time from an event other than the time sig change, or

* the message itself is not time positioned in the file in a way that is meaningful as an actual reference to the "score" event itself (if that makes sense...)

can anyone help? It would be much appreciated

Tim - Adelaide, Australia

example for multi track MIDI file writing

Posted by Anonymous User at 2011-11-03 07:55 AM
Hi

A couple of messages on here seem to have had difficulties writing multitrack MIDI files as output.

The very short & sweet answer is that you must instantiate a type 1 (or 2 i guess) MIDI file to output to a multitrack MIDI file..

anyway, type 0 (the default) will only create a 1 track output file

here is a brief example of how this is achieved (simply by passing appropriate arguments on instantiation)

>>>


from MidiOutFile import MidiOutFile




out_file = 'test.mid'

m = MidiOutFile(out_file)



# non optional midi framework

m.header(1,3)
#(default params are format=0, nTracks=1, division=96)
# refer MIdiOutFile module for details on the functions & the parameter definition



'''

not sure of necessity

but it may be good practice to put timesig & tempo messages etc on track 0
& start the notes on track 1

'''



# musical events

m.start_of_track(0)

m.update_time(0)

m.time_signature(4,2,24,8)

m.tempo(750000)

m.end_of_track()



m.start_of_track(1)

m.sequence_name('Piano')

m.instrument_name('Piano')



m.update_time(0)

m.note_on(channel=1, note=0x3C)

m.update_time(0)

m.note_on(channel=1, note=0x3E)

m.update_time(0)

m.note_on(channel=1, note=0x43)



# advance duration relative 1/4 note

m.update_time(96)

m.note_off(channel=1, note=0x3C)

m.update_time(0)

m.note_off(channel=1, note=0x3E)

m.update_time(0)

m.note_off(channel=1, note=0x43)

m.update_time(0)



# advance duration relative 1/2 note

m.update_time(192)

m.note_on(channel=1, note=0x3C)

m.update_time(0)

m.note_on(channel=1, note=0x3E)

m.update_time(0)

m.note_on(channel=1, note=0x43)



# advance duration relative 1/4 note

m.update_time(96)

m.note_off(channel=1, note=0x3C)

m.update_time(0)

m.note_off(channel=1, note=0x3E)

m.update_time(0)

m.note_off(channel=1, note=0x43)

m.update_time(0)



m.end_of_track()



# track 2



m.start_of_track(2)

m.sequence_name('bleep')

m.instrument_name('bloop')



m.update_time(0)

m.note_on(channel=1, note=0x3C)

m.note_on(channel=1, note=0x3E)



m.note_on(channel=1, note=0x43)



m.update_time(96)

m.note_off(channel=1, note=0x3C)



m.update_time(0)

m.note_off(channel=1, note=0x3E)

m.note_off(channel=1, note=0x43)

m.end_of_track()



# non optional midi framework

m.update_time(0)

m.end_of_track()



m.eof()



Tim in Adelaide