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