Using Python to generate MIDI files (Mac)

Max M maxm at mxm.dk
Fri Feb 15 11:49:11 EST 2002


kevin parks wrote:


> Anyone have a working module to generate MIDI files? with Python? I
> have seen this asked before, but not really answered. I know that
> there is a module to read MIDI files, and a few shakey attempts to
> send MIDI data in real-time out a port, but I specifically want to
> generate a midi file that i can then further mangle in other programs.

Would you be interrested in a half-hearted attempt??

The problem is that there is the midi filespec, and then there is a 
defacto standard where some elements _must_ be present for a programme 
to read it as a standard midi file.

At some time I WILL get around to finishing it, but as it is a hobby 
project all kind of customer stuff seems to get in the way :-(

regards Max M

Well here is a starter that sort-of works:

def byteString(string):
     return [ord(letter) for letter in string]

def word(value):
     # Big endian 2 byte word
     # returns a list with 2 bytes holding the value
     lsb = value & 0xFF
     msb = value & 0xFF00
     msb = msb >> 8
     return [msb, lsb]

def byte3(value):
     # Big endian 3 byte word
     b1 = value & 0xFF
     b2 = value & 0xFF00
     b3 = value & 0xFF0000
     b2 = b2 >> 8
     b3 = b3 >> 16
     return [b3, b2, b1]

def long(value):
     # Big endian 4 byte word
     b1 = value & 0xFF
     b2 = value & 0xFF00
     b3 = value & 0xFF0000
     b4 = value & 0xFF000000
     b2 = b2 >> 8
     b3 = b3 >> 16
     b4 = b4 >> 24
     return [b4, b3, b2, b1]

def varLen(value):
     # Big endian variable byte word
     # as defined by the midi standard
     result = []
     while value:
         result.append((value & 0x7F) | 0x80)
         value = value >> 7
     if len(result) == 0:
         return [0]
     else:
         result[len(result)-1] -= 128
         result.reverse()
         return result

class midiFile:

     # a midi file to which tracks can be added

     def __init__(self, fileName):
         self.fileName = fileName
         self.file = open(self.fileName, 'w')
         self.tracks = []

     def addTrack(self, item):
         self.tracks.append(item.get())

     def _writeBytes(self, vals):
         # writes a list of values 0-255 to bytes
         bytes = [chr(i) for i in vals]
         for byte in bytes:
             self.file.write(byte)

     def save(self):
         self._writeBytes(byteString('MThd') + long(6) + word(1) + \
                 word(len(self.tracks)) + word(96))
         for track in self.tracks:
             self._writeBytes(track)
         self.file.close()


class track:

     # a Midi Track

     def __init__(self):
         self.events = []

     def addEvent(self, item):
         self.events += item

     def get(self):
         return byteString('MTrk') + long(len(self.events)) + self.events


class events:

     def note_on(self, time, channel, note, velocity):
         return varLen(time) + [0x90 + channel, note, velocity]

     def note_off(self, time, channel, note, velocity):
         return varLen(time) + [0x80 + channel, note, velocity]

     def tempo(self, time=0, bpm=120):
         tempo = int(1000000/(bpm/60.0))
         return varLen(time) + [0xFF, 0x51, 0x03] + byte3(tempo)

     def signature(self, time, nn=4, dd=2):
         # dd => 2^-dd, dd = 1/8 = 2
         return varLen(time) + [0xFF, 0x58, 0x04, nn, dd, 24, 8]

     def text(self, time, value):
         return varLen(time) + [0xFF, 0x01] + byte3(len(value)) +\
                 byteString(value)

     def seqTrackName(self, time, value):
         return varLen(time) + [0xFF, 0x03] + byte3(len(value)) + \
                 byteString(value)

     def lyric(self, time, value):
         return varLen(time) + [0xFF, 0x05] + byte3(len(value)) + \
                 byteString(value)

     def endOfTrack(self, time):
         return varLen(time) + [0xFF, 0x2F, 0x00]

if __name__ == '__main__':

     # This is a library, so test code goes here
     evt = events()

     track1 = track()
     track1.addEvent(evt.tempo(0, bpm=120))
     track1.addEvent(evt.signature(0, 4, 2))
     #track1.addEvent(evt.text(0, 'Test song'))
     track2.addEvent(evt.endOfTrack(0))

##    track2 = track()
##    track2.addEvent(evt.note_on(0, 0, 60, 127))
##    track2.addEvent(evt.note_off(96, 0, 60, 127))
##    track2.addEvent(evt.endOfTrack(96))

     fileName = 'C:/root/pythonScripts/mxm_MIDI/midiOut.mid'
     myMidi = midiFile(fileName)
     myMidi.addTrack(track1)
##    myMidi.addTrack(track2)
     myMidi.save()





More information about the Python-list mailing list