win32 / dynwin.py / callbacks for MIDI input

Michal Wallace sabren at manifestation.com
Sun Feb 6 21:02:46 EST 2000


Hey all,

This is my first post here... sorry if I'm wordy.. I'm just
trying to give enough information to explain this little
puzzle... :)

I am trying to interface with a MIDI keyboard from windows 98.
I've found calldll / dynwin and have successfully used these
to send events TO my keyboard by wrapping some of the
multimedia routines that live in winmm.dll ... After a few long
hours of fumbling arond,  I am able to run my program[1], and
sound comes out of my keyboard.

Now I'd like to go the other way, and get input FROM the
keyboard. According to the Microsoft docs[2], I need to
write a callback... I've looked at the dynwin examples that
use gencb.py , but I'm having a really hard time getting it
to work. Specifically, I keep getting an invalid page fault
error and crashing python. (ouch!)

I'm pretty much a novice when it comes to C/C++,
callbacks,  DLL's and windows programming in
general, and I wondered if maybe someone could
help me out here.. :)

Here's the C function I'm trying to emulate:

void CALLBACK
InProc(  
    HMIDIIN hMidiIn,
    UINT wMsg,
    DWORD dwInstance,
    DWORD dwParam1,
    DWORD dwParam2
);

Here's what I did:

###
import gencb

def midiInProc( handle, msg, instance, param1, param2 ):
    pass

midiInProc_callback = gencb.generated_callback ( "lwlll", midiInProc )
print "callback at:", midiInProc_callback.address

###

This seems to work just fine.. So now I try to call the 
midiInOpen routine to open the device and tell it about
my callback, which is where I get the error.

Here's the C version from the docs:

 MMRESULT midiInOpen(
    LPHMIDIIN lphMidiIn,
    UINT uDeviceID,
    DWORD dwCallback,
    DWORD dwCallbackInstance,
    DWORD dwFlags
);

lphMidiIn is a pointer to the midi-handle that I'm trying to create.
uDeviceID is the number of the device (in my case, 0)
dwCallback is supposed to be the address of my function,
dwCallbackInstance is just a variable it'll pass to dwCallback
so I know which callb
ack to use... and dwFlags needs to be
this:

CALLBACK_FUNCTION = 0x00030000l    # dwCallback is a FARPROC


Here's what I've done:


####

HANDLE = structob.Oracle (
    "just a handle.. in this case to a MIDI thingy...",
    "Ll",
    ("value",))

curDevice = 0 # my keyboard
hmidi = windll.membuf(HANDLE.size)
rc = winmm.midiInOpen(hmidi, curDevice, midiInProc_callback.address, \
        0, CALLBACK_FUNCTION)

print "result code from midiInOpen: ", rc

handle = HANDLE.unpack(hmidi.read())[0]["value"]
print "handle:", handle

# close it..
rc = winmm.midiInClose(handle)
sys.exit(0)

#####

If i run this program over and over, I'll alternate between two
outcomes:

A) The result code for midiInOpen is 0 (meaning it "worked"), and the
    python crashes..

B) the result code is 20 (meaning the port is already opened, because
    I opened it and then the program crashed) but the program continues
    working and then closes the handle..

.... What I think is happening is that when I sucessfully open the
handle, it tries to fire the callback (it's supposed to send a
"just opened device" message).... And I've either screwed up
in defining the callback or passing it to the device, so that
when windows tries to invoke the callback, it actually
screws with some other part of python and python blows up.

Can anyone help me fix this? :)

Thanks!


-Michal Wallace
sabren at manifestation.com


[1] for the curious, the (really messy midi-out prototype) code is at:
http://www.sabren.com/rants/2000/01/20000129a.php3

[2]Microsoft MIDI input callback docs:
http://msdn.microsoft.com/library/psdk/multimed/mmfunc_5u03.htm







More information about the Python-list mailing list