|
|
/*****************************************************************************
map.c
midi mapper run-time
Copyright (c) Microsoft Corporation 1990-1991. All rights reserved
*****************************************************************************/
#include <windows.h>
#include <string.h>
#include <mmsystem.h>
#if defined(WIN32)
#include <port1632.h>
#endif
#include "hack.h"
#include <mmddk.h>
#include "midimap.h"
#include "midi.h"
#include "extern.h"
#include "mmreg.h"
#define ISSTATUS(bData) ((bData) & 0x80)
#define FILTERCHANNEL(bStatus) ((BYTE)((bStatus) & 0xf0))
#define FILTERSTATUS(bStatus) ((BYTE)((bStatus) & 0x0f))
#define STATUS_NOTEOFF 0x80
#define STATUS_NOTEON 0x90
#define STATUS_POLYPHONICKEY 0xa0
#define STATUS_CONTROLCHANGE 0xb0
#define STATUS_PROGRAMCHANGE 0xc0
#define STATUS_CHANNELPRESSURE 0xd0
#define STATUS_PITCHBEND 0xe0
#define STATUS_SYS 0xf0
#define STATUS_SYSEX 0xf0
#define STATUS_QFRAME 0xf1
#define STATUS_SONGPOINTER 0xf2
#define STATUS_SONGSELECT 0xf3
#define STATUS_F4 0xf4
#define STATUS_F5 0xf5
#define STATUS_TUNEREQUEST 0xf6
#define STATUS_EOX 0xf7
#define STATUS_TIMINGCLOCK 0xf8
#define STATUS_F9 0xf9
#define STATUS_START 0xfa
#define STATUS_CONTINUE 0xfb
#define STATUS_STOP 0xfc
#define STATUS_FD 0xfd
#define STATUS_ACTIVESENSING 0xfe
#define STATUS_SYSTEMRESET 0xff
#define CONTROL_VOLUME 0x07
#define MIDIDATABUFFER 512
#define STATE_MAPNAILED 0x0001
#define STATE_DATANAILED 0x0002
#define STATE_CODENAILED 0x0004
/*****************************************************************************
local structures
*****************************************************************************/
typedef unsigned char huge * HPBYTE;
#define DEV_PREPARED 0x0001
typedef struct mididev_tag { WORD wDeviceID; WORD wChannel; WORD fwFlags; HMIDIOUT hMidi; } MIDIDEV; typedef MIDIDEV *PMIDIDEV;
/*****************************************************************************
local data
*****************************************************************************/
/*
* critical section used to protect the open so that there is no * window in which two threads could open simultaneously - otherwise * with all these statics there would be a major accident */ CRITICAL_SECTION MapperCritSec;
static HGLOBAL hCurMap; // handle of current midi map
static WORD wChannelMask; // which channels are on
static UINT uPatchMask; // which channels have patch maps
static MIDIDEV mapdevs[16]; // contains device info. for each midi device in the current map.
static MIDIDEV chnldevs[16]; // map channels to midi devices.
static LPMIDIPATCHMAP lpPMap; // current patch map
static LPMIDIKEYMAP lpKMap; // current key map
static BYTE curpatch[16]; // what is the currently selected patch for each channel
static BYTE status; // virtual running status
static BYTE bCurrentStatus; // Current message type
static BYTE fActiveChannel; // Channel message to active channel
static BYTE bCurrentLen; // Current message length, if any
static DWORD_PTR OpenCallback; // Open Callback parameter
static DWORD_PTR OpenInstance; // Open Instance parameter
static DWORD OpenFlags; // Open Param2
static HMIDIOUT hmidiMapper; // Handle of current mapper device
static LPMIDIHDR pmidihdrMapper; // Buffer used for mapped devices
static UINT ufStateFlags; // State flags for device
extern BYTE FAR bMidiLengths[]; // Lengths in lengths.c
extern BYTE FAR bSysLengths[]; // Lengths in lengths.c
#define MIDILENGTH(bStatus) (bMidiLengths[((bStatus) & 0x70) >> 4])
#define SYSLENGTH(bStatus) (bSysLengths[(bStatus) & 0x07])
#define lpCurMap ((LPMIDIMAP)hCurMap) // pointer to current midi map
UINT mapLockCount;
UINT FAR PASCAL modGetDevCaps(LPMIDIOUTCAPSW lpCaps, UINT uSize); UINT FAR PASCAL modCachePatches(UINT msg, UINT uBank, LPPATCHARRAY lpPatchArray, UINT uFlags); static UINT FAR PASCAL midiReadCurrentSetup(LPMIDIOPENDESC lpOpen, DWORD dwParam2);
LRESULT FAR PASCAL DriverProc(DWORD, HDRVR, UINT, LPARAM, LPARAM);
static void NEAR PASCAL modShortData(LPBYTE pbData); static void NEAR PASCAL modLongData(HPBYTE pbData, DWORD dDataLength); static void NEAR PASCAL modTranslateEvent(LPBYTE pbData, BYTE bStart, BYTE bLength);
DWORD FAR PASCAL _loadds modMessage(UINT id, UINT msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2); static void PASCAL FAR CallbackNotification(UINT message, DWORD dwParam); static void NEAR PASCAL modSendLongData(UINT uMessageLength, BOOL fBroadcast, BOOL force); static BOOL NEAR PASCAL modHeaderDone(void);
static void PASCAL NEAR ReleaseResources(void);
static UINT PASCAL NEAR TranslateError(MMAPERR mmaperr) { switch (mmaperr) { case MMAPERR_INVALIDPORT: return MIDIERR_NODEVICE; case MMAPERR_MEMORY: return MMSYSERR_NOMEM; case MMAPERR_INVALIDSETUP: return MIDIERR_INVALIDSETUP; } return MIDIERR_NOMAP; }
#if defined(WIN16)
static BOOL NEAR PASCAL GlobalNail( HGLOBAL hSegment, UINT uFlag) { if (GlobalWire(hSegment)) { if (GlobalPageLock(hSegment)) { ufStateFlags |= uFlag; return TRUE; } GlobalUnWire(hSegment); } return FALSE; }
static void NEAR PASCAL GlobalUnNail( HGLOBAL hSegment, UINT uFlag) { if (ufStateFlags & uFlag) { GlobalPageUnlock(hSegment); GlobalUnWire(hSegment); ufStateFlags &= ~uFlag; } } #endif //WIN16
static void PASCAL NEAR ReleaseResources(void) { WORD wDevice;
#ifdef WIN16
GlobalUnNail((HGLOBAL)HIWORD((DWORD)(LPVOID)&hCurMap), STATE_DATANAILED); GlobalUnNail(hCurMap, STATE_MAPNAILED); GlobalUnNail((HGLOBAL)HIWORD(DriverProc), STATE_CODENAILED); #endif // WIN16
for (wDevice = 0; (wDevice < 16) && (mapdevs[wDevice].wDeviceID != (WORD)(-1)); wDevice++) { if (mapdevs[wDevice].hMidi) { midiOutReset(mapdevs[wDevice].hMidi); if (mapdevs[wDevice].fwFlags & DEV_PREPARED) { midiOutUnprepareHeader(mapdevs[wDevice].hMidi, pmidihdrMapper, sizeof(MIDIHDR)); mapdevs[wDevice].fwFlags &= ~DEV_PREPARED; } midiOutClose(mapdevs[wDevice].hMidi); mapdevs[wDevice].hMidi = NULL; mapdevs[wDevice].wDeviceID = (WORD)(-1); } } if (hCurMap) { GlobalFree(hCurMap); hCurMap = NULL; } if (pmidihdrMapper) { HGLOBAL hmem = GlobalHandle( pmidihdrMapper ); GlobalUnlock( hmem ); GlobalFree( hmem ); pmidihdrMapper = NULL; } }
static UINT PASCAL FAR CloseMidiDevice( void) { ReleaseResources(); CallbackNotification(MOM_CLOSE, 0); return 0; }
static void PASCAL FAR CallbackNotification( UINT message, DWORD dwParam) { if (OpenCallback) DriverCallback( OpenCallback , HIWORD(OpenFlags) | DCB_NOSWITCH , (HANDLE)hmidiMapper , message , OpenInstance , dwParam , 0 ); }
/***************************************************************************
* @doc INTERNAL * * @api LRESULT | DriverProc | The entry point for an installable driver. * * @parm DWORD | dwDriverId | For most messages, <p dwDriverId> is the DWORD * value that the driver returns in response to a <m DRV_OPEN> message. * Each time that the driver is opened, through the <f DrvOpen> API, * the driver receives a <m DRV_OPEN> message and can return an * arbitrary, non-zero value. The installable driver interface * saves this value and returns a unique driver handle to the * application. Whenever the application sends a message to the * driver using the driver handle, the interface routes the message * to this entry point and passes the corresponding <p dwDriverId>. * This mechanism allows the driver to use the same or different * identifiers for multiple opens but ensures that driver handles * are unique at the application interface layer. * * The following messages are not related to a particular open * instance of the driver. For these messages, the dwDriverId * will always be zero. * * DRV_LOAD, DRV_FREE, DRV_ENABLE, DRV_DISABLE, DRV_OPEN * * @parm HDRVR | hDriver | This is the handle returned to the * application by the driver interface. * * @parm UINT | wMessage | The requested action to be performed. Message * values below <m DRV_RESERVED> are used for globally defined messages. * Message values from <m DRV_RESERVED> to <m DRV_USER> are used for * defined driver protocols. Messages above <m DRV_USER> are used * for driver specific messages. * * @parm LPARAM | lParam1 | Data for this message. Defined separately for * each message * * @parm LPARAM | lParam2 | Data for this message. Defined separately for * each message * * @rdesc Defined separately for each message. ***************************************************************************/
LRESULT FAR PASCAL DriverProc(DWORD dwDriverID, HDRVR hDriver, UINT wMessage, LPARAM lParam1, LPARAM lParam2) { //
// NOTE DS is not valid here.
//
switch (wMessage) {
case DRV_LOAD: InitializeCriticalSection(&MapperCritSec); return (LRESULT)TRUE;
case DRV_FREE: DeleteCriticalSection(&MapperCritSec); return (LRESULT)TRUE;
case DRV_OPEN: case DRV_CLOSE: return (LRESULT)TRUE; case DRV_INSTALL: case DRV_REMOVE: return (LRESULT)DRVCNF_RESTART;
default: return DefDriverProc(dwDriverID, hDriver, wMessage,lParam1,lParam2); } }
DWORD FAR PASCAL _loadds modMessage(UINT id, UINT msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2) { int i; DWORD dResult;
// this driver only supports one device
if (id != 0) return MMSYSERR_BADDEVICEID;
switch (msg) {
case MODM_GETNUMDEVS: return 1;
case MODM_GETDEVCAPS: return modGetDevCaps((LPMIDIOUTCAPSW)dwParam1, LOWORD(dwParam2));
case MODM_OPEN: EnterCriticalSection(&MapperCritSec); if( hCurMap || mapLockCount ) { dResult = MMSYSERR_ALLOCATED; } else { dResult = midiReadCurrentSetup((LPMIDIOPENDESC)dwParam1, dwParam2); } LeaveCriticalSection(&MapperCritSec); return dResult;
case MODM_CLOSE: EnterCriticalSection(&MapperCritSec); dResult = CloseMidiDevice(); LeaveCriticalSection(&MapperCritSec); return dResult;
case MODM_CACHEPATCHES: case MODM_CACHEDRUMPATCHES: return modCachePatches(msg, HIWORD(dwParam2), (LPPATCHARRAY)dwParam1, LOWORD(dwParam2));
///////////////////////////////////////////////////////////////////////////
//
// INTERRUPT TIME CODE
//
// MODM_LONGDATA, MODM_DATA, and MODM_RESET are callable at interupt time!
//
///////////////////////////////////////////////////////////////////////////
case MODM_DATA: modShortData((LPBYTE)&dwParam1); return 0;
case MODM_LONGDATA: modLongData( (HPBYTE)((LPMIDIHDR)dwParam1)->lpData , ((LPMIDIHDR)dwParam1)->dwBufferLength ); ((LPMIDIHDR)dwParam1)->dwFlags |= MHDR_DONE; CallbackNotification(MOM_DONE, dwParam1); return 0;
///////////////////////////////////////////////////////////////////////////
case MODM_PREPARE: case MODM_UNPREPARE: return MMSYSERR_NOTSUPPORTED;
//case MODM_RESET:
//case MODM_GETVOLUME:
//case MODM_SETVOLUME:
default: //
// !!!this is in trouble if a map goes to multiple physical devices
// we return the *last* dResult, this is
// totally random for some messages (like MODM_GETVOLUME).
// pass the message on un-translated to all mapped physical
// devices.
//
for (dResult = 0, i = 0; i < 16 && mapdevs[i].hMidi; i++) switch (msg) { //
// Avoid nasty overlaps with open devices
//
case MODM_GETVOLUME: dResult = midiOutGetVolume((HMIDIOUT)(mapdevs[i].wDeviceID), (LPDWORD)dwParam1); break;
case MODM_SETVOLUME: dResult = midiOutSetVolume((HMIDIOUT)(mapdevs[i].wDeviceID), dwParam1); break;
default: dResult = midiOutMessage(mapdevs[i].hMidi, msg, dwParam1, dwParam2); break; }
return dResult; } }
/*****************************************************************************
* @doc EXTERNAL MIDI * * @api UINT | modGetDevCaps | This function returns the mappers device caps * * @parm LPMIDIOUTCAPS | lpCaps | Specifies a far pointer to a <t MIDIOUTCAPS> * structure. This structure is filled with information about the * capabilities of the device. * * @parm UINT | wSize | Specifies the size of the <t MIDIOUTCAPS> structure. * * @rdesc Returns zero if the function was successful. Otherwise, it returns * an error number. Possible error returns are: * @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range. * @flag MMSYSERR_NODRIVER | The driver was not installed. * ****************************************************************************/ UINT FAR PASCAL modGetDevCaps(LPMIDIOUTCAPSW lpCaps, UINT uSize) { MIDIOUTCAPSW mc; int i;
if (uSize != 0) {
i=LoadStringW( hLibInst, IDS_MIDIMAPPER, mc.szPname, sizeof(lpCaps->szPname) / sizeof(WCHAR) );
mc.wMid = MM_MICROSOFT; mc.wPid = MM_MIDI_MAPPER; mc.vDriverVersion = 0x0100; mc.wTechnology = MOD_MAPPER; mc.wVoices = 0; mc.wNotes = 0; mc.wChannelMask = wChannelMask; // 0 if mapper not opened yet
mc.dwSupport = MIDICAPS_CACHE;
_fmemcpy((LPSTR)lpCaps, (LPSTR)&mc, min(uSize, sizeof(mc))); }
return 0; }
static void PASCAL NEAR TranslatePatchArray( LPPATCHARRAY lpSource, LPPATCHARRAY lpDest, BOOL fToMaps) { int i;
_fmemset(lpDest, 0, sizeof(PATCHARRAY)); for (i = 0; i < 16; i++) { UINT curmask; int j;
curmask = 1 << i; if (uPatchMask & curmask) { lpPMap = (LPMIDIPATCHMAP)((LPSTR)lpCurMap + lpCurMap->chMap[i].oPMap); if (fToMaps) for (j = 0; j < MIDIPATCHSIZE; j++) lpDest[LOBYTE(lpPMap->wPMap[j])] |= (lpSource[j] & curmask) ? curmask : 0; else for (j = 0; j < MIDIPATCHSIZE; j++) lpDest[j] |= (lpSource[LOBYTE(lpPMap->wPMap[j])] & curmask) ? curmask : 0; } else for (j = 0; j < MIDIPATCHSIZE; j++) lpDest[j] |= (lpSource[j] & curmask) ? curmask : 0; } }
UINT FAR PASCAL modCachePatches(UINT msg, UINT uBank, LPPATCHARRAY lpPatchArray, UINT uFlags) { int i; PATCHARRAY patchlist; PATCHARRAY retpatchlist; UINT uResult = 0;
TranslatePatchArray(lpPatchArray, patchlist, TRUE);
// send to drivers
_fmemset(retpatchlist, 0, sizeof(PATCHARRAY));
for( i = 0; ((i < 16) && (mapdevs[i].wDeviceID != (WORD)(-1))); i++ ) { PATCHARRAY curpatchlist; int j;
for (j = 0; j < MIDIPATCHSIZE; j++ ) curpatchlist[j] = patchlist[j] & mapdevs[i].wChannel;
uResult = ( (msg == MODM_CACHEPATCHES) ? midiOutCachePatches( mapdevs[i].hMidi , uBank , curpatchlist , uFlags ) : midiOutCacheDrumPatches( mapdevs[i].hMidi , uBank , curpatchlist , uFlags ) );
// combine the returned info
for (j = 0; j < MIDIPATCHSIZE; j++ ) retpatchlist[j] |= (curpatchlist[j] & mapdevs[i].wChannel); }
TranslatePatchArray(retpatchlist, lpPatchArray, FALSE);
return uResult; }
///////////////////////////////////////////////////////////////////////////
//
// INTERRUPT TIME CODE
//
// MODM_LONGDATA, and MODM_DATA are callable at interupt time!
//
///////////////////////////////////////////////////////////////////////////
static BOOL NEAR PASCAL modHeaderDone( void) { if (pmidihdrMapper->dwFlags & MHDR_DONE) return TRUE; else return FALSE; }
static void NEAR PASCAL modSendLongData( UINT uMessageLength, BOOL fBroadcast, BOOL fForce) // Used on final invocation
{
static BYTE LongBuffer[200]; // Cache the stuff for performance
static DWORD nLongData; // How much we've got
static BOOL LastBroadcast; // What we were asked to do last time
static BYTE LastStatus; // Last status we had
if (nLongData && (fForce || FILTERSTATUS(status) != FILTERSTATUS(LastStatus) || uMessageLength + nLongData > sizeof(LongBuffer) || LastBroadcast != fBroadcast)) {
LPBYTE lpSave = pmidihdrMapper->lpData; pmidihdrMapper->lpData = LongBuffer;
pmidihdrMapper->dwBufferLength = nLongData; if (LastBroadcast) { WORD wDevice;
for (wDevice = 0; (wDevice < 16) && (mapdevs[wDevice].wDeviceID != (WORD)(-1)); wDevice++) { pmidihdrMapper->dwFlags &= ~MHDR_DONE; if (MMSYSERR_NOERROR == midiOutLongMsg(mapdevs[wDevice].hMidi, pmidihdrMapper, sizeof(MIDIHDR))) { while (!modHeaderDone()) Sleep(1); } } } else { pmidihdrMapper->dwFlags &= ~MHDR_DONE; if (MMSYSERR_NOERROR == midiOutLongMsg(chnldevs[FILTERSTATUS(LastStatus)].hMidi, pmidihdrMapper, sizeof(MIDIHDR))) { while (!modHeaderDone()) Sleep(1); } }
pmidihdrMapper->lpData = lpSave; nLongData = 0; }
//
// Pull in our new data
//
LastStatus = status; LastBroadcast = fBroadcast; if (fBroadcast || fActiveChannel) { memcpy(LongBuffer + nLongData, pmidihdrMapper->lpData, uMessageLength); nLongData += uMessageLength; } }
static void NEAR PASCAL modTranslateEvent( LPBYTE pbData, BYTE bStart, BYTE bLength) { static BYTE fControlVol;
if (wChannelMask & (1 << FILTERSTATUS(status))) { fActiveChannel = TRUE; bCurrentStatus = FILTERCHANNEL(status) + (BYTE)lpCurMap->chMap[FILTERSTATUS(status)].wChannel; if (!bStart) { *(pbData++) = bCurrentStatus; bStart++; bLength--; if (!bLength) return; } if (uPatchMask & (1 << FILTERSTATUS(status))) { lpPMap = (LPMIDIPATCHMAP)((LPSTR)lpCurMap + lpCurMap->chMap[FILTERSTATUS(status)].oPMap); switch (FILTERCHANNEL(status)) { case STATUS_NOTEOFF: case STATUS_NOTEON: case STATUS_POLYPHONICKEY: if ((bStart > 1) || !lpPMap->okMaps[curpatch[FILTERSTATUS(status)]]) break; lpKMap = (LPMIDIKEYMAP)((LPSTR)lpPMap + lpPMap->okMaps[curpatch[FILTERSTATUS(status)]]); *pbData = lpKMap->bKMap[*pbData]; break; case STATUS_CONTROLCHANGE: if (bStart == 1) { if (*pbData != CONTROL_VOLUME) break; pbData++; bStart++; bLength--; fControlVol = TRUE; if (!bLength) return; } *pbData = (BYTE)((DWORD)*pbData * (DWORD)HIBYTE(lpPMap->wPMap[curpatch[FILTERSTATUS(status)]]) / lpPMap->bVMax); fControlVol = FALSE; break; case STATUS_PROGRAMCHANGE: curpatch[FILTERSTATUS(status)] = *pbData; *pbData = (BYTE)lpPMap->wPMap[*pbData]; break; } } } else fActiveChannel = FALSE; }
static void NEAR PASCAL modShortData( LPBYTE pbData) { BOOL fBroadcast; BYTE bStart = 0; BYTE bLength = 0;
if (*pbData >= STATUS_TIMINGCLOCK) fBroadcast = TRUE; else { bCurrentLen = 0; if (ISSTATUS(*pbData)) { bCurrentStatus = *pbData; if (bCurrentStatus >= STATUS_SYSEX) { status = 0; fBroadcast = TRUE; } else { status = bCurrentStatus; bLength = MIDILENGTH(bCurrentStatus); fBroadcast = FALSE; bStart = 0; } } else if (!status) return; else { fBroadcast = FALSE; bLength = (BYTE)(MIDILENGTH(status) - 1); bStart = 1; } } if (fBroadcast) { WORD wDevice;
for (wDevice = 0; (wDevice < 16) && (mapdevs[wDevice].wDeviceID != (WORD)(-1)); wDevice++) midiOutShortMsg(mapdevs[wDevice].hMidi, *(LPDWORD)pbData); } else { modTranslateEvent(pbData, bStart, bLength); if (fActiveChannel) midiOutShortMsg(chnldevs[FILTERSTATUS(status)].hMidi, *(LPDWORD)pbData); } }
static void NEAR PASCAL modLongData( HPBYTE pbData, DWORD dDataLength) { static BYTE bStart; UINT uMessageLength; LPBYTE pbHdrData;
pbHdrData = pmidihdrMapper->lpData; uMessageLength = 0; for (; dDataLength;) { if (ISSTATUS(*pbData)) { if (bCurrentStatus == STATUS_SYSEX) { bCurrentStatus = *pbData; if ((bCurrentStatus == STATUS_EOX) || (bCurrentStatus == STATUS_SYSEX) || (bCurrentStatus >= STATUS_TIMINGCLOCK)) { *(pbHdrData++) = bCurrentStatus; dDataLength--; if (bCurrentStatus >= STATUS_TIMINGCLOCK) bCurrentStatus = STATUS_SYSEX; } else uMessageLength--; } else { if (bCurrentLen) { if (status) { BYTE bMessageLength;
bMessageLength = (BYTE)(MIDILENGTH(status) - bCurrentLen - bStart); modTranslateEvent(pmidihdrMapper->lpData - bMessageLength, bStart, bMessageLength); } modSendLongData(uMessageLength, !status, FALSE); pbHdrData = pmidihdrMapper->lpData; uMessageLength = 0; } *pbHdrData = *(pbData++); dDataLength--; if (*pbHdrData >= STATUS_TIMINGCLOCK) { modSendLongData(1, TRUE, FALSE); continue; } bCurrentStatus = *(pbHdrData++); if (bCurrentStatus >= STATUS_SYSEX) { status = 0; bCurrentLen = (BYTE)(SYSLENGTH(bCurrentStatus) - 1); } else { status = bCurrentStatus; bCurrentLen = (BYTE)(MIDILENGTH(bCurrentStatus) - 1); bStart = 0; } } } else { *(pbHdrData++) = *(pbData++); dDataLength--; if (bCurrentLen) bCurrentLen--; else if (status) { bStart = 1; bCurrentLen = (BYTE)(MIDILENGTH(status) - 2); }
} uMessageLength++; if (!bCurrentLen && ((bCurrentStatus != STATUS_SYSEX) || (uMessageLength == MIDIDATABUFFER))) { if (status) { BYTE bMessageLength;
bMessageLength = (BYTE)(MIDILENGTH(status) - bStart); modTranslateEvent(pmidihdrMapper->lpData - bStart, bStart, bMessageLength); } modSendLongData(uMessageLength, !status, FALSE); pbHdrData = pmidihdrMapper->lpData; uMessageLength = 0; } } if (uMessageLength) { if (status) { BYTE bMessageLength;
bMessageLength = (BYTE)(MIDILENGTH(status) - bCurrentLen - bStart); modTranslateEvent(pmidihdrMapper->lpData - bStart, bStart, bMessageLength); bStart += bMessageLength; } modSendLongData(uMessageLength, !status, FALSE); }
modSendLongData(0, 0, TRUE); }
/*****************************************************************************
* @doc INTERNAL MIDI * * @api BOOL | mapLock | This function prevents anyone from opening the * mapper. * * @rdesc Returns TRUE if successful and FALSE otherwise (i.e. the mapper is * already open. * * @comm This is a private function for the control panel applet to call * while a setup is being edited. There is a lock count kept - you must * call mapUnlock once for each call to mapLock. ****************************************************************************/ BOOL FAR PASCAL mapLock(VOID) { // if someone has the mapper open, return FALSE
if( hCurMap ) return FALSE;
mapLockCount++; return TRUE; }
/*****************************************************************************
* @doc INTERNAL MIDI * * @api VOID | mapUnlock | This function unlocks the mapper if it's locked. * * @rdesc There is no return value. * * @comm This is a private function for the control panel applet to call * while a setup is being edited. There is a lock count kept but * underflow will not generate an error, and lock count will remain 0. ****************************************************************************/ VOID FAR PASCAL mapUnlock(VOID) { if( mapLockCount ) mapLockCount--; return; }
/*****************************************************************************
* @doc INTERNAL MIDI * * @api UINT | midiReadCurrentSetup | This function reads in the current setup. * * @parm DWORD | dwParam1 | The first DWORD from the <f midiOutOpen> call. * * @parm DWORD | dwParam2 | The second DWORD from the <f midiOutOpen> call. * * @rdesc Returns zero if the function was successful. Otherwise, it returns * an error number. ****************************************************************************/ static UINT FAR PASCAL midiReadCurrentSetup(LPMIDIOPENDESC lpOpen, DWORD dwParam2) { int i,j; WORD devid; MMAPERR mmaperr; DWORD dwSize; UINT uResult; char szCurSetup[MMAP_MAXNAME]; WORD wChan;
// get current setup
mmaperr = mapGetCurrentSetup(szCurSetup, MMAP_MAXNAME); if (mmaperr != MMAPERR_SUCCESS) return TranslateError(mmaperr);
dwSize = mapGetSize(MMAP_SETUP, szCurSetup); if (dwSize < (DWORD)MMAPERR_MAXERROR) return TranslateError((UINT)dwSize);
// allocate memory
hCurMap = GlobalAlloc(GMEM_MOVEABLE, dwSize); if( !hCurMap ) return MMSYSERR_NOMEM;
hCurMap = (HGLOBAL)GlobalLock(hCurMap);
mmaperr = mapRead (MMAP_SETUP, szCurSetup, lpCurMap); if( mmaperr != MMAPERR_SUCCESS ) { ReleaseResources(); return TranslateError(mmaperr); }
// initialize channel and patch masks
wChannelMask = 0; uPatchMask = 0;
// initialize device list
for (i = 0; i < 16; i++) { mapdevs[i].wDeviceID = (WORD)(-1); mapdevs[i].hMidi = NULL; mapdevs[i].fwFlags = 0; }
// go through each source channel
for( wChan = 0; wChan < 16; wChan++ ) { if( ((lpCurMap->chMap[wChan]).dwFlags) & MMAP_ACTIVE ) {
// set channel mask
wChannelMask |= (1 << wChan);
// set patch mask
if( ((lpCurMap->chMap[wChan]).dwFlags) & MMAP_PATCHMAP ) uPatchMask |= (1 << wChan);
// map device id
devid = lpCurMap->chMap[wChan].wDeviceID;
// save driver and device ids for channel messages
chnldevs[wChan].wDeviceID = devid;
// algorithm for device list
// wChannel will have the channel mask for the device
for( j = 0; j < 16; j++ ) { if( mapdevs[j].wDeviceID == devid ) { mapdevs[j].wChannel |= 0x0001 << wChan; break; // from for loop
} if( mapdevs[j].wDeviceID == (WORD)(-1) ) { mapdevs[j].wDeviceID = devid; mapdevs[j].wChannel = (WORD)(1 << wChan); // first channel
break; } } } }
// create a long message buffer for translation of long messages.
{ HANDLE hMem; hMem = GlobalAlloc( GMEM_MOVEABLE | GMEM_ZEROINIT , (LONG)(sizeof(MIDIHDR) + MIDIDATABUFFER) ); if (hMem) pmidihdrMapper = ( hMem ? (LPMIDIHDR)GlobalLock(hMem) : NULL); } if (!pmidihdrMapper) { ReleaseResources(); return MMSYSERR_NOMEM; } pmidihdrMapper->lpData = (LPSTR)(pmidihdrMapper + 1); pmidihdrMapper->dwBufferLength = MIDIDATABUFFER;
// open all devices in new map
for( i = 0; ((i < 16) && (mapdevs[i].wDeviceID != (WORD)(-1)) ); i++ ) { uResult = midiOutOpen(&mapdevs[i].hMidi, mapdevs[i].wDeviceID, 0, 0, dwParam2 & ~CALLBACK_TYPEMASK);
if(uResult != 0 ){ // if any opens fail, return now
ReleaseResources(); return uResult; }
uResult = midiOutPrepareHeader(mapdevs[i].hMidi, pmidihdrMapper, sizeof(MIDIHDR)); if (uResult) { ReleaseResources(); return uResult; } mapdevs[i].fwFlags |= DEV_PREPARED;
for( j = 0; j < 16; j++ ) { if( mapdevs[i].wDeviceID == chnldevs[j].wDeviceID ) chnldevs[j].hMidi = mapdevs[i].hMidi; } }
OpenCallback = lpOpen->dwCallback; OpenInstance = lpOpen->dwInstance; OpenFlags = dwParam2; hmidiMapper = (HMIDIOUT)lpOpen->hMidi; status = 0; bCurrentLen = 0; bCurrentStatus = 0;
#if defined(WIN16)
if ( GlobalNail((HGLOBAL)HIWORD(DriverProc), STATE_CODENAILED) && GlobalNail(hCurMap, STATE_MAPNAILED) && GlobalNail((HGLOBAL)HIWORD((DWORD)(LPVOID)&hCurMap), STATE_DATANAILED) ) { #endif //WIN16
CallbackNotification(MOM_OPEN, 0); return MMSYSERR_NOERROR; #if defined(WIN16)
} ReleaseResources(); return MMSYSERR_NOMEM; #endif //WIN16
}
|