MIDI extensions (WIN32, Mac)?
Graham Breed
graham at nospam.microtonal.co.uk
Wed Feb 14 18:25:00 EST 2001
Below is some code that actually works. I don't think it's fully
compliant with the MIDI standard, but you can check that. There's no
obvious problem with speed.
Note: do not use input.read() without an argument. It will block
indefinitely.
I have written code in C to use the MIDI ports in Windows. I don't think
it can be done directly in Python, but I would be interested in working on
a C module.
I have no idea about Macintosh. Hopefully, OSX will behave like Linux in
this respect.
import string
#messages
noteOff = 0x80
noteOn = 0x90
polyAftertouch = 0xA0
controlChange = 0xB0
programChange = 0xC0
monoAftertouch = 0xD0
pitchBend = 0xE0
beginSysEx = 0xF0
songPositionPointer = 0xF2
songSelect = 0xF3
tuneRequest = 0xF6
endSysEx = 0xF7
timingClock = 0xF8
start = 0xFA
cont = 0xFB
stop = 0xFC
activeSensing = 0xFE
systemReset = 0xFF
messagesWithNotes = (noteOn, noteOff, polyAftertouch)
messageNames = {
noteOff: 'note off',
noteOn: 'note on',
polyAftertouch: 'poly aftertouch',
controlChange: 'control change',
programChange: 'program change',
monoAftertouch: 'mono aftertouch',
pitchBend: 'pitch bend',
beginSysEx: 'begin SysEx',
endSysEx: 'end SysEx',
songPositionPointer: 'song position pointer',
songSelect: 'song select',
tuneRequest: 'tune request',
endSysEx: 'end SysEx',
timingClock: 'timing clock',
start: 'start',
cont: 'continue',
stop: 'stop',
activeSensing: 'active sensing',
systemReset: 'system reset'}
nDataBytes = {
noteOff: 2,
noteOn: 2,
polyAftertouch: 2,
controlChange: 2,
programChange: 1,
monoAftertouch: 1,
pitchBend: 2}
noteNames = ('C','C#','D','Eb','E','F','F#',
'G','GA','A','Bb','B')
def isData(byte):
return byte<0x80;
def isChannelMessage(byte):
return 0x80<=byte<0xF0;
def formatNote(noteNum):
return noteNames[noteNum%12] + str(noteNum/12 - 1)
def sendMessage(output, message):
output.write(string.join(map(chr, message),''))
try:
output.flush()
except:
print "couldn't flush"
midiIn = open('/dev/midi00', 'r')
midiOut = open('/dev/midi1','w')
messageNumber = ''
data = []
dataLength = 0
channel=-1
while 1:
inputData = midiIn.read(1)
if len(inputData)>1 :
print 'read to much '+map(hex, map(ord, inputData))
else:
datum = ord(inputData)
if isData(datum):
data.append(datum)
if len(data)==dataLength:
print messageNames[messageNumber], 'channel', channel,
if messageNumber in messagesWithNotes:
print formatNote(data[0]), data[1]
else:
print string.join(map(hex, data))
sendMessage(midiOut, [messageNumber+channel]+data)
data = []
elif isChannelMessage(datum):
channel = datum%16
messageNumber = datum-channel
dataLength = nDataBytes[messageNumber]
if data:
print 'residual data '+string.join(map(hex, data))
data = []
elif datum==beginSysEx:
messageNumber=beginSysEx
dataLength = -1
data = [] # should this be different to the normal data?
elif datum==endSysEx:
if messageNumber != beginSysEx:
print 'end with no beginning'
formattedData = []
for byte in data:
formattedData.append(hex(byte)[-2:])
print 'SysEx', string.replace(string.join(
formattedData,''),'x','0')
sendMessage(midiOut, [beginSysEx]+data+[endSysEx])
data = []
else:
print messageNames.get(datum, 'undefined')
sendMessage(midiOut, datum)
More information about the Python-list
mailing list