692 lines
20 KiB
C
692 lines
20 KiB
C
|
/****************************************************************************
|
||
|
*
|
||
|
* midiin.c
|
||
|
*
|
||
|
* WDM Audio support for Midi Input devices
|
||
|
*
|
||
|
* Copyright (C) Microsoft Corporation, 1997 - 1999 All Rights Reserved.
|
||
|
*
|
||
|
* History
|
||
|
* 5-12-97 - Noel Cross (NoelC)
|
||
|
*
|
||
|
***************************************************************************/
|
||
|
|
||
|
#include "wdmdrv.h"
|
||
|
#include <stdarg.h>
|
||
|
|
||
|
#ifndef UNDER_NT
|
||
|
#pragma alloc_text(FIXCODE, midiCallback)
|
||
|
#pragma alloc_text(FIXCODE, midiInCompleteHeader)
|
||
|
#endif
|
||
|
|
||
|
/****************************************************************************
|
||
|
|
||
|
This function conforms to the standard Midi input driver message proc
|
||
|
(midMessage), which is documented in mmddk.h
|
||
|
|
||
|
****************************************************************************/
|
||
|
DWORD FAR PASCAL _loadds midMessage
|
||
|
(
|
||
|
UINT id,
|
||
|
UINT msg,
|
||
|
DWORD_PTR dwUser,
|
||
|
DWORD_PTR dwParam1,
|
||
|
DWORD_PTR dwParam2
|
||
|
)
|
||
|
{
|
||
|
LPDEVICEINFO DeviceInfo;
|
||
|
LPDEVICEINFO pInClient;
|
||
|
MMRESULT mmr;
|
||
|
|
||
|
switch (msg)
|
||
|
{
|
||
|
case MIDM_INIT:
|
||
|
DPF(DL_TRACE|FA_MIDI, ("MIDM_INIT") );
|
||
|
return wdmaudAddRemoveDevNode(MidiInDevice, (LPCWSTR)dwParam2, TRUE);
|
||
|
|
||
|
case DRVM_EXIT:
|
||
|
DPF(DL_TRACE|FA_MIDI, ("DRVM_EXIT: MidiIn") );
|
||
|
return wdmaudAddRemoveDevNode(MidiInDevice, (LPCWSTR)dwParam2, FALSE);
|
||
|
|
||
|
case MIDM_GETNUMDEVS:
|
||
|
DPF(DL_TRACE|FA_MIDI, ("MIDM_GETNUMDEVS") );
|
||
|
return wdmaudGetNumDevs(MidiInDevice, (LPCWSTR)dwParam1);
|
||
|
|
||
|
case MIDM_GETDEVCAPS:
|
||
|
DPF(DL_TRACE|FA_MIDI, ("MIDM_GETDEVCAPS") );
|
||
|
if (DeviceInfo = GlobalAllocDeviceInfo((LPWSTR)dwParam2))
|
||
|
{
|
||
|
DeviceInfo->DeviceType = MidiInDevice;
|
||
|
DeviceInfo->DeviceNumber = id;
|
||
|
mmr = wdmaudGetDevCaps(DeviceInfo, (MDEVICECAPSEX FAR*)dwParam1);
|
||
|
GlobalFreeDeviceInfo(DeviceInfo);
|
||
|
return mmr;
|
||
|
} else {
|
||
|
MMRRETURN( MMSYSERR_NOMEM );
|
||
|
}
|
||
|
|
||
|
case MIDM_OPEN:
|
||
|
{
|
||
|
LPMIDIOPENDESC pmod = (LPMIDIOPENDESC)dwParam1;
|
||
|
|
||
|
DPF(DL_TRACE|FA_MIDI, ("MIDM_OPEN") );
|
||
|
if (DeviceInfo = GlobalAllocDeviceInfo((LPWSTR)pmod->dnDevNode))
|
||
|
{
|
||
|
DeviceInfo->DeviceType = MidiInDevice;
|
||
|
DeviceInfo->DeviceNumber = id;
|
||
|
mmr = midiOpen(DeviceInfo, dwUser, pmod, (DWORD)dwParam2);
|
||
|
DPF(DL_TRACE|FA_MIDI,("dwUser(DI)=%08X",dwUser) );
|
||
|
GlobalFreeDeviceInfo(DeviceInfo);
|
||
|
return mmr;
|
||
|
} else {
|
||
|
MMRRETURN( MMSYSERR_NOMEM );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
case MIDM_CLOSE:
|
||
|
DPF(DL_TRACE|FA_MIDI, ("MIDM_CLOSE dwUser(DI)=%08X",dwUser) );
|
||
|
pInClient = (LPDEVICEINFO)dwUser;
|
||
|
|
||
|
if( (mmr=IsValidDeviceInfo(pInClient)) != MMSYSERR_NOERROR )
|
||
|
{
|
||
|
MMRRETURN( mmr );
|
||
|
}
|
||
|
|
||
|
mmr = wdmaudCloseDev( pInClient );
|
||
|
|
||
|
if (MMSYSERR_NOERROR == mmr)
|
||
|
{
|
||
|
#ifdef UNDER_NT
|
||
|
//
|
||
|
// Wait for all of the queued up I/O to come back from
|
||
|
// wdmaud.sys.
|
||
|
//
|
||
|
wdmaudDestroyCompletionThread ( pInClient );
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Tell the caller we're done
|
||
|
//
|
||
|
midiCallback( pInClient, MIM_CLOSE, 0L, 0L);
|
||
|
|
||
|
ISVALIDDEVICEINFO(pInClient);
|
||
|
ISVALIDDEVICESTATE(pInClient->DeviceState,FALSE);
|
||
|
|
||
|
midiCleanUp( pInClient );
|
||
|
}
|
||
|
|
||
|
return mmr;
|
||
|
|
||
|
case MIDM_ADDBUFFER:
|
||
|
DPF(DL_TRACE|FA_MIDI, ("MIDM_ADDBUFFER") );
|
||
|
|
||
|
//
|
||
|
// Don't touch bad pointers!
|
||
|
//
|
||
|
pInClient = (LPDEVICEINFO)dwUser;
|
||
|
|
||
|
if( ( (mmr=IsValidDeviceInfo(pInClient)) != MMSYSERR_NOERROR) ||
|
||
|
( (mmr=IsValidDeviceState(pInClient->DeviceState,FALSE)) != MMSYSERR_NOERROR ) ||
|
||
|
( (mmr=IsValidMidiHeader((LPMIDIHDR)dwParam1)) != MMSYSERR_NOERROR)
|
||
|
)
|
||
|
{
|
||
|
MMRRETURN( mmr );
|
||
|
}
|
||
|
|
||
|
// check if it's been prepared
|
||
|
if (!(((LPMIDIHDR)dwParam1)->dwFlags & MHDR_PREPARED))
|
||
|
MMRRETURN( MIDIERR_UNPREPARED );
|
||
|
|
||
|
DPFASSERT(!(((LPMIDIHDR)dwParam1)->dwFlags & MHDR_INQUEUE));
|
||
|
|
||
|
// if it is already in our Q, then we cannot do this
|
||
|
if ( ((LPMIDIHDR)dwParam1)->dwFlags & MHDR_INQUEUE )
|
||
|
MMRRETURN( MIDIERR_STILLPLAYING );
|
||
|
|
||
|
DPF(DL_TRACE|FA_MIDI,("dwUser(DI)=%08X,dwParam1(HDR)=%08X",pInClient,dwParam1) );
|
||
|
return midiInRead( pInClient, (LPMIDIHDR)dwParam1);
|
||
|
|
||
|
case MIDM_STOP:
|
||
|
DPF(DL_TRACE|FA_MIDI, ("MIDM_STOP dwUser(DI)=%08X",dwUser) );
|
||
|
|
||
|
pInClient = (LPDEVICEINFO)dwUser;
|
||
|
return wdmaudSetDeviceState(pInClient,
|
||
|
IOCTL_WDMAUD_MIDI_IN_STOP);
|
||
|
|
||
|
case MIDM_START:
|
||
|
DPF(DL_TRACE|FA_MIDI, ("MIDM_START dwUser(DI)=%08X",dwUser) );
|
||
|
|
||
|
pInClient = (LPDEVICEINFO)dwUser;
|
||
|
return wdmaudSetDeviceState(pInClient,
|
||
|
IOCTL_WDMAUD_MIDI_IN_RECORD);
|
||
|
|
||
|
case MIDM_RESET:
|
||
|
DPF(DL_TRACE|FA_MIDI, ("MIDM_RESET dwUser(DI)=%08X",dwUser) );
|
||
|
|
||
|
pInClient = (LPDEVICEINFO)dwUser;
|
||
|
return wdmaudSetDeviceState(pInClient,
|
||
|
IOCTL_WDMAUD_MIDI_IN_RESET);
|
||
|
#ifdef MIDI_THRU
|
||
|
case DRVM_ADD_THRU:
|
||
|
case DRVM_REMOVE_THRU:
|
||
|
#endif
|
||
|
|
||
|
default:
|
||
|
MMRRETURN( MMSYSERR_NOTSUPPORTED );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Should not get here
|
||
|
//
|
||
|
|
||
|
DPFASSERT(0);
|
||
|
MMRRETURN( MMSYSERR_NOTSUPPORTED );
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @api void | midiCallback | This calls DriverCallback for a MIDIHDR.
|
||
|
*
|
||
|
* @parm LPDEVICEINFO | pMidiDevice | pointer to midi device.
|
||
|
*
|
||
|
* @parm UINT | msg | The message.
|
||
|
*
|
||
|
* @parm DWORD | dw1 | message DWORD (dw2 is always set to 0).
|
||
|
*
|
||
|
* @rdesc There is no return value.
|
||
|
***************************************************************************/
|
||
|
VOID FAR midiCallback
|
||
|
(
|
||
|
LPDEVICEINFO pMidiDevice,
|
||
|
UINT msg,
|
||
|
DWORD_PTR dw1,
|
||
|
DWORD_PTR dw2
|
||
|
)
|
||
|
{
|
||
|
|
||
|
// invoke the callback function, if it exists. dwFlags contains
|
||
|
// midi driver specific flags in the LOWORD and generic driver
|
||
|
// flags in the HIWORD
|
||
|
|
||
|
if (pMidiDevice->dwCallback)
|
||
|
DriverCallback(pMidiDevice->dwCallback, // user's callback DWORD
|
||
|
HIWORD(pMidiDevice->dwFlags), // callback flags
|
||
|
(HDRVR)pMidiDevice->DeviceHandle, // handle to the midi device
|
||
|
msg, // the message
|
||
|
pMidiDevice->dwInstance, // user's instance data
|
||
|
dw1, // first DWORD
|
||
|
dw2); // second DWORD
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @api DWORD | midiOpen | Open midi device and set up logical device data
|
||
|
*
|
||
|
* @parm LPDEVICEINFO | DeviceInfo | Specifies if it's a midi input or output
|
||
|
* device
|
||
|
*
|
||
|
* @parm DWORD | dwUser | Input parameter to modMessage - pointer to
|
||
|
* application's handle (generated by this routine)
|
||
|
*
|
||
|
* @parm DWORD | pmod | pointer to MIDIOPENDESC, was dwParam1 parameter
|
||
|
* to modMessage
|
||
|
*
|
||
|
* @parm DWORD | dwParam2 | Input parameter to modMessage
|
||
|
*
|
||
|
* @rdesc modMessage return code.
|
||
|
***************************************************************************/
|
||
|
MMRESULT FAR midiOpen
|
||
|
(
|
||
|
LPDEVICEINFO DeviceInfo,
|
||
|
DWORD_PTR dwUser,
|
||
|
LPMIDIOPENDESC pmod,
|
||
|
DWORD dwParam2
|
||
|
)
|
||
|
{
|
||
|
LPDEVICEINFO pClient; // pointer to client information structure
|
||
|
MMRESULT mmr;
|
||
|
#ifndef UNDER_NT
|
||
|
DWORD dwCallback16;
|
||
|
#else
|
||
|
ULONG BufferCount;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// pmod contains a pointer to a MIDIOPENDESC
|
||
|
// dwParam2 contains midi driver specific flags in the LOWORD
|
||
|
// and generic driver flags in the HIWORD
|
||
|
|
||
|
//
|
||
|
// allocate my per-client structure
|
||
|
//
|
||
|
pClient = GlobalAllocDeviceInfo(DeviceInfo->wstrDeviceInterface);
|
||
|
if (NULL == pClient)
|
||
|
{
|
||
|
MMRRETURN( MMSYSERR_NOMEM );
|
||
|
}
|
||
|
|
||
|
pClient->DeviceState = (LPVOID) GlobalAllocPtr( GPTR, sizeof( DEVICESTATE ) );
|
||
|
if (NULL == pClient->DeviceState)
|
||
|
{
|
||
|
GlobalFreeDeviceInfo( pClient );
|
||
|
MMRRETURN( MMSYSERR_NOMEM );
|
||
|
}
|
||
|
|
||
|
#ifdef UNDER_NT
|
||
|
//
|
||
|
// Allocate memory for our critical section
|
||
|
//
|
||
|
pClient->DeviceState->csQueue = (LPVOID) GlobalAllocPtr( GPTR, sizeof( CRITICAL_SECTION ) );
|
||
|
if (NULL == pClient->DeviceState->csQueue)
|
||
|
{
|
||
|
GlobalFreePtr( pClient->DeviceState );
|
||
|
GlobalFreeDeviceInfo( pClient );
|
||
|
MMRRETURN( MMSYSERR_NOMEM );
|
||
|
}
|
||
|
|
||
|
try
|
||
|
{
|
||
|
InitializeCriticalSection( (LPCRITICAL_SECTION)pClient->DeviceState->csQueue );
|
||
|
}
|
||
|
except(EXCEPTION_EXECUTE_HANDLER)
|
||
|
{
|
||
|
GlobalFreePtr( pClient->DeviceState->csQueue );
|
||
|
GlobalFreePtr( pClient->DeviceState );
|
||
|
GlobalFreeDeviceInfo( pClient );
|
||
|
MMRRETURN( MMSYSERR_NOMEM );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// fill out context data
|
||
|
//
|
||
|
pClient->DeviceNumber= DeviceInfo->DeviceNumber;
|
||
|
pClient->DeviceType = DeviceInfo->DeviceType;
|
||
|
pClient->dwInstance = pmod->dwInstance;
|
||
|
pClient->dwCallback = pmod->dwCallback;
|
||
|
#ifdef UNDER_NT
|
||
|
pClient->DeviceHandle= (HANDLE32)pmod->hMidi;
|
||
|
#else
|
||
|
pClient->DeviceHandle= (HANDLE32)MAKELONG(pmod->hMidi,0);
|
||
|
_asm
|
||
|
{
|
||
|
mov ax, offset MidiEventDeviceCallback
|
||
|
mov word ptr [dwCallback16], ax
|
||
|
mov ax, seg MidiEventDeviceCallback
|
||
|
mov word ptr [dwCallback16+2], ax
|
||
|
}
|
||
|
pClient->dwCallback16= dwCallback16;
|
||
|
#endif
|
||
|
pClient->dwFlags = dwParam2;
|
||
|
|
||
|
//
|
||
|
// initialize the device state
|
||
|
//
|
||
|
DPF(DL_TRACE|FA_SYNC,("DI=%08X New DeviceState",pClient) );
|
||
|
pClient->DeviceState->lpMidiInQueue= NULL;
|
||
|
pClient->DeviceState->fPaused = FALSE;
|
||
|
pClient->DeviceState->fRunning = FALSE;
|
||
|
pClient->DeviceState->fExit = FALSE;
|
||
|
|
||
|
pClient->DeviceState->bMidiStatus = 0;
|
||
|
pClient->DeviceState->lpNoteOnMap = NULL;
|
||
|
#ifdef DEBUG
|
||
|
pClient->DeviceState->dwSig = DEVICESTATE_SIGNATURE;
|
||
|
#endif
|
||
|
if (pClient->DeviceType == MidiOutDevice)
|
||
|
{
|
||
|
//
|
||
|
// For MIDI out, allocate one byte per note per channel to track
|
||
|
// what's been played. This is used to avoid doing a brute-force
|
||
|
// all notes off on MODM_RESET.
|
||
|
//
|
||
|
pClient->DeviceState->lpNoteOnMap = GlobalAllocPtr( GPTR, MIDI_NOTE_MAP_SIZE );
|
||
|
if (NULL == pClient->DeviceState->lpNoteOnMap)
|
||
|
{
|
||
|
#ifdef UNDER_NT
|
||
|
GlobalFreePtr( pClient->DeviceState->csQueue );
|
||
|
#endif
|
||
|
GlobalFreePtr( pClient->DeviceState );
|
||
|
GlobalFreeDeviceInfo( pClient );
|
||
|
MMRRETURN( MMSYSERR_NOMEM );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// See if we can open our device
|
||
|
//
|
||
|
mmr = wdmaudOpenDev( pClient, NULL );
|
||
|
|
||
|
if (mmr != MMSYSERR_NOERROR)
|
||
|
{
|
||
|
if ( pClient->DeviceState->lpNoteOnMap )
|
||
|
{
|
||
|
GlobalFreePtr( pClient->DeviceState->lpNoteOnMap );
|
||
|
}
|
||
|
#ifdef UNDER_NT
|
||
|
DeleteCriticalSection( (LPCRITICAL_SECTION)pClient->DeviceState->csQueue );
|
||
|
GlobalFreePtr( pClient->DeviceState->csQueue );
|
||
|
#endif
|
||
|
GlobalFreePtr( pClient->DeviceState );
|
||
|
GlobalFreeDeviceInfo( pClient ) ;
|
||
|
return mmr;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Add instance to chain of devices
|
||
|
//
|
||
|
EnterCriticalSection(&wdmaudCritSec);
|
||
|
pClient->Next = pMidiDeviceList;
|
||
|
pMidiDeviceList = pClient;
|
||
|
LeaveCriticalSection(&wdmaudCritSec);
|
||
|
|
||
|
//
|
||
|
// give the client my driver dw
|
||
|
//
|
||
|
{
|
||
|
LPDEVICEINFO FAR *pUserHandle;
|
||
|
|
||
|
pUserHandle = (LPDEVICEINFO FAR *)dwUser;
|
||
|
*pUserHandle = pClient;
|
||
|
}
|
||
|
|
||
|
#ifndef UNDER_NT
|
||
|
// If this is a MIDI output device, page lock the memory because it can
|
||
|
// be accessed at interrupt time.
|
||
|
//
|
||
|
GlobalSmartPageLock( (HGLOBAL)HIWORD( pClient ));
|
||
|
GlobalSmartPageLock( (HGLOBAL)HIWORD( pClient->DeviceState ));
|
||
|
GlobalSmartPageLock( (HGLOBAL)HIWORD( pClient->DeviceState->lpNoteOnMap ));
|
||
|
#endif
|
||
|
|
||
|
#ifdef UNDER_NT
|
||
|
//
|
||
|
// If this is a MIDI input device on NT, send some buffers
|
||
|
// down to the device in order so that once recording starts
|
||
|
// we can get some data back. The pin is paused after
|
||
|
// the call to wdmaudOpenDev.
|
||
|
//
|
||
|
if ( MidiInDevice == pClient->DeviceType )
|
||
|
{
|
||
|
for (BufferCount = 0; BufferCount < STREAM_BUFFERS; BufferCount++)
|
||
|
{
|
||
|
mmr = wdmaudGetMidiData( pClient, NULL );
|
||
|
if ( MMSYSERR_NOERROR != mmr )
|
||
|
{
|
||
|
//
|
||
|
// We hope that this doesn't happen, but if it does
|
||
|
// we need to try to close down the device.
|
||
|
//
|
||
|
if ( MMSYSERR_NOERROR == wdmaudCloseDev( pClient ) )
|
||
|
{
|
||
|
wdmaudDestroyCompletionThread ( pClient );
|
||
|
midiCleanUp( pClient );
|
||
|
}
|
||
|
DPF( 2, ("midiInOpen failed: returning mmr = %d", mmr ) );
|
||
|
return mmr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// sent client his OPEN callback message
|
||
|
//
|
||
|
midiCallback(pClient, DeviceInfo->DeviceType == MidiOutDevice ? MOM_OPEN : MIM_OPEN,
|
||
|
0L, 0L);
|
||
|
|
||
|
return MMSYSERR_NOERROR;
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @api void | midiCleanUp | Free resources for a midi device
|
||
|
*
|
||
|
* @parm LPDEVICEINFO | pClient | Pointer to a DEVICEINFO structure describing
|
||
|
* resources to be freed.
|
||
|
*
|
||
|
* @rdesc There is no return value.
|
||
|
*
|
||
|
* @comm If the pointer to the resource is NULL then the resource has not
|
||
|
* been allocated.
|
||
|
***************************************************************************/
|
||
|
VOID FAR midiCleanUp
|
||
|
(
|
||
|
LPDEVICEINFO pClient
|
||
|
)
|
||
|
{
|
||
|
LPDEVICEINFO FAR *ppCur ;
|
||
|
|
||
|
//
|
||
|
// remove from device chain
|
||
|
//
|
||
|
EnterCriticalSection(&wdmaudCritSec);
|
||
|
for (ppCur = &pMidiDeviceList;
|
||
|
*ppCur != NULL;
|
||
|
ppCur = &(*ppCur)->Next)
|
||
|
{
|
||
|
if (*ppCur == pClient)
|
||
|
{
|
||
|
*ppCur = (*ppCur)->Next;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
LeaveCriticalSection(&wdmaudCritSec);
|
||
|
|
||
|
DPF(DL_TRACE|FA_SYNC,("DI=%08X Freed DeviceState",pClient) );
|
||
|
|
||
|
#ifdef UNDER_NT
|
||
|
DeleteCriticalSection( (LPCRITICAL_SECTION)pClient->DeviceState->csQueue );
|
||
|
GlobalFreePtr( pClient->DeviceState->csQueue );
|
||
|
#endif
|
||
|
|
||
|
if (pClient->DeviceState->lpNoteOnMap)
|
||
|
{
|
||
|
#ifndef UNDER_NT
|
||
|
GlobalSmartPageUnlock( (HGLOBAL)HIWORD( pClient->DeviceState->lpNoteOnMap ));
|
||
|
#endif
|
||
|
GlobalFreePtr( pClient->DeviceState->lpNoteOnMap );
|
||
|
}
|
||
|
|
||
|
#ifndef UNDER_NT
|
||
|
GlobalSmartPageUnlock( (HGLOBAL)HIWORD( pClient->DeviceState ));
|
||
|
GlobalSmartPageUnlock( (HGLOBAL)HIWORD( pClient ));
|
||
|
#endif
|
||
|
#ifdef DEBUG
|
||
|
//
|
||
|
// In debug, let's set all the values in the DEVICESTATE structure to bad
|
||
|
// values.
|
||
|
//
|
||
|
pClient->DeviceState->cSampleBits=0xDEADBEEF;
|
||
|
pClient->DeviceState->hThread=NULL;
|
||
|
pClient->DeviceState->dwThreadId=0xDEADBEEF;
|
||
|
pClient->DeviceState->lpWaveQueue=NULL;
|
||
|
pClient->DeviceState->csQueue=NULL;
|
||
|
pClient->DeviceState->hevtQueue=NULL;
|
||
|
pClient->DeviceState->hevtExitThread=NULL;
|
||
|
|
||
|
#endif
|
||
|
GlobalFreePtr( pClient->DeviceState );
|
||
|
pClient->DeviceState=NULL;
|
||
|
#ifdef DEBUG
|
||
|
//
|
||
|
// Now set all the values in the DEVICEINFO structure to bad values.
|
||
|
//
|
||
|
// pClient->Next=(LPDEVICEINFO)0xDEADBEEF;
|
||
|
pClient->DeviceNumber=-1;
|
||
|
pClient->DeviceType=0xDEADBEEF;
|
||
|
pClient->DeviceHandle=NULL;
|
||
|
pClient->dwInstance=(DWORD_PTR)NULL;
|
||
|
pClient->dwCallback=(DWORD_PTR)NULL;
|
||
|
pClient->dwCallback16=0xDEADBEEF;
|
||
|
pClient->dwFlags=0xDEADBEEF;
|
||
|
pClient->DataBuffer=NULL;
|
||
|
pClient->HardwareCallbackEventHandle=NULL;
|
||
|
pClient->dwCallbackType=0xDEADBEEF;
|
||
|
pClient->dwLineID=0xDEADBEEF;
|
||
|
pClient->dwFormat=0xDEADBEEF;
|
||
|
// pClient->DeviceState=(LPDEVICESTATE)0xDEADBEEF;
|
||
|
|
||
|
#endif
|
||
|
GlobalFreeDeviceInfo( pClient ) ;
|
||
|
pClient=NULL;
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @api DWORD | midiInRead | Pass a new buffer to the Auxiliary thread for
|
||
|
* a midi device.
|
||
|
*
|
||
|
* @parm LPDEVICEINFO | pClient | The data associated with the logical midi
|
||
|
* device.
|
||
|
*
|
||
|
* @parm LPMIDIHDR | pHdr | Pointer to a midi buffer
|
||
|
*
|
||
|
* @rdesc A MMSYS... type return code for the application.
|
||
|
*
|
||
|
* @comm The buffer flags are set and the buffer is passed to the auxiliary
|
||
|
* device task for processing.
|
||
|
***************************************************************************/
|
||
|
MMRESULT midiInRead
|
||
|
(
|
||
|
LPDEVICEINFO DeviceInfo,
|
||
|
LPMIDIHDR pHdr
|
||
|
)
|
||
|
{
|
||
|
MMRESULT mmr = MMSYSERR_NOERROR;
|
||
|
LPMIDIHDR pTemp;
|
||
|
DWORD dwCallback16;
|
||
|
|
||
|
//
|
||
|
// Put the request at the end of our queue.
|
||
|
//
|
||
|
pHdr->dwFlags |= MHDR_INQUEUE;
|
||
|
pHdr->dwFlags &= ~MHDR_DONE;
|
||
|
pHdr->dwBytesRecorded = 0;
|
||
|
pHdr->lpNext = NULL;
|
||
|
|
||
|
//
|
||
|
// Store the context for this write in the header so that
|
||
|
// we know which client to send this back to on completion.
|
||
|
//
|
||
|
pHdr->reserved = (DWORD_PTR)DeviceInfo;
|
||
|
|
||
|
#ifndef UNDER_NT
|
||
|
//
|
||
|
// Put the long message callback handler into the
|
||
|
// DeviceInfo structure.
|
||
|
//
|
||
|
_asm
|
||
|
{
|
||
|
mov ax, offset MidiInDeviceCallback
|
||
|
mov word ptr [dwCallback16], ax
|
||
|
mov ax, seg MidiInDeviceCallback
|
||
|
mov word ptr [dwCallback16+2], ax
|
||
|
}
|
||
|
DeviceInfo->dwCallback16 = dwCallback16;
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Add the MIDI header to the queue
|
||
|
//
|
||
|
CRITENTER ;
|
||
|
|
||
|
if (!DeviceInfo->DeviceState->lpMidiInQueue)
|
||
|
{
|
||
|
DeviceInfo->DeviceState->lpMidiInQueue = pHdr;
|
||
|
pTemp = NULL;
|
||
|
#ifdef UNDER_NT
|
||
|
if( (DeviceInfo->DeviceState->hevtQueue) &&
|
||
|
(DeviceInfo->DeviceState->hevtQueue != (HANDLE)FOURTYTHREE) &&
|
||
|
(DeviceInfo->DeviceState->hevtQueue != (HANDLE)FOURTYTWO) )
|
||
|
{
|
||
|
DPF(DL_TRACE|FA_SYNC,("REMOVED: SetEvent on hevtQueue") );
|
||
|
// SetEvent( DeviceInfo->DeviceState->hevtQueue );
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (pTemp = DeviceInfo->DeviceState->lpMidiInQueue;
|
||
|
pTemp->lpNext != NULL;
|
||
|
pTemp = pTemp->lpNext);
|
||
|
|
||
|
pTemp->lpNext = pHdr;
|
||
|
}
|
||
|
|
||
|
CRITLEAVE ;
|
||
|
|
||
|
#ifndef UNDER_NT
|
||
|
//
|
||
|
// Call the 16 routine to send the buffer down
|
||
|
// to the kernel. On NT, do all the processing
|
||
|
// of the MIDI data in User mode.
|
||
|
//
|
||
|
mmr = wdmaudSubmitMidiInHeader(DeviceInfo, pHdr);
|
||
|
if (mmr != MMSYSERR_NOERROR)
|
||
|
{
|
||
|
// Unlink...
|
||
|
GlobalFreePtr( pHdr );
|
||
|
|
||
|
if (pTemp)
|
||
|
{
|
||
|
pTemp->lpNext = NULL;
|
||
|
}
|
||
|
else
|
||
|
DeviceInfo->DeviceState->lpMidiInQueue = NULL;
|
||
|
pHdr->dwFlags &= ~WHDR_INQUEUE;
|
||
|
|
||
|
DbgBreak();
|
||
|
MMRRETURN( mmr ); // used to return MMSYSERR_INVALPARAM for all errors!
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return mmr;
|
||
|
}
|
||
|
|
||
|
/****************************************************************************
|
||
|
* @doc INTERNAL
|
||
|
*
|
||
|
* @api VOID | midiInCompleteHeader |
|
||
|
*
|
||
|
* @parm LPDEVICEINFO | DeviceInfo | The data associated with the logical midi
|
||
|
* device.
|
||
|
*
|
||
|
* @comm The buffer flags are set and the buffer is passed to the auxiliary
|
||
|
* device task for processing.
|
||
|
****************************************************************************/
|
||
|
VOID midiInCompleteHeader
|
||
|
(
|
||
|
LPDEVICEINFO DeviceInfo,
|
||
|
DWORD dwTimeStamp,
|
||
|
WORD wDataType
|
||
|
)
|
||
|
{
|
||
|
LPMIDIHDR pHdr;
|
||
|
|
||
|
DPFASSERT(DeviceInfo);
|
||
|
|
||
|
//
|
||
|
// Only remove headers from the front of the queue
|
||
|
// so that order is maintained.
|
||
|
//
|
||
|
if (pHdr = DeviceInfo->DeviceState->lpMidiInQueue)
|
||
|
{
|
||
|
DeviceInfo->DeviceState->lpMidiInQueue = DeviceInfo->DeviceState->lpMidiInQueue->lpNext;
|
||
|
|
||
|
DPF(DL_TRACE|FA_MIDI, ("Pulling header out of queue") );
|
||
|
pHdr->dwFlags &= ~MHDR_INQUEUE;
|
||
|
pHdr->dwFlags |= MHDR_DONE;
|
||
|
pHdr->lpNext = NULL;
|
||
|
|
||
|
midiCallback((LPDEVICEINFO)pHdr->reserved,
|
||
|
wDataType, // MIM_LONGDATA or MIM_LONGERROR
|
||
|
(DWORD_PTR)pHdr,
|
||
|
dwTimeStamp);
|
||
|
}
|
||
|
}
|