Annotation of ntddk/src/mmedia/mmdrv/mididd.c, revision 1.1

1.1     ! root        1: /****************************************************************************
        !             2:  *
        !             3:  *   mididd.c
        !             4:  *
        !             5:  *   Multimedia kernel driver support component (mmdrv)
        !             6:  *
        !             7:  *   Copyright (c) 1991 Microsoft Corporation.  All Rights Reserved.
        !             8:  *
        !             9:  *   Driver for midi input and output devices
        !            10:  *
        !            11:  *   -- Midi driver entry points (modMessage, midMessage)
        !            12:  *   -- Auxiliary task (necessary for receiving Apcs and generating
        !            13:  *      callbacks ASYNCRHONOUSLY)
        !            14:  *   -- Interface to kernel driver (NtDeviceIoControlFile)
        !            15:  *   -- Midi parsing code (ported from Windows 3.1).
        !            16:  *
        !            17:  *   History
        !            18:  *      01-Feb-1992 - Robin Speed (RobinSp) wrote it
        !            19:  *
        !            20:  ***************************************************************************/
        !            21: 
        !            22: #include "mmdrv.h"
        !            23: #include <ntddmidi.h>
        !            24: 
        !            25: /*****************************************************************************
        !            26: 
        !            27:     internal declarations
        !            28: 
        !            29:  ****************************************************************************/
        !            30: 
        !            31: #define D1 dprintf1
        !            32: #define D2 dprintf2
        !            33: #define D3 dprintf3
        !            34: 
        !            35: //
        !            36: // Stack size for our auxiliary task
        !            37: //
        !            38: 
        !            39: #define MIDI_STACK_SIZE 300
        !            40: 
        !            41: #define SYSEX_ERROR    0xFF              // internal error for sysex's on input
        !            42: 
        !            43: //
        !            44: // Functions for auxiliary thread to perform
        !            45: //
        !            46: 
        !            47: typedef enum {
        !            48:     MidiThreadInvalid,
        !            49:     MidiThreadAddBuffer,
        !            50:     MidiThreadSetState,
        !            51:     MidiThreadSetData,
        !            52:     MidiThreadClose,
        !            53:     MidiThreadTerminate
        !            54: } MIDITHREADFUNCTION;
        !            55: 
        !            56: //
        !            57: // Our local buffers for interfacing to midi input
        !            58: //
        !            59: 
        !            60: #define LOCAL_MIDI_DATA_SIZE 20
        !            61: typedef struct _LOCALMIDIHDR {
        !            62:     OVERLAPPED          Ovl;
        !            63:     DWORD               BytesReturned;
        !            64:     struct _LOCALMIDIHDR *lpNext;       // Queueing (really debug only)
        !            65:     BOOL                Done;           // Driver completed buffer
        !            66:     PVOID               pClient;        // Our instance data for Apcs
        !            67:     MIDI_DD_INPUT_DATA  MidiData;       // What the driver wants to process
        !            68:     BYTE                ExtraData[LOCAL_MIDI_DATA_SIZE - sizeof(ULONG)];
        !            69:                                         // The rest of our input buffer
        !            70: } LOCALMIDIHDR, *PLOCALMIDIHDR;
        !            71: 
        !            72: //
        !            73: // Midi input data
        !            74: //
        !            75: 
        !            76: #define NUMBER_OF_LOCAL_MIDI_BUFFERS 8
        !            77: 
        !            78: typedef struct {
        !            79: 
        !            80:     //
        !            81:     // Static data for managing midi input
        !            82:     //
        !            83:     BOOL                fMidiInStarted; // Do we think midi in is running ?
        !            84:     DWORD               dwMsg;          // Current short msg
        !            85:     DWORD               dwCurData;      // Position in long message
        !            86:     BYTE                status;         // Running status byte
        !            87:     BOOLEAN             fSysex;         // Processing extended message
        !            88:     BOOLEAN             Bad;            // Input not working properly
        !            89:     BYTE                bBytesLeft;     // Bytes left in short message
        !            90:     BYTE                bBytePos;       // Position in short message
        !            91:     DWORD               dwCurTime;      // Latest time from driver
        !            92:     DWORD               dwMsgTime;      // Time to insert into message
        !            93:                                         // in milliseconds since device
        !            94:                                         // was opened
        !            95:     PLOCALMIDIHDR       DeviceQueue;    // Keep track of what the device
        !            96:                                         // has (debugging only)
        !            97:     LOCALMIDIHDR                        // Driver interface buffers
        !            98:      Bufs[NUMBER_OF_LOCAL_MIDI_BUFFERS];// When input is active these
        !            99:                                         // are queued on the device
        !           100:                                         // except while data is being
        !           101:                                         // processed from them
        !           102: } LOCALMIDIDATA, *PLOCALMIDIDATA;
        !           103: 
        !           104: 
        !           105: //
        !           106: // per allocation structure for Midi
        !           107: //
        !           108: 
        !           109: typedef struct tag_MIDIALLOC {
        !           110:     struct tag_MIDIALLOC *Next;         // Chain of devices
        !           111:     UINT                DeviceNumber;   // Number of device
        !           112:     UINT                DeviceType;     // MidiInput or MidiOutput
        !           113:     DWORD               dwCallback;     // client's callback
        !           114:     DWORD               dwInstance;     // client's instance data
        !           115:     HMIDI               hMidi;          // handle for stream
        !           116:     HANDLE              hDev;           // Midi device handle
        !           117:     LPMIDIHDR           lpMIQueue;      // Buffers sent to device
        !           118:                                         // This is only required so that
        !           119:                                         // CLOSE knows when things have
        !           120:                                         // really finished.
        !           121:                                         // notify.  This is only accessed
        !           122:                                         // on the device thread and its
        !           123:                                         // apcs so does not need any
        !           124:                                         // synchronized access.
        !           125:     HANDLE              Event;          // Event for driver syncrhonization
        !           126:                                         // and notification of auxiliary
        !           127:                                         // task operation completion.
        !           128:     MIDITHREADFUNCTION  AuxFunction;    // Function for thread to perform
        !           129:     union {
        !           130:         LPMIDIHDR       pHdr;           // Buffer to pass in aux task
        !           131:         ULONG           State;          // State to set
        !           132:         struct {
        !           133:             ULONG       Function;       // IOCTL to use
        !           134:             PBYTE       pData;          // Data to set or get
        !           135:             ULONG       DataLen;        // Length of data
        !           136:         } GetSetData;
        !           137: 
        !           138:     } AuxParam;
        !           139:                                         // 0 means terminate task.
        !           140:     HANDLE              ThreadHandle;   // Handle for termination ONLY
        !           141:     HANDLE              AuxEvent1;      // Aux thread waits on this
        !           142:     HANDLE              AuxEvent2;      // Aux thread caller waits on this
        !           143:     DWORD               AuxReturnCode;  // Return code from Aux task
        !           144:     DWORD               dwFlags;        // Open flags
        !           145:     PLOCALMIDIDATA      Mid;            // Extra midi input structures
        !           146:     int                 l;              // Helper global for modMidiLength
        !           147: 
        !           148: } MIDIALLOC, *PMIDIALLOC;
        !           149: 
        !           150: PMIDIALLOC MidiHandleList;              // Our chain of wave handles
        !           151: 
        !           152: /*****************************************************************************
        !           153: 
        !           154:     internal function prototypes
        !           155: 
        !           156:  ****************************************************************************/
        !           157: 
        !           158: STATIC DWORD midiGetDevCaps(DWORD id, UINT DeviceType, LPBYTE lpCaps,
        !           159:                             DWORD dwSize);
        !           160: STATIC DWORD midiThread(LPVOID lpParameter);
        !           161: STATIC void midiCleanUp(PMIDIALLOC pClient);
        !           162: STATIC DWORD midiThreadCall(MIDITHREADFUNCTION Function, PMIDIALLOC pClient);
        !           163: STATIC DWORD midiSetState(PMIDIALLOC pClient, ULONG State);
        !           164: STATIC void midiInOvl(DWORD dwRet, DWORD dwBytes, LPOVERLAPPED pOverlap);
        !           165: STATIC DWORD midiInWrite(LPMIDIHDR pHdr, PMIDIALLOC pClient);
        !           166: STATIC DWORD midiOutWrite(PBYTE pData, ULONG Len, PMIDIALLOC pClient);
        !           167: STATIC void midiBlockFinished(LPMIDIHDR lpHdr, DWORD MsgId);
        !           168: STATIC void midiCallback(PMIDIALLOC pMidi, DWORD msg, DWORD dw1, DWORD dw2);
        !           169: STATIC int modMIDIlength(PMIDIALLOC pClient, BYTE b);
        !           170: STATIC void midByteRec(PMIDIALLOC pClient, BYTE byte);
        !           171: STATIC void midSendPartBuffer(PMIDIALLOC pClient);
        !           172: STATIC void midFreeQ(PMIDIALLOC pClient);
        !           173: STATIC void midiFlush(PMIDIALLOC pClient);
        !           174: 
        !           175: /****************************************************************************
        !           176:  * @doc INTERNAL
        !           177:  *
        !           178:  * @api VOID | TerminateMidi | Free all midi resources for mmdrv.dll
        !           179:  *
        !           180:  * @rdesc None
        !           181:  ***************************************************************************/
        !           182: VOID TerminateMidi(VOID)
        !           183: {
        !           184:     //
        !           185:     // Don't do any cleanup - Midi input resources cleaned up on Close.
        !           186:     //
        !           187: }
        !           188: 
        !           189: /****************************************************************************
        !           190:  * @doc INTERNAL
        !           191:  *
        !           192:  * @api void | midiGetDevCaps | Get the device capabilities.
        !           193:  *
        !           194:  * @parm DWORD | id | Device id
        !           195:  *
        !           196:  * @parm UINT | DeviceType | type of device
        !           197:  *
        !           198:  * @parm LPBYTE | lpCaps | Far pointer to a MIDIOUTCAPS structure to
        !           199:  *      receive the information.
        !           200:  *
        !           201:  * @parm DWORD | dwSize | Size of the MIDIOUTCAPS structure.
        !           202:  *
        !           203:  * @rdesc There is no return value.
        !           204:  ***************************************************************************/
        !           205: STATIC DWORD midiGetDevCaps(DWORD id, UINT DeviceType,
        !           206:                             LPBYTE lpCaps, DWORD dwSize)
        !           207: {
        !           208:     return sndGetData(DeviceType, id, dwSize, lpCaps,
        !           209:                       IOCTL_MIDI_GET_CAPABILITIES);
        !           210: }
        !           211: 
        !           212: 
        !           213: /****************************************************************************
        !           214:  * @doc INTERNAL
        !           215:  *
        !           216:  * @api DWORD | midiOpen | Open midi device and set up logical device data
        !           217:  *    and auxilary task for issuing requests and servicing Apc's
        !           218:  *
        !           219:  * @parm MIDIDEVTYPE | DeviceType | Whether it's a midi input or output device
        !           220:  *
        !           221:  * @parm DWORD | id | The device logical id
        !           222:  *
        !           223:  * @parm DWORD | msg | Input parameter to modMessage
        !           224:  *
        !           225:  * @parm DWORD | dwUser | Input parameter to modMessage - pointer to
        !           226:  *   application's handle (generated by this routine)
        !           227:  *
        !           228:  * @parm DWORD | dwParam1 | Input parameter to modMessage
        !           229:  *
        !           230:  * @parm DWORD | dwParam2 | Input parameter to modMessage
        !           231:  *
        !           232:  * @rdesc modMessage return code.
        !           233:  ***************************************************************************/
        !           234: 
        !           235: STATIC DWORD midiOpen(UINT  DeviceType,
        !           236:                       DWORD id,
        !           237:                       DWORD dwUser,
        !           238:                       DWORD dwParam1,
        !           239:                       DWORD dwParam2)
        !           240: {
        !           241:     PMIDIALLOC     pClient;  // pointer to client information structure
        !           242:     MMRESULT mRet;
        !           243: 
        !           244:     // dwParam1 contains a pointer to a MIDIOPENDESC
        !           245:     // dwParam2 contains midi driver specific flags in the LOWORD
        !           246:     // and generic driver flags in the HIWORD
        !           247: 
        !           248:     //
        !           249:     // allocate my per-client structure
        !           250:     //
        !           251:     if (DeviceType == MidiOutDevice) {
        !           252:         pClient = (PMIDIALLOC)HeapAlloc(hHeap, 0, sizeof(MIDIALLOC));
        !           253: 
        !           254:         if (pClient != NULL) {
        !           255:             memset(pClient, 0, sizeof(MIDIALLOC));
        !           256:         }
        !           257:     } else {
        !           258:         WinAssert(DeviceType == MidiInDevice);
        !           259:         pClient = (PMIDIALLOC)HeapAlloc(hHeap, 0,
        !           260:                    sizeof(struct _x{MIDIALLOC S1; LOCALMIDIDATA S2;}));
        !           261: 
        !           262:         if (pClient != NULL) {
        !           263:             memset(pClient, 0, sizeof(struct _x{MIDIALLOC S1; LOCALMIDIDATA S2;}));
        !           264:         }
        !           265:     }
        !           266: 
        !           267:     if (pClient == NULL) {
        !           268:         return MMSYSERR_NOMEM;
        !           269:     }
        !           270: 
        !           271:     if (DeviceType == MidiInDevice) {
        !           272:         int i;
        !           273:         pClient->Mid = (PLOCALMIDIDATA)(pClient + 1);
        !           274:         for (i = 0 ;i < NUMBER_OF_LOCAL_MIDI_BUFFERS ; i++) {
        !           275:             pClient->Mid->Bufs[i].pClient = pClient;
        !           276:         }
        !           277:     }
        !           278: 
        !           279:     //
        !           280:     // and fill it with info
        !           281:     //
        !           282:     // (note that setting everything to 0 correctly initialized our
        !           283:     //  midi input processing static data).
        !           284: 
        !           285:     pClient->DeviceType  = DeviceType;
        !           286:     pClient->dwCallback  = ((LPMIDIOPENDESC)dwParam1)->dwCallback;
        !           287:     pClient->dwInstance  = ((LPMIDIOPENDESC)dwParam1)->dwInstance;
        !           288:     pClient->hMidi       = ((LPMIDIOPENDESC)dwParam1)->hMidi;
        !           289:     pClient->dwFlags     = dwParam2;
        !           290: 
        !           291:     //
        !           292:     // See if we can open our device
        !           293:     // If it's only a query be sure only to open for read, otherwise
        !           294:     // we could get STATUS_BUSY if someone else is writing to the
        !           295:     // device.
        !           296:     //
        !           297: 
        !           298:     mRet = sndOpenDev(DeviceType,
        !           299:                        id,
        !           300:                        &pClient->hDev,
        !           301:                        (GENERIC_READ | GENERIC_WRITE));
        !           302: 
        !           303:     if (mRet != MMSYSERR_NOERROR) {
        !           304: 
        !           305:         midiCleanUp(pClient);
        !           306:         return mRet;
        !           307:     }
        !           308: 
        !           309: 
        !           310:     //
        !           311:     // Create our event for syncrhonization with the device driver
        !           312:     //
        !           313: 
        !           314:     pClient->Event = CreateEvent(NULL, FALSE, FALSE, NULL);
        !           315: 
        !           316:     if (pClient->Event == NULL) {
        !           317:         midiCleanUp(pClient);
        !           318:         return MMSYSERR_NOMEM;
        !           319:     }
        !           320: 
        !           321:     if (DeviceType == MidiInDevice) {
        !           322: 
        !           323:         //
        !           324:         // Create our event pair for synchronization with the auxiliary
        !           325:         // thread
        !           326:         //
        !           327: 
        !           328:         pClient->AuxEvent1 = CreateEvent(NULL, FALSE, FALSE, NULL);
        !           329:         if (pClient->AuxEvent1 == NULL) {
        !           330:             midiCleanUp(pClient);
        !           331:             return MMSYSERR_NOMEM;
        !           332:         }
        !           333:         pClient->AuxEvent2 = CreateEvent(NULL, FALSE, FALSE, NULL);
        !           334:         if (pClient->AuxEvent2 == NULL) {
        !           335:             midiCleanUp(pClient);
        !           336:             return MMSYSERR_NOMEM;
        !           337:         }
        !           338: 
        !           339:         //
        !           340:         // Create our auxiliary thread for sending buffers to the driver
        !           341:         // and collecting Apcs
        !           342:         //
        !           343: 
        !           344:         mRet = mmTaskCreate((LPTASKCALLBACK)midiThread,
        !           345:                             &pClient->ThreadHandle,
        !           346:                             (DWORD)pClient);
        !           347: 
        !           348:         if (mRet != MMSYSERR_NOERROR) {
        !           349:             midiCleanUp(pClient);
        !           350:             return MMSYSERR_NOMEM;
        !           351:         }
        !           352: 
        !           353:         //
        !           354:         // Make sure the thread has really started
        !           355:         //
        !           356: 
        !           357:         WaitForSingleObject(pClient->AuxEvent2, INFINITE);
        !           358:     }
        !           359: 
        !           360:     //
        !           361:     // give the client my driver dw
        !           362:     //
        !           363:     {
        !           364:         PMIDIALLOC *pUserHandle;
        !           365:         pUserHandle = (PMIDIALLOC *)dwUser;
        !           366:         *pUserHandle = pClient;
        !           367:     }
        !           368: 
        !           369:     //
        !           370:     // sent client his OPEN callback message
        !           371:     //
        !           372:     midiCallback(pClient, DeviceType == MidiOutDevice ? MOM_OPEN : MIM_OPEN,
        !           373:                  0L, 0L);
        !           374: 
        !           375:     return MMSYSERR_NOERROR;
        !           376: }
        !           377: 
        !           378: /****************************************************************************
        !           379:  * @doc INTERNAL
        !           380:  *
        !           381:  * @api void | midiCleanUp | Free resources for a midi device
        !           382:  *
        !           383:  * @parm PMIDIALLOC | pClient | Pointer to a MIDIALLOC structure describing
        !           384:  *      resources to be freed.
        !           385:  *
        !           386:  * @rdesc There is no return value.
        !           387:  *
        !           388:  * @comm If the pointer to the resource is NULL then the resource has not
        !           389:  *     been allocated.
        !           390:  ***************************************************************************/
        !           391: STATIC void midiCleanUp(PMIDIALLOC pClient)
        !           392: {
        !           393:     if (pClient->hDev != INVALID_HANDLE_VALUE) {
        !           394:         CloseHandle(pClient->hDev);
        !           395:     }
        !           396:     if (pClient->AuxEvent1) {
        !           397:         CloseHandle(pClient->AuxEvent1);
        !           398:     }
        !           399:     if (pClient->AuxEvent2) {
        !           400:         CloseHandle(pClient->AuxEvent2);
        !           401:     }
        !           402:     if (pClient->Event) {
        !           403:         CloseHandle(pClient->Event);
        !           404:     }
        !           405: 
        !           406:     HeapFree(hHeap, 0, (LPSTR)pClient);
        !           407: }
        !           408: 
        !           409: /****************************************************************************
        !           410:  * @doc INTERNAL
        !           411:  *
        !           412:  * @api DWORD | midiOutWrite | Synchronously process a midi output
        !           413:  *       buffer.
        !           414:  *
        !           415:  * @parm LPMIDIHDR | pHdr | Pointer to a midi buffer
        !           416:  *
        !           417:  * @parm PMIDIALLOC | pClient | The data associated with the logical midi
        !           418:  *     device.
        !           419:  *
        !           420:  * @rdesc A MMSYS... type return code for the application.
        !           421:  ***************************************************************************/
        !           422: STATIC DWORD midiOutWrite(PBYTE pData, ULONG Len, PMIDIALLOC pClient)
        !           423: {
        !           424:     DWORD BytesReturned;
        !           425: 
        !           426:     //
        !           427:     // Try passing the request to our driver
        !           428:     // We operate synchronously but allow for the driver to operate
        !           429:     // asynchronously by waiting on an event.
        !           430:     //
        !           431: 
        !           432:     if (!DeviceIoControl(
        !           433:                     pClient->hDev,
        !           434:                     IOCTL_MIDI_PLAY,
        !           435:                     (PVOID)pData,                // Input buffer
        !           436:                     Len,                         // Input buffer size
        !           437:                     NULL,                        // Output buffer
        !           438:                     0,                           // Output buffer size
        !           439:                     &BytesReturned,
        !           440:                     NULL)) {
        !           441:         return sndTranslateStatus();
        !           442:     }
        !           443: 
        !           444:     return MMSYSERR_NOERROR;
        !           445: }
        !           446: 
        !           447: /****************************************************************************
        !           448:  * @doc INTERNAL
        !           449:  *
        !           450:  * @api DWORD | midiInPutBuffer | Pass a buffer to receive midi input
        !           451:  *
        !           452:  * @parm LPMIDIHDR | pHdr | Pointer to a midi buffer
        !           453:  *
        !           454:  * @parm PMIDIALLOC | pClient | The data associated with the logical midi
        !           455:  *     device.
        !           456:  *
        !           457:  * @rdesc A MMSYS... type return code for the application.
        !           458:  ***************************************************************************/
        !           459: STATIC MMRESULT midiInPutBuffer(PLOCALMIDIHDR pHdr, PMIDIALLOC pClient)
        !           460: {
        !           461:     DWORD BytesReturned;
        !           462:     BOOL Result;
        !           463: 
        !           464:     WinAssert(!pHdr->Done);  // Flag should be clear ready for setting by Apc
        !           465: 
        !           466:     //
        !           467:     // BUGBUG - nice to have a semaphore for some of this !
        !           468:     //
        !           469: 
        !           470:     //
        !           471:     // Try passing the request to our driver
        !           472:     // We operate synchronously but allow for the driver to operate
        !           473:     // asynchronously by waiting on an event.
        !           474:     //
        !           475: 
        !           476:     Result = ReadFileEx(
        !           477:                  pClient->hDev,
        !           478:                  (LPVOID)&pHdr->MidiData,
        !           479:                  sizeof(pHdr->ExtraData) +
        !           480:                      sizeof(MIDI_DD_INPUT_DATA),
        !           481:                  &pHdr->Ovl,
        !           482:                  midiInOvl);
        !           483: 
        !           484:     //
        !           485:     // Put the buffer in our queue
        !           486:     //
        !           487: 
        !           488:     if (Result || GetLastError() == ERROR_IO_PENDING) {
        !           489:         PLOCALMIDIHDR *ppHdr;
        !           490:         pHdr->lpNext = NULL;
        !           491:         ppHdr = &pClient->Mid->DeviceQueue;
        !           492:         while (*ppHdr) {
        !           493:            ppHdr = &(*ppHdr)->lpNext;
        !           494:         }
        !           495: 
        !           496:         *ppHdr = pHdr;
        !           497: 
        !           498:         return MMSYSERR_NOERROR;
        !           499:     }
        !           500:     return sndTranslateStatus();
        !           501: }
        !           502: 
        !           503: /****************************************************************************
        !           504:  * @doc INTERNAL
        !           505:  *
        !           506:  * @api DWORD | midiInWrite | Pass a new buffer to the Auxiliary thread for
        !           507:  *       a midi device.
        !           508:  *
        !           509:  * @parm LPMIDIHDR | pHdr | Pointer to a midit buffer
        !           510:  *
        !           511:  * @parm PMIDIALLOC | pClient | The data associated with the logical midi
        !           512:  *     device.
        !           513:  *
        !           514:  * @rdesc A MMSYS... type return code for the application.
        !           515:  *
        !           516:  * @comm The buffer flags are set and the buffer is passed to the auxiliary
        !           517:  *     device task for processing.
        !           518:  ***************************************************************************/
        !           519: STATIC DWORD midiInWrite(LPMIDIHDR pHdr, PMIDIALLOC pClient)
        !           520: {
        !           521:     //
        !           522:     // Put the request at the end of our queue.
        !           523:     //
        !           524:     pHdr->dwFlags |= MHDR_INQUEUE;
        !           525:     pHdr->dwFlags &= ~MHDR_DONE;
        !           526:     pClient->AuxParam.pHdr = pHdr;
        !           527:     return midiThreadCall(MidiThreadAddBuffer, pClient);
        !           528: }
        !           529: 
        !           530: /****************************************************************************
        !           531:  * @doc INTERNAL
        !           532:  *
        !           533:  * @api DWORD | midiSetState | Set a midi device to a given state
        !           534:  *
        !           535:  * @parm PMIDIALLOC | pClient | The data associated with the logical midi
        !           536:  *     output device.
        !           537:  *
        !           538:  * @parm ULONG | State | The new state
        !           539:  *
        !           540:  * @rdesc A MMSYS... type return code for the application.
        !           541:  ***************************************************************************/
        !           542: STATIC DWORD midiSetState(PMIDIALLOC pClient, ULONG State)
        !           543: {
        !           544:     MMRESULT mRc;
        !           545: 
        !           546:     mRc = sndSetHandleData(pClient->hDev,
        !           547:                            sizeof(State),
        !           548:                            &State,
        !           549:                            IOCTL_MIDI_SET_STATE,
        !           550:                            pClient->Event);
        !           551: 
        !           552:     midiFlush(pClient);
        !           553: 
        !           554:     return mRc;
        !           555: }
        !           556: 
        !           557: 
        !           558: 
        !           559: /****************************************************************************
        !           560:  * @doc INTERNAL
        !           561:  *
        !           562:  * @api DWORD | midiThreadCall | Set the function for the thread to perform
        !           563:  *     and 'call' the thread using the event pair mechanism.
        !           564:  *
        !           565:  * @parm MIDITHREADFUNCTION | Function | The function to perform
        !           566:  *
        !           567:  * @parm PMIDIALLOC | Our logical device data
        !           568:  *
        !           569:  * @rdesc An MMSYS... type return value suitable for returning to the
        !           570:  *      application
        !           571:  *
        !           572:  * @comm The AuxParam field in the device data is the 'input' to
        !           573:  *      the function processing loop in MidiThread().
        !           574:  ***************************************************************************/
        !           575: STATIC DWORD midiThreadCall(MIDITHREADFUNCTION Function, PMIDIALLOC pClient)
        !           576: {
        !           577:     //
        !           578:     // Set the function code
        !           579:     //
        !           580:     pClient->AuxFunction = Function;
        !           581: 
        !           582:     //
        !           583:     // Kick off the thread
        !           584:     //
        !           585:     SetEvent(pClient->AuxEvent1);
        !           586: 
        !           587:     //
        !           588:     // Wait for it to complete
        !           589:     //
        !           590:     WaitForSingleObject(pClient->AuxEvent2, INFINITE);
        !           591: 
        !           592:     //
        !           593:     // Return the return code that our task set.
        !           594:     //
        !           595:     return pClient->AuxReturnCode;
        !           596: }
        !           597: 
        !           598: /****************************************************************************
        !           599:  * @doc INTERNAL
        !           600:  *
        !           601:  * @api void | midiInApc | Apc routine.  Called when a kernel sound driver
        !           602:  *     completes processing of a midi buffer.
        !           603:  *
        !           604:  * @parm PVOID | ApcContext | The Apc parameter.  In our case this is a
        !           605:  *     pointer to our midi device data.
        !           606:  *
        !           607:  * @parm PIO_STATUS_BLOCK | pIosb | Pointer to the Io status block
        !           608:  *     used for the request.
        !           609:  *
        !           610:  * @rdesc There is no return code.
        !           611:  ***************************************************************************/
        !           612: STATIC void midiInOvl(DWORD dwRet, DWORD dwBytesReturned, LPOVERLAPPED pOverlap)
        !           613: {
        !           614:     PLOCALMIDIHDR pHdr;
        !           615: 
        !           616:     pHdr = ((PLOCALMIDIHDR)pOverlap);
        !           617: 
        !           618:     WinAssert(((PMIDIALLOC)pHdr->pClient)->DeviceType == MidiInDevice);
        !           619: 
        !           620:     //
        !           621:     // Note that the buffer is complete.  We don't do anything else here
        !           622:     // because funny things happen if we call the client's callback
        !           623:     // routine from within an Apc.
        !           624:     //
        !           625: 
        !           626:     pHdr->BytesReturned = dwBytesReturned;
        !           627:     pHdr->Done = TRUE;
        !           628: }
        !           629: 
        !           630: /****************************************************************************
        !           631:  * @doc INTERNAL
        !           632:  *
        !           633:  * @api void | midiFlush | Buffer completion routine.  This completes
        !           634:  *     the work of the Apc routine at below Apc priority.  This gets
        !           635:  *     round the nasty situations arising when the user's callback
        !           636:  *     causes more apcs to run (I strongly suspect this is a kernel
        !           637:  *     but).
        !           638:  *
        !           639:  * @parm PMIDIALLOC | pClient | The client's handle data
        !           640:  *
        !           641:  * @rdesc There is no return code.
        !           642:  ***************************************************************************/
        !           643: 
        !           644: STATIC void midiFlush(PMIDIALLOC pClient)
        !           645: {
        !           646:     //
        !           647:     // Process any completed buffers - the Apc routine
        !           648:     // set the 'Done' flag in any completed requests.
        !           649:     // Note that the call to the user's callback can
        !           650:     // cause more requests to become complete
        !           651:     //
        !           652: 
        !           653:     if (pClient->DeviceType == MidiInDevice) {  // Output is synchronous
        !           654:         while (pClient->Mid->DeviceQueue &&
        !           655:                pClient->Mid->DeviceQueue->Done) {
        !           656: 
        !           657:             PLOCALMIDIHDR pHdr;
        !           658: 
        !           659:             pHdr = pClient->Mid->DeviceQueue;
        !           660: 
        !           661:             //
        !           662:             // Clear our flag ready for next time
        !           663:             //
        !           664: 
        !           665:             pHdr->Done = FALSE;
        !           666: 
        !           667:             //
        !           668:             // Take buffer off the device queue
        !           669:             //
        !           670: 
        !           671: 
        !           672:             pClient->Mid->DeviceQueue = pHdr->lpNext;
        !           673: 
        !           674:             //
        !           675:             // Grab the latest time estimate - convert from 100ns units
        !           676:             // to milliseconds
        !           677:             //
        !           678: 
        !           679:             pClient->Mid->dwCurTime =
        !           680:                 RtlExtendedLargeIntegerDivide(pHdr->MidiData.Time,
        !           681:                                               10000,
        !           682:                                               NULL).LowPart;
        !           683: 
        !           684:             //
        !           685:             // Complete our buffer
        !           686:             //
        !           687: 
        !           688:             if (!pClient->Mid->Bad) {
        !           689:                 int i;
        !           690:                 for (i = 0;
        !           691:                              i + sizeof(LARGE_INTEGER) < pHdr->BytesReturned;
        !           692:                                  i++) {
        !           693:                     midByteRec(pClient, pHdr->MidiData.Data[i]);
        !           694:                 }
        !           695:                 //
        !           696:                 // Requeue our buffer if we're still recording
        !           697:                 //
        !           698:                 if (pClient->Mid->fMidiInStarted) {
        !           699:                     if (midiInPutBuffer(pHdr, pClient) != MMSYSERR_NOERROR) {
        !           700:                         pClient->Mid->Bad = TRUE;
        !           701:                     }
        !           702:                 }
        !           703:             }
        !           704:         } // End of processing completed buffers
        !           705:     }
        !           706: }
        !           707: 
        !           708: /****************************************************************************
        !           709:  * @doc INTERNAL
        !           710:  *
        !           711:  * @api DWORD | midiThread | Midi device auxiliary thread.
        !           712:  *
        !           713:  * @parm LPVOID | lpParameter | The thread parameter.  In our case this is a
        !           714:  *     pointer to our midi device data.
        !           715:  *
        !           716:  * @rdesc Thread return code.
        !           717:  ***************************************************************************/
        !           718: STATIC DWORD midiThread(LPVOID lpParameter)
        !           719: {
        !           720:     PMIDIALLOC pClient;
        !           721:     BOOL Close;
        !           722: 
        !           723:     Close = FALSE;
        !           724: 
        !           725:     pClient = (PMIDIALLOC)lpParameter;
        !           726: 
        !           727:     //
        !           728:     // Set our thread to high priority so we don't fail to pass
        !           729:     // new buffers to the device when we get them back.  Also
        !           730:     // we don't want any gaps if callbacks are meant to play
        !           731:     // notes just received.
        !           732:     //
        !           733: 
        !           734:     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
        !           735: 
        !           736:     //
        !           737:     // We start notifying our creator we have started and
        !           738:     // waiting for something to do.
        !           739:     //
        !           740: 
        !           741:     SetEvent(pClient->AuxEvent2);
        !           742:     WaitForSingleObject(pClient->AuxEvent1, INFINITE);
        !           743: 
        !           744:     //
        !           745:     // Now we're going
        !           746:     //
        !           747: 
        !           748:     for(;;) {
        !           749:         //
        !           750:         // Initialize our return code
        !           751:         //
        !           752: 
        !           753:         pClient->AuxReturnCode = MMSYSERR_NOERROR;
        !           754: 
        !           755:         //
        !           756:         // Decode function number to perform
        !           757:         //
        !           758: 
        !           759:         switch (pClient->AuxFunction) {
        !           760:         case MidiThreadAddBuffer:
        !           761: 
        !           762:             //
        !           763:             // Add the buffer to our list to be processed
        !           764:             //
        !           765:             {
        !           766:                 LPMIDIHDR *pHdrSearch;
        !           767: 
        !           768:                 pClient->AuxParam.pHdr->lpNext = NULL;
        !           769: 
        !           770:                 pHdrSearch = &pClient->lpMIQueue;
        !           771:                 while (*pHdrSearch) {
        !           772:                     pHdrSearch = &(*pHdrSearch)->lpNext;
        !           773:                 }
        !           774: 
        !           775:                 *pHdrSearch = pClient->AuxParam.pHdr;
        !           776:             }
        !           777:             break;
        !           778: 
        !           779:         case MidiThreadSetState:
        !           780: 
        !           781: 
        !           782: 
        !           783:             switch (pClient->AuxParam.State) {
        !           784:             case MIDI_DD_RECORD:
        !           785:                 //
        !           786:                 // Start means we must add our buffers to the driver's list
        !           787:                 //
        !           788:                 if (!pClient->Mid->fMidiInStarted && !pClient->Mid->Bad) {
        !           789:                     int i;
        !           790:                     for (i = 0; i < NUMBER_OF_LOCAL_MIDI_BUFFERS; i++) {
        !           791:                         pClient->AuxReturnCode =
        !           792:                             midiInPutBuffer(&pClient->Mid->Bufs[i], pClient);
        !           793: 
        !           794:                         if (pClient->AuxReturnCode != MMSYSERR_NOERROR) {
        !           795:                             //
        !           796:                             // Failed to add our buffer so give up and
        !           797:                             // get our buffers back !
        !           798:                             //
        !           799:                             pClient->Mid->Bad = TRUE;
        !           800:                             break;
        !           801:                         }
        !           802:                     }
        !           803:                     //
        !           804:                     // Set Device state.  By issuing state changes on THIS
        !           805:                     // thread the calling thread can be sure that all Apc's
        !           806:                     // generated by buffer completions will complete
        !           807:                     // BEFORE this function completes.
        !           808:                     //
        !           809: 
        !           810:                     pClient->AuxReturnCode =
        !           811:                         midiSetState(pClient, pClient->AuxParam.State);
        !           812: 
        !           813:                     //
        !           814:                     // If this failed then get our buffers back,
        !           815:                     // otherwise set our new state
        !           816:                     //
        !           817:                     if (pClient->AuxReturnCode != MMSYSERR_NOERROR) {
        !           818:                         pClient->Mid->Bad = TRUE;
        !           819:                     } else {
        !           820:                         pClient->Mid->fMidiInStarted = TRUE;
        !           821:                     }
        !           822:                 } else {
        !           823:                     //
        !           824:                     // Already started or bad
        !           825:                     //
        !           826:                 }
        !           827:                 break;
        !           828: 
        !           829:             case MIDI_DD_STOP:
        !           830:                 //
        !           831:                 // Set Device state.  By issuing state changes on THIS
        !           832:                 // thread the calling thread can be sure that all Apc's
        !           833:                 // generated by buffer completions will complete
        !           834:                 // BEFORE this function completes.
        !           835:                 //
        !           836: 
        !           837:                 if (pClient->Mid->fMidiInStarted) {
        !           838:                     pClient->Mid->fMidiInStarted = FALSE;
        !           839: 
        !           840:                     //
        !           841:                     // RESET so we get our buffers back
        !           842:                     //
        !           843:                     pClient->AuxReturnCode =
        !           844:                         midiSetState(pClient, MIDI_DD_RESET);
        !           845:                         WinAssert(!pClient->Mid->DeviceQueue);
        !           846: 
        !           847:                     if (pClient->AuxReturnCode == MMSYSERR_NOERROR) {
        !           848:                         midSendPartBuffer(pClient);
        !           849:                     }
        !           850:                 }
        !           851:                 break;
        !           852: 
        !           853:             case MIDI_DD_RESET:
        !           854:                 //
        !           855:                 // Set Device state.  By issuing state changes on THIS
        !           856:                 // thread the calling thread can be sure that all Apc's
        !           857:                 // generated by buffer completions will complete
        !           858:                 // BEFORE this function completes.
        !           859:                 //
        !           860: 
        !           861:                 if (pClient->Mid->fMidiInStarted) {
        !           862:                     pClient->Mid->fMidiInStarted = FALSE;
        !           863:                     pClient->AuxReturnCode =
        !           864:                         midiSetState(pClient, pClient->AuxParam.State);
        !           865:                         WinAssert(!pClient->Mid->DeviceQueue);
        !           866: 
        !           867:                     if (pClient->AuxReturnCode == MMSYSERR_NOERROR) {
        !           868:                         pClient->Mid->Bad = FALSE; // Recovered !!
        !           869:                         midSendPartBuffer(pClient);
        !           870:                     }
        !           871:                 }
        !           872:                 //
        !           873:                 // We zero the input queue anyway - compatibility with
        !           874:                 // windows 3.1
        !           875:                 //
        !           876:                 midFreeQ(pClient);
        !           877:                 break;
        !           878: 
        !           879:             }
        !           880:             break;
        !           881: 
        !           882:         case MidiThreadSetData:
        !           883:             {
        !           884:                 pClient->AuxReturnCode =
        !           885:                     sndSetHandleData(pClient->hDev,
        !           886:                                      pClient->AuxParam.GetSetData.DataLen,
        !           887:                                      pClient->AuxParam.GetSetData.pData,
        !           888:                                      pClient->AuxParam.GetSetData.Function,
        !           889:                                      pClient->Event);
        !           890:             }
        !           891:             break;
        !           892: 
        !           893:         case MidiThreadClose:
        !           894:             //
        !           895:             // Try to complete.
        !           896:             // If we're completed all our buffers then we can.
        !           897:             // otherwise we can't
        !           898:             //
        !           899:             if (pClient->lpMIQueue == NULL) {
        !           900:                 pClient->AuxReturnCode = MMSYSERR_NOERROR;
        !           901:                 Close = TRUE;
        !           902:             } else {
        !           903:                 pClient->AuxReturnCode = MIDIERR_STILLPLAYING;
        !           904:             }
        !           905:             break;
        !           906: 
        !           907:         default:
        !           908:             WinAssert(FALSE);   // Invalid call
        !           909:             break;
        !           910:         }
        !           911:         //
        !           912:         // Trap invalid callers
        !           913:         //
        !           914:         pClient->AuxFunction = MidiThreadInvalid;
        !           915: 
        !           916:                 //
        !           917:                 // See if apcs completed
        !           918:                 //
        !           919:                 midiFlush(pClient);
        !           920: 
        !           921:         //
        !           922:         // Release the caller
        !           923:         //
        !           924:         SetEvent(pClient->AuxEvent2);
        !           925: 
        !           926:         //
        !           927:         // Complete ?
        !           928:         //
        !           929:         if (Close) {
        !           930:             break;
        !           931:         }
        !           932:         //
        !           933:         // Wait for more !
        !           934:         //
        !           935:         while (WaitForSingleObjectEx(pClient->AuxEvent1, INFINITE, TRUE) ==
        !           936:                    WAIT_IO_COMPLETION) {
        !           937:                         //
        !           938:                         // Complete buffers whose Apcs ran
        !           939:                         //
        !           940:                         midiFlush(pClient);
        !           941:         }
        !           942:     }
        !           943: 
        !           944:     //
        !           945:     // We've been asked to terminte
        !           946:     //
        !           947: 
        !           948:     return 1;
        !           949: }
        !           950: 
        !           951: 
        !           952: 
        !           953: /****************************************************************************
        !           954:  * @doc INTERNAL
        !           955:  *
        !           956:  * @api void | midiCallback | This calls DriverCallback for a MIDIHDR.
        !           957:  *
        !           958:  * @parm PMIDIALLOC | pMidi | Pointer to midi device.
        !           959:  *
        !           960:  * @parm DWORD | msg | The message.
        !           961:  *
        !           962:  * @parm DWORD | dw1 | message DWORD (dw2 is always set to 0).
        !           963:  *
        !           964:  * @rdesc There is no return value.
        !           965:  ***************************************************************************/
        !           966: void midiCallback(PMIDIALLOC pMidi, DWORD msg, DWORD dw1, DWORD dw2)
        !           967: {
        !           968: 
        !           969:     // invoke the callback function, if it exists.  dwFlags contains
        !           970:     // midi driver specific flags in the LOWORD and generic driver
        !           971:     // flags in the HIWORD
        !           972: 
        !           973:     if (pMidi->dwCallback)
        !           974:         DriverCallback(pMidi->dwCallback,       // user's callback DWORD
        !           975:                        HIWORD(pMidi->dwFlags),  // callback flags
        !           976:                        pMidi->hMidi,            // handle to the midi device
        !           977:                        msg,                     // the message
        !           978:                        pMidi->dwInstance,       // user's instance data
        !           979:                        dw1,                     // first DWORD
        !           980:                        dw2);                    // second DWORD
        !           981: }
        !           982: 
        !           983: 
        !           984: 
        !           985: /****************************************************************************
        !           986: 
        !           987:     This function conforms to the standard Midi input driver message proc
        !           988:     (midMessage), which is documented in mmddk.d.
        !           989: 
        !           990: ****************************************************************************/
        !           991: DWORD APIENTRY midMessage(DWORD id, DWORD msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
        !           992: {
        !           993:     PMIDIALLOC pInClient;
        !           994: 
        !           995:     switch (msg) {
        !           996: 
        !           997:         case MIDM_GETNUMDEVS:
        !           998:             D2(("MIDM_GETNUMDEVS"));
        !           999:             return sndGetNumDevs(MidiInDevice);
        !          1000: 
        !          1001:         case MIDM_GETDEVCAPS:
        !          1002:             D2(("MIDM_GETDEVCAPS"));
        !          1003:             return midiGetDevCaps(id, MidiInDevice, (LPBYTE)dwParam1,
        !          1004:                                   (DWORD)dwParam2);
        !          1005: 
        !          1006:         case MIDM_OPEN:
        !          1007:             D2(("MIDM_OPEN"));
        !          1008:             return midiOpen(MidiInDevice, id, dwUser, dwParam1, dwParam2);
        !          1009: 
        !          1010:         case MIDM_CLOSE:
        !          1011:             D2(("MIDM_CLOSE"));
        !          1012:             pInClient = (PMIDIALLOC)dwUser;
        !          1013: 
        !          1014:             //
        !          1015:             // Call our task to see if it's ready to complete
        !          1016:             //
        !          1017:             if (midiThreadCall(MidiThreadClose, pInClient) != 0L) {
        !          1018:                 return MIDIERR_STILLPLAYING;
        !          1019:             }
        !          1020: 
        !          1021:             //
        !          1022:             // Wait for our thread to terminate and close our device
        !          1023:             //
        !          1024:             WaitForSingleObject(pInClient->ThreadHandle, INFINITE);
        !          1025:             CloseHandle(pInClient->ThreadHandle);
        !          1026:             midiCleanUp(pInClient);
        !          1027: 
        !          1028:             //
        !          1029:             // Tell the caller we're done
        !          1030:             //
        !          1031:             midiCallback(pInClient, MIM_CLOSE, 0L, 0L);
        !          1032: 
        !          1033: 
        !          1034:             return MMSYSERR_NOERROR;
        !          1035: 
        !          1036:         case MIDM_ADDBUFFER:
        !          1037:             D2(("MIDM_ADDBUFFER"));
        !          1038: 
        !          1039:             // check if it's been prepared
        !          1040:             if (!(((LPMIDIHDR)dwParam1)->dwFlags & MHDR_PREPARED))
        !          1041:                 return MIDIERR_UNPREPARED;
        !          1042: 
        !          1043:             WinAssert(!(((LPMIDIHDR)dwParam1)->dwFlags & MHDR_INQUEUE));
        !          1044: 
        !          1045:             // if it is already in our Q, then we cannot do this
        !          1046:             if ( ((LPMIDIHDR)dwParam1)->dwFlags & MHDR_INQUEUE )
        !          1047:                 return ( MIDIERR_STILLPLAYING );
        !          1048: 
        !          1049:             // store the pointer to my MIDIALLOC structure in the midihdr
        !          1050:             pInClient = (PMIDIALLOC)dwUser;
        !          1051:             ((LPMIDIHDR)dwParam1)->reserved = (DWORD)(LPSTR)pInClient;
        !          1052: 
        !          1053:             return midiInWrite((LPMIDIHDR)dwParam1, pInClient);
        !          1054: 
        !          1055:         case MIDM_STOP:
        !          1056:             D2(("MIDM_PAUSE"));
        !          1057:             pInClient = (PMIDIALLOC)dwUser;
        !          1058:             pInClient->AuxParam.State = MIDI_DD_STOP;
        !          1059:             return midiThreadCall(MidiThreadSetState, pInClient);
        !          1060: 
        !          1061:         case MIDM_START:
        !          1062:             D2(("MIDM_RESTART"));
        !          1063:             pInClient = (PMIDIALLOC)dwUser;
        !          1064:             pInClient->AuxParam.State = MIDI_DD_RECORD;
        !          1065:             return midiThreadCall(MidiThreadSetState, pInClient);
        !          1066: 
        !          1067:         case MIDM_RESET:
        !          1068:             D2(("MIDM_RESET"));
        !          1069:             pInClient = (PMIDIALLOC)dwUser;
        !          1070:             pInClient->AuxParam.State = MIDI_DD_RESET;
        !          1071:             return midiThreadCall(MidiThreadSetState, pInClient);
        !          1072: 
        !          1073:         default:
        !          1074:             return MMSYSERR_NOTSUPPORTED;
        !          1075:     }
        !          1076: 
        !          1077:     //
        !          1078:     // Should not get here
        !          1079:     //
        !          1080: 
        !          1081:     WinAssert(0);
        !          1082:     return MMSYSERR_NOTSUPPORTED;
        !          1083: }
        !          1084: 
        !          1085: /****************************************************************************
        !          1086: 
        !          1087:     This function conforms to the standard Midi output driver message proc
        !          1088:     (modMessage), which is documented in mmddk.d.
        !          1089: 
        !          1090: ****************************************************************************/
        !          1091: DWORD APIENTRY modMessage(DWORD id, DWORD msg, DWORD dwUser, DWORD dwParam1,
        !          1092:                           DWORD dwParam2)
        !          1093: {
        !          1094:     PMIDIALLOC pOutClient;
        !          1095: 
        !          1096:     switch (msg) {
        !          1097:     case MODM_GETNUMDEVS:
        !          1098:         D2(("MODM_GETNUMDEVS"));
        !          1099:         return sndGetNumDevs(MidiOutDevice);
        !          1100: 
        !          1101:     case MODM_GETDEVCAPS:
        !          1102:         D2(("MODM_GETDEVCAPS"));
        !          1103:         return midiGetDevCaps(id, MidiOutDevice, (LPBYTE)dwParam1,
        !          1104:                               (DWORD)dwParam2);
        !          1105: 
        !          1106:     case MODM_OPEN:
        !          1107:         D2(("MODM_OPEN"));
        !          1108:         return midiOpen(MidiOutDevice, id, dwUser, dwParam1, dwParam2);
        !          1109: 
        !          1110:     case MODM_CLOSE:
        !          1111:         D2(("MODM_CLOSE"));
        !          1112:         pOutClient = (PMIDIALLOC)dwUser;
        !          1113: 
        !          1114:         midiCallback(pOutClient, MOM_CLOSE, 0L, 0L);
        !          1115: 
        !          1116:         //
        !          1117:         // Close our device
        !          1118:         //
        !          1119:         midiCleanUp(pOutClient);
        !          1120: 
        !          1121:         return MMSYSERR_NOERROR;
        !          1122: 
        !          1123:     case MODM_DATA:
        !          1124:         D2(("MODM_DATA"));
        !          1125:         {
        !          1126:             int i;
        !          1127:             BYTE b[4];
        !          1128:             for (i = 0; i < 4; i ++) {
        !          1129:                 b[i] = (BYTE)(dwParam1 % 256);
        !          1130:                 dwParam1 /= 256;
        !          1131:             }
        !          1132:             return midiOutWrite(b, modMIDIlength((PMIDIALLOC)dwUser, b[0]),
        !          1133:                                 (PMIDIALLOC)dwUser);
        !          1134:         }
        !          1135: 
        !          1136:     case MODM_LONGDATA:
        !          1137:         D2(("MODM_LONGDATA"));
        !          1138: 
        !          1139:         pOutClient = (PMIDIALLOC)dwUser;
        !          1140:         {
        !          1141:             LPMIDIHDR lpHdr;
        !          1142:             MMRESULT  mRet;
        !          1143: 
        !          1144:             //
        !          1145:             // check if it's been prepared
        !          1146:             //
        !          1147:             lpHdr = (LPMIDIHDR)dwParam1;
        !          1148:             if (!(lpHdr->dwFlags & MHDR_PREPARED)) {
        !          1149:                 return MIDIERR_UNPREPARED;
        !          1150:             }
        !          1151: 
        !          1152:             //
        !          1153:             //
        !          1154:             //
        !          1155: 
        !          1156:             mRet = midiOutWrite(lpHdr->lpData, lpHdr->dwBufferLength,
        !          1157:                                 pOutClient);
        !          1158: 
        !          1159:             // note that clearing the done bit or setting the inqueue bit
        !          1160:             // isn't necessary here since this function is synchronous -
        !          1161:             // the client will not get control back until it's done.
        !          1162: 
        !          1163:             lpHdr->dwFlags |= MHDR_DONE;
        !          1164: 
        !          1165:             // notify client
        !          1166: 
        !          1167:             if (mRet == MMSYSERR_NOERROR) {
        !          1168:                 midiCallback(pOutClient, MOM_DONE, (DWORD)lpHdr, 0L);
        !          1169:             }
        !          1170: 
        !          1171:             return mRet;
        !          1172:         }
        !          1173: 
        !          1174: 
        !          1175:     case MODM_RESET:
        !          1176:         D2(("MODM_RESET"));
        !          1177:         return midiSetState((PMIDIALLOC)dwUser, MIDI_DD_RESET);
        !          1178: 
        !          1179: 
        !          1180:     case MODM_SETVOLUME:
        !          1181:         D2(("MODM_SETVOLUME"));
        !          1182:         //pOutClient = (PMIDIALLOC)dwUser;
        !          1183:         //pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
        !          1184:         //pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
        !          1185:         //pOutClient->AuxParam.GetSetData.Function = IOCTL_MIDI_SET_VOLUME;
        !          1186:         //return midiThreadCall(MidiThreadSetData, pOutClient);
        !          1187: 
        !          1188:         return sndSetData(MidiOutDevice, id, sizeof(DWORD),
        !          1189:                           (PBYTE)&dwParam1, IOCTL_MIDI_SET_VOLUME);
        !          1190: 
        !          1191: 
        !          1192:     case MODM_GETVOLUME:
        !          1193:         D2(("MODM_GETVOLUME"));
        !          1194:         //pOutClient = (PMIDIALLOC)dwUser;
        !          1195:         //pOutClient->AuxParam.GetSetData.pData = *(PBYTE *)&dwParam1;
        !          1196:         //pOutClient->AuxParam.GetSetData.DataLen = sizeof(DWORD);
        !          1197:         //pOutClient->AuxParam.GetSetData.Function = IOCTL_MIDI_GET_VOLUME;
        !          1198:         //return midiThreadCall(MidiThreadGetData, pOutClient);
        !          1199: 
        !          1200:         return sndGetData(MidiOutDevice, id, sizeof(DWORD),
        !          1201:                           (PBYTE)dwParam1, IOCTL_MIDI_GET_VOLUME);
        !          1202: 
        !          1203:     case MODM_CACHEPATCHES:
        !          1204: 
        !          1205:         D2(("MODM_CACHEPATCHES"));
        !          1206: 
        !          1207:         pOutClient = (PMIDIALLOC)dwUser;
        !          1208:         {
        !          1209:             MIDI_DD_CACHE_PATCHES AppData;
        !          1210:             DWORD BytesReturned;
        !          1211: 
        !          1212:             AppData.Bank = HIWORD(dwParam2);
        !          1213:             AppData.Flags = LOWORD(dwParam2);
        !          1214:             memcpy(AppData.Patches, (PVOID)dwParam1, sizeof(AppData.Patches));
        !          1215: 
        !          1216:             return DeviceIoControl(
        !          1217:                            pOutClient->hDev,
        !          1218:                            IOCTL_MIDI_CACHE_PATCHES,
        !          1219:                            (PVOID)&AppData,
        !          1220:                            sizeof(AppData),
        !          1221:                            NULL,
        !          1222:                            0,
        !          1223:                            &BytesReturned,
        !          1224:                            NULL) ?
        !          1225:                  MMSYSERR_NOERROR :
        !          1226:                  sndTranslateStatus();
        !          1227:         }
        !          1228: 
        !          1229:     case MODM_CACHEDRUMPATCHES:
        !          1230: 
        !          1231:         D2(("MODM_CACHEDRUMPATCHES"));
        !          1232: 
        !          1233:         pOutClient = (PMIDIALLOC)dwUser;
        !          1234:         {
        !          1235:             MIDI_DD_CACHE_DRUM_PATCHES AppData;
        !          1236:             DWORD BytesReturned;
        !          1237: 
        !          1238:             AppData.Patch = HIWORD(dwParam2);
        !          1239:             AppData.Flags = LOWORD(dwParam2);
        !          1240:             memcpy(AppData.DrumPatches, (PVOID)dwParam1,
        !          1241:                    sizeof(AppData.DrumPatches));
        !          1242: 
        !          1243:             return DeviceIoControl(
        !          1244:                            pOutClient->hDev,
        !          1245:                            IOCTL_MIDI_CACHE_DRUM_PATCHES,
        !          1246:                            (PVOID)&AppData,
        !          1247:                            sizeof(AppData),
        !          1248:                            NULL,
        !          1249:                            0,
        !          1250:                            &BytesReturned,
        !          1251:                            NULL) ?
        !          1252:                  MMSYSERR_NOERROR :
        !          1253:                  sndTranslateStatus();
        !          1254:         }
        !          1255: 
        !          1256:     default:
        !          1257:         return MMSYSERR_NOTSUPPORTED;
        !          1258:     }
        !          1259: 
        !          1260:     //
        !          1261:     // Should not get here
        !          1262:     //
        !          1263: 
        !          1264:     WinAssert(0);
        !          1265:     return MMSYSERR_NOTSUPPORTED;
        !          1266: }
        !          1267: 
        !          1268: 
        !          1269: /***********************************************************************
        !          1270: 
        !          1271:  UTILITY ROUTINES PORTED DIRECTLY FROM WIN 3.1
        !          1272: 
        !          1273:  ***********************************************************************/
        !          1274: 
        !          1275: 
        !          1276: /****************************************************************************
        !          1277:  * @doc INTERNAL
        !          1278:  *
        !          1279:  * @api int | modMIDIlength | Get the length of a short midi message.
        !          1280:  *
        !          1281:  * @parm DWORD | dwMessage | The message.
        !          1282:  *
        !          1283:  * @rdesc Returns the length of the message.
        !          1284:  ***************************************************************************/
        !          1285: STATIC int modMIDIlength(PMIDIALLOC pClient, BYTE b)
        !          1286: {
        !          1287:     if (b >= 0xF8) {             // system realtime
        !          1288:         pClient->l = 1;
        !          1289:         return pClient->l;
        !          1290:     }
        !          1291: 
        !          1292:     switch (b) {
        !          1293:     case 0xF0: case 0xF4: case 0xF5: case 0xF6: case 0xF7:
        !          1294:         pClient->l = 1;
        !          1295:         return pClient->l;
        !          1296: 
        !          1297:     case 0xF1: case 0xF3:
        !          1298:         pClient->l = 2;
        !          1299:         return pClient->l;
        !          1300: 
        !          1301:     case 0xF2:
        !          1302:         pClient->l = 3;
        !          1303:         return pClient->l;
        !          1304:     }
        !          1305: 
        !          1306:     switch (b & 0xF0) {
        !          1307:     case 0x80: case 0x90: case 0xA0: case 0xB0: case 0xE0:
        !          1308:         pClient->l = 3;
        !          1309:         return pClient->l;
        !          1310: 
        !          1311:     case 0xC0: case 0xD0:
        !          1312:         pClient->l = 2;
        !          1313:         return pClient->l;
        !          1314:     }
        !          1315: 
        !          1316:     return (pClient->l - 1);        // uses previous value if data byte (running status)
        !          1317: }
        !          1318: 
        !          1319: /****************************************************************************
        !          1320:  * @doc INTERNAL
        !          1321:  *
        !          1322:  * @api void | midBufferWrite | This function writes a byte into the long
        !          1323:  *     message buffer.  If the buffer is full or a SYSEX_ERROR or
        !          1324:  *     end-of-sysex byte is received, the buffer is marked as 'done' and
        !          1325:  *     it's owner is called back.
        !          1326:  *
        !          1327:  * @parm BYTE | byte | The byte received.
        !          1328:  *
        !          1329:  * @rdesc There is no return value
        !          1330:  ***************************************************************************/
        !          1331: STATIC void midBufferWrite(PMIDIALLOC pClient, BYTE byte)
        !          1332: {
        !          1333: LPMIDIHDR  lpmh;
        !          1334: UINT       msg;
        !          1335: 
        !          1336:     // if no buffers, nothing happens
        !          1337:     if (pClient->lpMIQueue == NULL)
        !          1338:         return;
        !          1339: 
        !          1340:     lpmh = pClient->lpMIQueue;
        !          1341: 
        !          1342:     if (byte == SYSEX_ERROR) {
        !          1343:         D2(("sysexerror"));
        !          1344:         msg = MIM_LONGERROR;
        !          1345:     }
        !          1346:     else {
        !          1347:         D2(("bufferwrite"));
        !          1348:         msg = MIM_LONGDATA;
        !          1349:         *((LPSTR)(lpmh->lpData) + pClient->Mid->dwCurData++) = byte;
        !          1350:     }
        !          1351: 
        !          1352:     // if end of sysex, buffer full or error, send them back the buffer
        !          1353:     if ((byte == SYSEX_ERROR) || (byte == 0xF7) || (pClient->Mid->dwCurData >= lpmh->dwBufferLength)) {
        !          1354:         D2(("bufferdone"));
        !          1355:         pClient->lpMIQueue = pClient->lpMIQueue->lpNext;
        !          1356:         lpmh->dwBytesRecorded = pClient->Mid->dwCurData;
        !          1357:         pClient->Mid->dwCurData = 0L;
        !          1358:         lpmh->dwFlags |= MHDR_DONE;
        !          1359:         lpmh->dwFlags &= ~MHDR_INQUEUE;
        !          1360:         midiCallback(pClient, msg, (DWORD)lpmh, pClient->Mid->dwMsgTime);
        !          1361:     }
        !          1362: 
        !          1363:     return;
        !          1364: }
        !          1365: 
        !          1366: /****************************************************************************
        !          1367:  * @doc INTERNAL
        !          1368:  *
        !          1369:  * @api void | midByteRec | This function constructs the complete midi
        !          1370:  *     messages from the individual bytes received and passes the message
        !          1371:  *     to the client via his callback.
        !          1372:  *
        !          1373:  * @parm WORD | word | The byte received is in the low order byte.
        !          1374:  *
        !          1375:  * @rdesc There is no return value
        !          1376:  *
        !          1377:  * @comm Note that currently running status isn't turned off on errors.
        !          1378:  ***************************************************************************/
        !          1379: STATIC void midByteRec(PMIDIALLOC pClient, BYTE byte)
        !          1380: {
        !          1381: 
        !          1382:     if (!pClient->Mid->fMidiInStarted)
        !          1383:         return;
        !          1384: 
        !          1385:     // if it's a system realtime message, send it
        !          1386:     // this does not affect running status or any current message
        !          1387:     if (byte >= 0xF8) {
        !          1388:         D2((" rt"));
        !          1389:         midiCallback(pClient, MIM_DATA, (DWORD)byte, pClient->Mid->dwCurTime);
        !          1390:     }
        !          1391: 
        !          1392:     // else if it's a system common message
        !          1393:     else if (byte >= 0xF0) {
        !          1394: 
        !          1395:         if (pClient->Mid->fSysex) {                        // if we're in a sysex
        !          1396:             pClient->Mid->fSysex = FALSE;                  // status byte during sysex ends it
        !          1397:             if (byte == 0xF7)
        !          1398:             {
        !          1399:                 midBufferWrite(pClient, 0xF7);        // write in long message buffer
        !          1400:                 return;
        !          1401:             }
        !          1402:             else
        !          1403:                 midBufferWrite(pClient, SYSEX_ERROR); // secret code indicating error
        !          1404:         }
        !          1405: 
        !          1406:         if (pClient->Mid->dwMsg) {              // throw away any incomplete short data
        !          1407:             midiCallback(pClient, MIM_ERROR, pClient->Mid->dwMsg, pClient->Mid->dwMsgTime);
        !          1408:             pClient->Mid->dwMsg = 0L;
        !          1409:         }
        !          1410: 
        !          1411:         pClient->Mid->status = 0;               // kill running status
        !          1412:         pClient->Mid->dwMsgTime = pClient->Mid->dwCurTime;    // save timestamp
        !          1413: 
        !          1414:         switch(byte) {
        !          1415: 
        !          1416:         case 0xF0:
        !          1417:             D2((" F0"));
        !          1418:             pClient->Mid->fSysex = TRUE;
        !          1419:             midBufferWrite(pClient, 0xF0);
        !          1420:             break;
        !          1421: 
        !          1422:         case 0xF7:
        !          1423:             D2((" F7"));
        !          1424:             if (!pClient->Mid->fSysex)
        !          1425:                 midiCallback(pClient, MIM_ERROR, (DWORD)byte, pClient->Mid->dwMsgTime);
        !          1426:             // else already took care of it above
        !          1427:             break;
        !          1428: 
        !          1429:         case 0xF4:      // system common, no data bytes
        !          1430:         case 0xF5:
        !          1431:         case 0xF6:
        !          1432:             D2((" status0"));
        !          1433:             midiCallback(pClient, MIM_DATA, (DWORD)byte, pClient->Mid->dwMsgTime);
        !          1434:             pClient->Mid->bBytePos = 0;
        !          1435:             break;
        !          1436: 
        !          1437:         case 0xF1:      // system common, one data byte
        !          1438:         case 0xF3:
        !          1439:             D2((" status1"));
        !          1440:             pClient->Mid->dwMsg |= byte;
        !          1441:             pClient->Mid->bBytesLeft = 1;
        !          1442:             pClient->Mid->bBytePos = 1;
        !          1443:             break;
        !          1444: 
        !          1445:         case 0xF2:      // system common, two data bytes
        !          1446:             D2((" status2"));
        !          1447:             pClient->Mid->dwMsg |= byte;
        !          1448:             pClient->Mid->bBytesLeft = 2;
        !          1449:             pClient->Mid->bBytePos = 1;
        !          1450:             break;
        !          1451:         }
        !          1452:     }
        !          1453: 
        !          1454:     // else if it's a channel message
        !          1455:     else if (byte >= 0x80) {
        !          1456: 
        !          1457:         if (pClient->Mid->fSysex) {                        // if we're in a sysex
        !          1458:             pClient->Mid->fSysex = FALSE;                  // status byte during sysex ends it
        !          1459:             midBufferWrite(pClient, SYSEX_ERROR);     // secret code indicating error
        !          1460:         }
        !          1461: 
        !          1462:         if (pClient->Mid->dwMsg) {              // throw away any incomplete data
        !          1463:             midiCallback(pClient, MIM_ERROR, pClient->Mid->dwMsg, pClient->Mid->dwMsgTime);
        !          1464:             pClient->Mid->dwMsg = 0L;
        !          1465:         }
        !          1466: 
        !          1467:         pClient->Mid->status = byte;            // save for running status
        !          1468:         pClient->Mid->dwMsgTime = pClient->Mid->dwCurTime;    // save timestamp
        !          1469:         pClient->Mid->dwMsg |= byte;
        !          1470:         pClient->Mid->bBytePos = 1;
        !          1471: 
        !          1472:         switch(byte & 0xF0) {
        !          1473: 
        !          1474:         case 0xC0:         // channel message, one data byte
        !          1475:         case 0xD0:
        !          1476:             D2((" status1"));
        !          1477:             pClient->Mid->bBytesLeft = 1;
        !          1478:             break;
        !          1479: 
        !          1480:         case 0x80:         // channel message, two data bytes
        !          1481:         case 0x90:
        !          1482:         case 0xA0:
        !          1483:         case 0xB0:
        !          1484:         case 0xE0:
        !          1485:             D2((" status2"));
        !          1486:             pClient->Mid->bBytesLeft = 2;
        !          1487:             break;
        !          1488:         }
        !          1489:     }
        !          1490: 
        !          1491:     // else if it's an expected data byte for a long message
        !          1492:     else if (pClient->Mid->fSysex) {
        !          1493:         D2((" sxdata"));
        !          1494:         midBufferWrite(pClient, byte);        // write in long message buffer
        !          1495:     }
        !          1496: 
        !          1497:     // else if it's an expected data byte for a short message
        !          1498:     else if (pClient->Mid->bBytePos != 0) {
        !          1499:         D2((" data"));
        !          1500:         if ((pClient->Mid->status) && (pClient->Mid->bBytePos == 1)) { // if running status
        !          1501:              pClient->Mid->dwMsg |= pClient->Mid->status;
        !          1502:              pClient->Mid->dwMsgTime = pClient->Mid->dwCurTime;        // save timestamp
        !          1503:         }
        !          1504:         pClient->Mid->dwMsg += (DWORD)byte << ((pClient->Mid->bBytePos++) * 8);
        !          1505:         if (--pClient->Mid->bBytesLeft == 0) {
        !          1506:             midiCallback(pClient, MIM_DATA, pClient->Mid->dwMsg, pClient->Mid->dwMsgTime);
        !          1507:             pClient->Mid->dwMsg = 0L;
        !          1508:             if (pClient->Mid->status) {
        !          1509:                 pClient->Mid->bBytesLeft = pClient->Mid->bBytePos - (BYTE)1;
        !          1510:                 pClient->Mid->bBytePos = 1;
        !          1511:             }
        !          1512:             else {
        !          1513:                 pClient->Mid->bBytePos = 0;
        !          1514:             }
        !          1515:         }
        !          1516:     }
        !          1517: 
        !          1518:     // else if it's an unexpected data byte
        !          1519:     else {
        !          1520:         D2((" baddata"));
        !          1521:         midiCallback(pClient, MIM_ERROR, (DWORD)byte, pClient->Mid->dwMsgTime);
        !          1522:     }
        !          1523: 
        !          1524:     return;
        !          1525: }
        !          1526: 
        !          1527: 
        !          1528: /****************************************************************************
        !          1529:  * @doc INTERNAL
        !          1530:  *
        !          1531:  * @api void | midFreeQ | Free all buffers in the MIQueue.
        !          1532:  *
        !          1533:  * @comm Currently this is only called after sending off any partially filled
        !          1534:  *     buffers, so all buffers here are empty.  The timestamp value is 0 in
        !          1535:  *     this case.
        !          1536:  *
        !          1537:  * @rdesc There is no return value.
        !          1538:  ***************************************************************************/
        !          1539: STATIC void midFreeQ(PMIDIALLOC pClient)
        !          1540: {
        !          1541: LPMIDIHDR   lpH, lpN;
        !          1542: 
        !          1543:     lpH = pClient->lpMIQueue;              // point to top of the queue
        !          1544:     pClient->lpMIQueue = NULL;             // mark the queue as empty
        !          1545:     pClient->Mid->dwCurData = 0L;
        !          1546: 
        !          1547:     while (lpH) {
        !          1548:         lpN = lpH->lpNext;
        !          1549:         lpH->dwFlags |= MHDR_DONE;
        !          1550:         lpH->dwFlags &= ~MHDR_INQUEUE;
        !          1551:         lpH->dwBytesRecorded = 0;
        !          1552:         midiCallback(pClient, MIM_LONGDATA, (DWORD)lpH,
        !          1553:                      pClient->Mid->dwCurTime);
        !          1554:         lpH = lpN;
        !          1555:     }
        !          1556: }
        !          1557: 
        !          1558: /****************************************************************************
        !          1559:  * @doc INTERNAL
        !          1560:  *
        !          1561:  * @api void | midSendPartBuffer | This function is called from midStop().
        !          1562:  *     It looks at the buffer at the head of the queue and, if it contains
        !          1563:  *     any data, marks it as done as sends it back to the client.
        !          1564:  *
        !          1565:  * @rdesc The return value is the number of bytes transfered. A value of zero
        !          1566:  *     indicates that there was no more data in the input queue.
        !          1567:  ***************************************************************************/
        !          1568: STATIC void midSendPartBuffer(PMIDIALLOC pClient)
        !          1569: {
        !          1570: LPMIDIHDR lpH;
        !          1571: 
        !          1572:     if (pClient->lpMIQueue && pClient->Mid->dwCurData) {
        !          1573:         lpH = pClient->lpMIQueue;
        !          1574:         pClient->lpMIQueue = pClient->lpMIQueue->lpNext;
        !          1575:         lpH->dwFlags |= MHDR_DONE;
        !          1576:         lpH->dwFlags &= ~MHDR_INQUEUE;
        !          1577:         pClient->Mid->dwCurData = 0L;
        !          1578:         midiCallback(pClient, MIM_LONGERROR, (DWORD)lpH,
        !          1579:                      pClient->Mid->dwMsgTime);
        !          1580:     }
        !          1581: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.