sabren.net   rants   archive   bio   portfolio


« index »

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__#


« index »