/*
* 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 <windows.h>
#include <mmsystem.h>
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