/* * MIDI.xs --- Windows 32bit MIDI API Wrapper Module * * $Id: MIDI.xs,v 1.10 2003-03-18 01:05:51-05 hiroo Exp $ * * Copyright (c) 2002 Hiroo Hayashi. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the same terms as Perl itself. * * For more detail of Windows 32bit MIDI API, visit * http://msdn.microsoft.com/library/ * Graphics and Multimedia * -> Windows Multimedia * -> SDK Documentation * -> Windows Multimedia * -> Multimedia Audio * -> Musical Instrument Digital Interface (MIDI) */ #ifdef __cplusplus extern "C" { #endif #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #ifdef __cplusplus } #endif #include #include static MMRESULT mmsyserr = MMSYSERR_NOERROR; static SV *midiInProc = NULL; static void CALLBACK /* without CALLBACK we have segfault */ midiInProc_wrapper(hMidiIn, wMsg, dwInstance, dwParam1, dwParam2) HMIDIIN hMidiIn; UINT wMsg; DWORD dwInstance; DWORD dwParam1; DWORD dwParam2; { dSP; ENTER; SAVETMPS; PUSHMARK(SP); #if 0 warn("midiInProc_wrapper: %p at %p, %x, %x, %x, %x\n", hMidiIn, &hMidiIn, wMsg, dwInstance, dwParam1, dwParam2); if (dwParam1) { MIDIHDR *p = (MIDIHDR *)dwParam1; printf("%p, %lx, %lx, %lx, %lx, %p, %p, %lx\n", p->lpData, p->dwBufferLength, p->dwBytesRecorded, p->dwUser, p->dwFlags, p->lpNext, p->reserved, p->dwOffset); } if (dwParam1) { MIDIHDR *p = (MIDIHDR *)dwParam1; printf("%p, %lx\n", p->lpData, p->dwBufferLength); } #endif if (hMidiIn) { SV* rv = sv_newmortal(); sv_setref_pv(rv, "Win32API::MIDI::In", hMidiIn); XPUSHs(rv); } else { XPUSHs(&PL_sv_undef); } XPUSHs(sv_2mortal(newSViv(wMsg))); XPUSHs(sv_2mortal(newSViv(dwInstance))); XPUSHs(sv_2mortal(newSViv(dwParam1))); XPUSHs(sv_2mortal(newSViv(dwParam2))); PUTBACK; call_sv(midiInProc, G_DISCARD); FREETMPS; LEAVE; } /* define constants in mmsystem.h */ #include "mmsystem.xs" /*MODULE = Win32::MIDI PACKAGE = Win32::MIDI PREFIX = midi*/ MODULE = Win32API::MIDI PACKAGE = Win32API::MIDI double constant(sv,arg) PREINIT: STRLEN len; INPUT: SV * sv char * s = SvPV(sv, len); int arg CODE: RETVAL = constant(s,len,arg); OUTPUT: RETVAL int midisyserr() PROTOTYPE: CODE: RETVAL = mmsyserr; OUTPUT: RETVAL # MIDI Services # Quering MIDI Devices UINT midiInGetNumDevs() PROTOTYPE: UINT midiOutGetNumDevs() PROTOTYPE: =pod MMRESULT midiOutGetDevCaps( UINT uDeviceID, LPMIDIOUTCAPS lpMidiOutCaps, <- return value UINT cbMidiOutCaps ); typedef struct { WORD wMid; WORD wPid; MMVERSION vDriverVersion; CHAR szPname[MAXPNAMELEN]; WORD wTechnology; WORD wVoices; WORD wNotes; WORD wChannelMask; DWORD dwSupport; } MIDIOUTCAPS; =cut # midiOutGetDevCaps returns hash reference HV * midiOutGetDevCaps(uDeviceID = MIDI_MAPPER) unsigned int uDeviceID PROTOTYPE: ;$ PREINIT: MIDIOUTCAPS moc; HV * rh; CODE: { mmsyserr = midiOutGetDevCaps(uDeviceID, &moc, sizeof(MIDIOUTCAPS)); rh = (HV *)sv_2mortal((SV *)newHV()); if (mmsyserr == MMSYSERR_NOERROR) { hv_store(rh, "wMid", 4, newSVnv(moc.wMid), 0); hv_store(rh, "wPid", 4, newSVnv(moc.wPid), 0); hv_store(rh, "vDriverVersion", 14, newSVnv(moc.vDriverVersion), 0); hv_store(rh, "szPname", 7, newSVpv(moc.szPname, 0), 0); hv_store(rh, "wTechnology", 4, newSVnv(moc.wTechnology), 0); hv_store(rh, "wVoices", 7, newSVnv(moc.wVoices), 0); hv_store(rh, "wNotes", 6, newSVnv(moc.wNotes), 0); hv_store(rh, "wChannelMask", 12, newSVnv(moc.wChannelMask), 0); hv_store(rh, "dwSupport", 9, newSVnv(moc.dwSupport), 0); } else { /* return undef */ } RETVAL = rh; } OUTPUT: RETVAL =pod MMRESULT midiInGetDevCaps( UINT_PTR uDeviceID, LPMIDIINCAPS lpMidiInCaps, UINT cbMidiInCaps ); typedef struct { WORD wMid; WORD wPid; MMVERSION vDriverVersion; CHAR szPname[MAXPNAMELEN]; DWORD dwSupport; } MIDIINCAPS; =cut # midiInGetDevCaps returns hash reference HV * midiInGetDevCaps(uDeviceID) unsigned int uDeviceID PROTOTYPE: $ INIT: MIDIINCAPS mic; HV * rh; CODE: { mmsyserr = midiInGetDevCaps(uDeviceID, &mic, sizeof(MIDIINCAPS)); rh = (HV *)sv_2mortal((SV *)newHV()); if (mmsyserr == MMSYSERR_NOERROR) { hv_store(rh, "wMid", 4, newSVnv(mic.wMid), 0); hv_store(rh, "wPid", 4, newSVnv(mic.wPid), 0); hv_store(rh, "vDriverVersion", 14, newSVnv(mic.vDriverVersion), 0); hv_store(rh, "szPname", 7, newSVpv(mic.szPname, 0), 0); hv_store(rh, "dwSupport", 9, newSVnv(mic.dwSupport), 0); } else { /* return undef */ } RETVAL = rh; } OUTPUT: RETVAL =pod MMRESULT midiConnect( HMIDI hMidi, HMIDIOUT hmo, LPVOID pReserved ); MMRESULT midiDisconnect( HMIDI hMidi, HMIDIOUT hmo, LPVOID pReserved ); =cut MMRESULT midiConnect(HMIDI hMidi, HMIDIOUT hmo) C_ARGS: hMidi, hmo, NULL MMRESULT midiDisconnect(HMIDI hMidi, HMIDIOUT hmo) C_ARGS: hMidi, hmo, NULL ######################################################################## MODULE = Win32API::MIDI PACKAGE = Win32API::MIDI::In PREFIX = midiIn =pod # Opening and Closing Device Drivers MMRESULT midiInOpen( LPHMIDIIN lphMidiIn, UINT uDeviceID, DWORD_PTR dwCallback, DWORD_PTR dwCallbackInstance, DWORD dwFlags ); MMRESULT midiInClose( HMIDIIN hMidiIn ); =cut HMIDIIN midiInOpen(unsigned int uDeviceID, \ SV * dwCallback, \ DWORD dwCallbackInstance = (DWORD)NULL, \ DWORD dwFlags = CALLBACK_FUNCTION) PROTOTYPE: $$;$$ PREINIT: HMIDIIN h; CODE: { switch (dwFlags) { case CALLBACK_NULL: /* For what this is? */ mmsyserr = midiInOpen(&h, uDeviceID, (DWORD_PTR)NULL, (DWORD_PTR)NULL, dwFlags); RETVAL = mmsyserr == MMSYSERR_NOERROR ? h : NULL; break; case CALLBACK_FUNCTION: if (SvTRUE(dwCallback)) { if (midiInProc) { SvSetSV(midiInProc, dwCallback); } else { midiInProc = newSVsv(dwCallback); } } else { if (midiInProc) { SvSetSV(midiInProc, &PL_sv_undef); } } #if 0 warn("2: %p at %p, %x, %p, %x, %x\n", h, &h, uDeviceID, (DWORD_PTR)midiInProc_wrapper, dwCallbackInstance, dwFlags); #endif mmsyserr = midiInOpen(&h, uDeviceID, (DWORD_PTR)midiInProc_wrapper, (DWORD_PTR)dwCallbackInstance, dwFlags); RETVAL = mmsyserr == MMSYSERR_NOERROR ? h : NULL; break; default: warn("Gnu.xs:midiInOpen[%d]: only CALLBACK_FUNCTION is supported for dwFlags.\n", dwFlags); RETVAL = NULL; } } OUTPUT: RETVAL MMRESULT midiInClose(HMIDIIN hmi) PROTOTYPE: $ =pod Managing MIDI Data Blocks MMRESULT midiInPrepareHeader( HMIDIIN hmi, LPMIDIHDR lpMidiInHdr, UINT cbMidiInHdr ); MMRESULT midiInUnprepareHeader( HMIDIIN hmi, LPMIDIHDR lpMidiInHdr, UINT cbMidiInHdr ); typedef struct { LPSTR lpData; DWORD dwBufferLength; DWORD dwBytesRecorded; DWORD_PTR dwUser; DWORD dwFlags; struct midihdr_tag far * lpNext; DWORD_PTR reserved; DWORD dwOffset; DWORD_PTR dwReserved[4]; } MIDIHDR; =cut MMRESULT midiInPrepareHeader(HMIDIIN hmi, LPMIDIHDR lpMidiInHdr) PROTOTYPE: $$ C_ARGS: hmi, lpMidiInHdr, sizeof(MIDIHDR) =pod MMRESULT midiInPrepareHeader(HMIDIIN hmi, LPMIDIHDR lpMidiInHdr) PROTOTYPE: $$ CODE: { LPMIDIHDR p = lpMidiInHdr; printf("midiInPrepareHeader: %p,%p,%4s,%x,%x,%x\n", p, p->lpData, p->lpData, p->dwBufferLength, p->dwBytesRecorded, p->dwUser); RETVAL = midiInPrepareHeader(hmi, lpMidiInHdr, sizeof(MIDIHDR)); } =cut MMRESULT midiInUnprepareHeader(HMIDIIN hmi, LPMIDIHDR lpMidiInHdr) PROTOTYPE: $$ C_ARGS: hmi, lpMidiInHdr, sizeof(MIDIHDR) MMRESULT midiInAddBuffer(HMIDIIN hmi, LPMIDIHDR lpMidiInHdr) PROTOTYPE: $$ C_ARGS: hmi, lpMidiInHdr, sizeof(MIDIHDR) MMRESULT midiInReset(HMIDIIN hmi) PROTOTYPE: $ MMRESULT midiInStart(HMIDIIN hmi) PROTOTYPE: $ MMRESULT midiInStop(HMIDIIN hmi) PROTOTYPE: $ =pod Handling Errors with MIDI Functions MMRESULT midiInGetErrorText( MMRESULT wError, LPSTR lpText, UINT cchText ); =cut SV * midiInGetErrorText(SV *stub, MMRESULT wError = mmsyserr) PROTOTYPE: $;$ PREINIT: char text[MAXERRORLENGTH]; CODE: ST(0) = sv_newmortal(); mmsyserr = midiInGetErrorText(wError, text, MAXERRORLENGTH); if (mmsyserr == MMSYSERR_NOERROR) { sv_setpv(ST(0), text); } SV * midiInGetID(HMIDIIN hmi) PROTOTYPE: $ PREINIT: UINT id; CODE: ST(0) = sv_newmortal(); mmsyserr = midiInGetID(hmi, &id); if (mmsyserr == MMSYSERR_NOERROR) { sv_setuv(ST(0), id); } ######################################################################## MODULE = Win32API::MIDI PACKAGE = Win32API::MIDI::Out PREFIX = midiOut =pod # Opening and Closing Device Drivers MMRESULT midiOutOpen( LPHMIDIOUT lphmo, <- return value UINT uDeviceID, DWORD_PTR dwCallback, DWORD_PTR dwCallbackInstance, DWORD dwFlags ); MMRESULT midiOutClose( HMIDIOUT hmo ); =cut HMIDIOUT midiOutOpen(unsigned int uDeviceID = MIDI_MAPPER, \ DWORD dwCallback = (DWORD)NULL, \ DWORD dwCallbackInstance = (DWORD)NULL, \ DWORD dwFlags = CALLBACK_NULL) PROTOTYPE: ;$$$$ PREINIT: HMIDIOUT h; CODE: { switch (dwFlags) { case CALLBACK_NULL: mmsyserr = midiOutOpen(&h, uDeviceID, dwCallback, dwCallbackInstance, dwFlags); RETVAL = (mmsyserr == MMSYSERR_NOERROR) ? h : NULL; break; default: warn("Gnu.xs:midiOutOpen[%d]: only CALLBACK_NULL is supported for dwFlags.\n", dwFlags); RETVAL = NULL; } } OUTPUT: RETVAL MMRESULT midiOutClose(HMIDIOUT hmo) PROTOTYPE: $ =pod Sending Individual MIDI Messages MMRESULT midiOutLongMsg( HMIDIOUT hmo, LPMIDIHDR lpMidiOutHdr, UINT cbMidiOutHdr ); MMRESULT midiOutReset( HMIDIOUT hmo ); MMRESULT midiOutShortMsg( HMIDIOUT hmo, DWORD dwMsg ); =cut MMRESULT midiOutLongMsg(HMIDIOUT hmo, LPMIDIHDR lpMidiOutHdr) PROTOTYPE: $$ C_ARGS: hmo, lpMidiOutHdr, sizeof(MIDIHDR) MMRESULT midiOutReset(HMIDIOUT hmo) PROTOTYPE: $ MMRESULT midiOutShortMsg(HMIDIOUT hmo, DWORD dwMsg) PROTOTYPE: $$ =pod Managing MIDI Data Blocks MMRESULT midiOutPrepareHeader( HMIDIOUT hmo, LPMIDIHDR lpMidiOutHdr, UINT cbMidiOutHdr ); MMRESULT midiOutUnprepareHeader( HMIDIOUT hmo, LPMIDIHDR lpMidiOutHdr, UINT cbMidiOutHdr ); typedef struct { LPSTR lpData; !!! DWORD dwBufferLength; !!! DWORD dwBytesRecorded; DWORD_PTR dwUser; DWORD dwFlags; !!!zero struct midihdr_tag far * lpNext; DWORD_PTR reserved; DWORD dwOffset; DWORD_PTR dwReserved[4]; # [8]? } MIDIHDR; =cut MMRESULT midiOutPrepareHeader(HMIDIOUT hmo, LPMIDIHDR lpMidiOutHdr) PROTOTYPE: $$ C_ARGS: hmo, lpMidiOutHdr, sizeof(MIDIHDR) MMRESULT midiOutUnprepareHeader(HMIDIOUT hmo, LPMIDIHDR lpMidiOutHdr) PROTOTYPE: $$ C_ARGS: hmo, lpMidiOutHdr, sizeof(MIDIHDR) =pod Handling Errors with MIDI Functions UINT midiOutGetErrorText( MMRESULT mmrError, LPSTR lpText, UINT cchText ); =cut SV * midiOutGetErrorText(SV *stub, MMRESULT wError = mmsyserr) PROTOTYPE: $;$ PREINIT: char text[MAXERRORLENGTH]; CODE: { ST(0) = sv_newmortal(); mmsyserr = midiOutGetErrorText(wError, text, MAXERRORLENGTH); if (mmsyserr == MMSYSERR_NOERROR) { sv_setpv(ST(0), text); } } =pod MMRESULT midiOutGetID( HMIDIOUT hmo, LPUINT puDeviceID ); =cut UINT midiOutGetID(HMIDIOUT hmo) PROTOTYPE: $ PREINIT: UINT id; CODE: mmsyserr = midiOutGetID(hmo, &id); ST(0) = sv_newmortal(); if (mmsyserr == MMSYSERR_NOERROR) { sv_setuv(ST(0), id); } ######################################################################## MODULE = Win32API::MIDI PACKAGE = Win32API::MIDI::Stream PREFIX = midiStream =pod midiStreamOpen MMRESULT midiStreamOpen( LPHMIDISTRM lphStream, LPUINT puDeviceID, DWORD cMidi, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen ); MMRESULT midiStreamClose( HMIDISTRM hStream ); MMRESULT midiStreamOut( HMIDISTRM hMidiStream, LPMIDIHDR lpMidiHdr, UINT cbMidiHdr ); MMRESULT midiStreamRestart( HMIDISTRM hms ); MMRESULT midiStreamPause( HMIDISTRM hms ); MMRESULT midiStreamStop( HMIDISTRM hms ); MMRESULT midiStreamPosition( HMIDISTRM hms, LPMMTIME pmmt, UINT cbmmt ); MMRESULT midiStreamProperty( HMIDISTRM hms, LPBYTE lppropdata, DWORD dwProperty ); =cut HMIDISTRM midiStreamOpen(unsigned int uDeviceID = MIDI_MAPPER, \ DWORD dwCallback = (DWORD)NULL, \ DWORD dwInstance = (DWORD)NULL, \ DWORD fdwOpen = CALLBACK_NULL) PROTOTYPE: ;$$$$ PREINIT: HMIDISTRM h; CODE: { switch (fdwOpen) { case CALLBACK_NULL: mmsyserr = midiStreamOpen(&h, &uDeviceID, 1, dwCallback, dwInstance, fdwOpen); RETVAL = (mmsyserr == MMSYSERR_NOERROR) ? h : NULL; break; default: warn("Gnu.xs:midiStreamOpen[%d]: only CALLBACK_NULL is supported for fdwOpen.\n", fdwOpen); RETVAL = NULL; } } OUTPUT: RETVAL MMRESULT midiStreamClose(HMIDISTRM hStream) PROTOTYPE: $ MMRESULT midiStreamOut(HMIDISTRM hMidiStream, LPMIDIHDR lpMidiHdr) PROTOTYPE: $$ C_ARGS: hMidiStream, lpMidiHdr, sizeof(MIDIHDR) MMRESULT midiStreamRestart(HMIDISTRM hms); PROTOTYPE: $ MMRESULT midiStreamPause(HMIDISTRM hms); PROTOTYPE: $ MMRESULT midiStreamStop(HMIDISTRM hms); PROTOTYPE: $ MMRESULT midiStreamPosition(HMIDISTRM hms, LPMMTIME pmmt); PROTOTYPE: $$$ C_ARGS: hms, pmmt, sizeof(MMTIME) MMRESULT midiStreamProperty(HMIDISTRM hms, LPBYTE lppropdata, int dwProperty); PROTOTYPE: $$$ ######################################################################## =pod - : ignore ?midiOutGetVolume (for internal MIDI synthesizer?) ?midiOutSetVolume (for internal MIDI synthesizer?) -midiOutCacheDrumPatches (for internal MIDI synthesizer) -midiOutCachePatches (for internal MIDI synthesizer) -midiOutMessage (send message to device driver) -midiInMessage (send message to device driver) /* * Local Variables: * c-default-style: "gnu" * End: */ =cut