Annotation of ntddk/src/mmedia/mmdrv/mididd.c, revision 1.1.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.