Python Midi Package
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
pydrums
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
Replies to this comment
mixing midi
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
am I missing something?
Replies to this comment
Notes !
how do i know wich note is note=0x41 ....
which note represents ,,,, there is any manual ou something so see all notes in Hex
thnx
Replies to this comment
python midi with 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
Replies to this comment
Great Module!
Blender and Midi
Johnny Matthews
Replies to this comment
typo
dispatch.sysex_event(sysex_data)
Playing midi
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
Replies to this comment
How to create more then 1 track.
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.
Replies to this comment
Thanks for the Python MIDI Package
- Sami Kyostila
Midi out to another program
Problem with flats in Key Signature
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!
Replies to this comment
Absolute time
I'd like to know at which point in seconds a note is to be played.
Thanks
Replies to this comment
abs_time
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
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
Replies to this comment
do somebody want wave??
"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
Now supporting 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
Replies to this comment
Bug in pitch bend output
@@ -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??
Replies to this comment
rests
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).
Replies to this comment
Instrument
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!
Replies to this comment
Simple math operations with MIDI
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
Replies to this comment
I have question about create piano midi
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
update for Python v3.0?
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?
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()
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
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?
Replies to this comment
bugs
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
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
Wilbert Berendsen
time stamping time_signature events
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
Replies to this comment
example for multi track MIDI file writing
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
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