Python/MIDI prototype for Win32! [0129.2000]
""" I just absolutely cannot believe it took me 10 hours - from around
midnight to 10:00am to get this thing working... I spent most of it
trying to figure out why my tuple wasn't a tuple. Sheesh.... Anyway,
I'm pretty proud of this little script.. It plays the chromatic scale
on a MIDI device... Nothing too useful yet, but it should be, soon! I
just figured I'd post it to my site to show off..
It requires Python, and these modules:
dynwin (for windll, oracle)
npstruct calldll
all of which are available from:
http://www.nightmare.com/software.html
-michal
"""
################################################################
#
# winmidi.py - python module for interfacing with MIDI for windows
# just a test script, based on a VB demo from microsoft...
# 1029.2000 by sabren@manifestation.com
#
############################################################
import sys
# yeah, I know I should do this the right way:
sys.path.append("""c:\program files\python\dynwin""")
MAXPNAMELEN = 32 #Maximum product name length
# Error values for functions used in this sample. See the function for more information
MMSYSERR_BASE = 0
MMSYSERR_BADDEVICEID = (MMSYSERR_BASE + 2) # device ID out of range
MMSYSERR_INVALPARAM = (MMSYSERR_BASE + 11) # invalid parameter passed
MMSYSERR_NODRIVER = (MMSYSERR_BASE + 6) # no device driver present
MMSYSERR_NOMEM = (MMSYSERR_BASE + 7) # memory allocation error
MMSYSERR_INVALHANDLE = (MMSYSERR_BASE + 5) # device handle is invalid
MIDIERR_BASE = 64
MIDIERR_STILLPLAYING = (MIDIERR_BASE + 1) # still something playing
MIDIERR_NOTREADY = (MIDIERR_BASE + 3) # hardware is still busy
MIDIERR_BADOPENMODE = (MIDIERR_BASE + 6) # operation unsupported w/ open mode
import windll
import gencb
import structob
MIDIINCAPS = structob.Oracle (
'MIDI In Capabilities for a Device',
'Nlll' + `MAXPNAMELEN` + 'c2l',
( 'wMid',
'wPid',
'vDriverVersion',
'szPname',
'dwSupport' ))
HANDLE = structob.Oracle (
"just a handle.. in this case to a MIDI thingy...",
"Ll",
("value",)) # need the comma to make it a tuple!!!
# (friggin took me 4 hours to figure that out, too..
MIDIOUTCAPS = structob.Oracle (
'MIDI Out Capabilities for a Device',
'Llll' + `MAXPNAMELEN` + 'cllll2l',
( 'wMid',
'wPid',
'vDriverVersion',
'szPname',
'wTechnology',
'wVoices',
'wNotes',
'wChannelMask',
'dwSupport' ))
winmm = windll.module("winmm")
numDevices = winmm.midiOutGetNumDevs()
print `numDevices` + " MIDI output devices found (besides Mapper):"
import string
# use this to turn the tuple into a string..
def cstr( dict ):
res = ""
for i in dict:
if ord(i) == 0: # 0x00-terminated string
break
else:
res = res + i
return res
for i in range(-1,numDevices): # why must I suvtract one?? : VB does it too.. -1 is the midi mapper
buf = windll.membuf(MIDIOUTCAPS.size)
winmm.midiOutGetDevCaps(i, buf.address(), MIDIOUTCAPS.size)
#print buf.read()
dict, size = MIDIOUTCAPS.unpack (buf.read())
#print "xxxxxxx xx: " + ("x" * 32 )
print "szPname is: " + cstr(dict["szPname"]) #@TODO: WHY IS IT STRIPPING 4 chars?
#@TODO: also, windll has a "cstring" class..
#print `MIDIOUTCAPS.size` + "expected, " + `size` + "received.."
curDevice = -1 # midi mapper
channel = 9 # drums
channel = 0 # piano
baseNote = 60
volume = 127
volume = 40
hmidi = windll.membuf(HANDLE.size)
print "read0:", hmidi.read()
rc = winmm.midiOutOpen(hmidi, curDevice, 0, 0, 0)
print "read1:", hmidi.read()
print "result from midiOutOpen: ", rc
print "hmidi:", HANDLE.unpack (hmidi.read())
handle = HANDLE.unpack(hmidi.read())[0]["value"]
print "handle:", handle
import time
#scale = range(1,8) + range(8,0,-1) # not chromatic.. its just by half notes
scale = (0, 2, 4, 5, 7, 9, 11, 12, 11, 9, 7, 5, 4, 2, 0) # chromatic scale
print scale
for note in scale:
# play a note
midimsg = 0x90 + ((baseNote + note) * 0x100) + (volume * 0x10000) + channel
rc = winmm.midiOutShortMsg (handle, midimsg)
time.sleep(0.25)
# turn it off
midimsg = 0x80 + ((baseNote + note) * 0x100) + channel
rc = winmm.midiOutShortMsg (handle, midimsg)
rc = winmm.midiOutClose(handle) #@TODO: should be value stored in the buffer..
print "result from midiOutClose:", rc
print "........"
# had to add "import calldll" INSIDE windll.module.unload(),
# even though windll imports calldll.. dunno why..
# otherwise it was saying:
#
#Exception exceptions.AttributeError: "'None' object has no attribute 'free_library'" in
# ignored
#
#__END__#