Annotation of ntddk/src/mmedia/synth/dll/midint.c, revision 1.1.1.1

1.1       root        1: /******************************************************************
                      2: 
                      3:     midint.c - midi routines for NT
                      4: 
                      5: 
                      6:     Copyright (c) 1991 Microsoft Corporation.  All Rights Reserved.
                      7: 
                      8: *******************************************************************/
                      9: 
                     10: #include <windows.h>
                     11: #include <mmsystem.h>
                     12: #include <mmddk.h>
                     13: #include <devioctl.h>
                     14: #include <ntddwave.h>
                     15: #include <ntddmidi.h>
                     16: #include <ntddaux.h>
                     17: #include "driver.h"
                     18: 
                     19: //
                     20: // global variable saying whether the kernel driver thinks
                     21: // we have an opl3-type or an adlib-type device
                     22: //
                     23: UINT gMidiType;
                     24: 
                     25: //
                     26: // For NT we pipe the port writes to the kernel driver in batches.
                     27: // Each batch is a pair of port,data values in DeviceData.
                     28: //
                     29: // MidiPosition contains the next position to use in the array.
                     30: 
                     31: SYNTH_DATA DeviceData[SYNTH_DATA_SIZE];
                     32: int MidiPosition;
                     33: HANDLE MidiDeviceHandle;
                     34: static MIDI_DD_VOLUME MidiVolume;
                     35: static MIDI_DD_VOLUME CurrentVolume;
                     36: 
                     37: static OVERLAPPED WriteOverlapped;      // We need to use this, otherwise
                     38:                                 // write file complains.
                     39: 
                     40: static OVERLAPPED VolumeOverlapped;// For asynch IO for volume notify
                     41: 
                     42: /*
                     43:  *  Translate a win error code (ERROR_...) to a multi-media error code
                     44:  *  (MMSYSERR_...).
                     45:  *
                     46:  */
                     47: 
                     48: MMRESULT MidiTranslateStatus(VOID)
                     49: {
                     50:     //
                     51:     // NOTE code copied from mmdrv!drvutil.c!sndTranslateStatus
                     52:     //
                     53: 
                     54:     switch (GetLastError()) {
                     55:     case NO_ERROR:
                     56:         break;
                     57: 
                     58:     case ERROR_BUSY:
                     59:         return MMSYSERR_ALLOCATED;
                     60: 
                     61:     case ERROR_NOT_SUPPORTED:
                     62:     case ERROR_INVALID_FUNCTION:
                     63:         return MMSYSERR_NOTSUPPORTED;
                     64: 
                     65:     case ERROR_NOT_ENOUGH_MEMORY:
                     66:         return MMSYSERR_NOMEM;
                     67: 
                     68:     case ERROR_ACCESS_DENIED:
                     69:         return MMSYSERR_BADDEVICEID;
                     70: 
                     71:     case ERROR_INSUFFICIENT_BUFFER:
                     72:         return MMSYSERR_INVALPARAM;
                     73: 
                     74:     default:
                     75:         return MMSYSERR_ERROR;
                     76:     }
                     77: 
                     78: }
                     79: 
                     80: 
                     81: /*************************************************************************
                     82: VolLinearToLog - converts a linear scale to logarithm
                     83:         0xffff -> 0
                     84:         0x0001 -> 191
                     85: 
                     86: inputs
                     87:         WORD    volume - 0 to 0xffff
                     88: returns
                     89:         BYTE    - value in decibels attenuation, each unit is 1.5 dB
                     90: */
                     91: BYTE VolLinearToLog (WORD volume)
                     92: {
                     93:     WORD    gain, shift;
                     94:     WORD    temp;
                     95:     WORD    lut[16] = {0,0,0,1,1,1,2,2,2,2,3,3,3,3,3,3};
                     96:     BYTE    out;
                     97: 
                     98:     /* get an estimate to within 6 dB of gain */
                     99:     for (temp = volume, gain = 0, shift = 0;
                    100:         temp != 0;
                    101:         gain += 4, temp >>= 1, shift++);
                    102: 
                    103:     /* look at highest 3 bits in number into look-up-table to
                    104:         find how many more dB */
                    105:     if (shift > 5)
                    106:         temp = volume >> (shift - 5);
                    107:     else if (shift < 5)
                    108:         temp = volume << (5 - shift);
                    109:     else
                    110:         temp = volume;
                    111:     temp &= 0x000f;
                    112: 
                    113:     gain += lut[temp];
                    114: 
                    115:     out = (BYTE) ((16 * 4) + 3 - gain);
                    116:     return (out < 128) ? out : (BYTE)127;
                    117: }
                    118: 
                    119: /*
                    120:  *  Set the MIDI device volume
                    121:  */
                    122: 
                    123: VOID MidiSetTheVolume(DWORD Left, DWORD Right)
                    124: {
                    125:     CurrentVolume.Left = Left;
                    126:     CurrentVolume.Right = Right;
                    127: 
                    128: 
                    129:     //
                    130:     // Call the routine to store and set the settings
                    131:     //
                    132: 
                    133:     MidiNewVolume(VolLinearToLog(HIWORD(Left)), VolLinearToLog(HIWORD(Right)));
                    134: }
                    135: 
                    136: /*
                    137:  *  See if the device volume has changed, if it has then copy it
                    138:  *  to our local variables.
                    139:  *
                    140:  *  This is achieved by passing an IOCTL_SOUND_GET_CHANGED volume
                    141:  *  packet to the kernel driver then testing if it's completed.
                    142:  */
                    143: 
                    144: VOID MidiCheckVolume(VOID)
                    145: {
                    146:     DWORD BytesReturned;
                    147: 
                    148:     if (WaitForSingleObject(VolumeOverlapped.hEvent, 0) == 0) {
                    149:         //
                    150:         // We got a volume change - Set the volume we've now got
                    151:         //
                    152: 
                    153:         MidiSetTheVolume(MidiVolume.Left, MidiVolume.Right);
                    154: 
                    155:         //
                    156:         // Wait until the volume does not change (so the IO does
                    157:         // not complete
                    158:         //
                    159: 
                    160:         while (DeviceIoControl(MidiDeviceHandle,
                    161:                              IOCTL_SOUND_GET_CHANGED_VOLUME,
                    162:                              &MidiVolume,
                    163:                              sizeof(MidiVolume),
                    164:                              &MidiVolume,
                    165:                              sizeof(MidiVolume),
                    166:                              &BytesReturned,
                    167:                              &VolumeOverlapped)) {
                    168:             MidiSetTheVolume(MidiVolume.Left, MidiVolume.Right);
                    169:         }
                    170:         if (GetLastError() == ERROR_IO_PENDING) {
                    171:             //
                    172:             // This is what we want
                    173:             //
                    174:             return;
                    175:         } else {
                    176:             //
                    177:             // We failed so make sure the next caller doesn't hang!
                    178:             //
                    179:             SetEvent(VolumeOverlapped.hEvent);
                    180:         }
                    181:     }
                    182: }
                    183: 
                    184: /*
                    185:  *  Send any data in our output strem to the kernel driver
                    186:  */
                    187: 
                    188: VOID MidiFlush(VOID)
                    189: {
                    190: 
                    191:     DWORD BytesWritten;
                    192: 
                    193:     if (MidiPosition != 0) {
                    194:         WriteFile(MidiDeviceHandle,
                    195:                   DeviceData,
                    196:                   MidiPosition * sizeof(SYNTH_DATA),
                    197:                   &BytesWritten,
                    198:                   &WriteOverlapped);
                    199:     }
                    200: 
                    201:     //
                    202:     // We know our kernel driver doesn't operate asynchronously so
                    203:     // we don't need to wait for the write to complete.
                    204:     //
                    205: 
                    206:     MidiPosition = 0;
                    207: }
                    208: 
                    209: /*
                    210:  *  Close the kernel device (if write type)
                    211:  */
                    212: 
                    213: VOID MidiCloseDevice(HANDLE DeviceHandle)
                    214: {
                    215:    /*
                    216:     *  Close the device first to stop any more events
                    217:     */
                    218: 
                    219:     CloseHandle(DeviceHandle);
                    220:     CloseHandle(VolumeOverlapped.hEvent);
                    221:     CloseHandle(WriteOverlapped.hEvent);
                    222:     DeviceHandle = NULL;
                    223:     VolumeOverlapped.hEvent = NULL;
                    224:     WriteOverlapped.hEvent = NULL;
                    225: 
                    226: }
                    227: 
                    228: /*
                    229:  *  Open the kernel device corresponding to our midi device
                    230:  */
                    231: 
                    232: MMRESULT MidiOpenDevice(LPHANDLE lpHandle, BOOL Write)
                    233: {
                    234:     HANDLE DeviceHandle;
                    235: 
                    236:     /* attempt to open the OPL3 device first. if this fails,
                    237:      * try the adlib.
                    238:      */
                    239:     DeviceHandle = CreateFile(L"\\\\.\\opl3.mid",
                    240:                               Write ? GENERIC_READ | GENERIC_WRITE :
                    241:                                       GENERIC_READ,
                    242:                               FILE_SHARE_WRITE,
                    243:                               NULL,
                    244:                               OPEN_EXISTING,
                    245:                               Write ? FILE_FLAG_OVERLAPPED : 0,
                    246:                               NULL);
                    247: 
                    248:     if (DeviceHandle != INVALID_HANDLE_VALUE) {
                    249:         gMidiType = TYPE_OPL3;
                    250:     } else {
                    251:         /* try for an adlib card instead */
                    252:         DeviceHandle = CreateFile(L"\\\\.\\adlib.mid",
                    253:                               Write ? GENERIC_READ | GENERIC_WRITE :
                    254:                                       GENERIC_READ,
                    255:                               FILE_SHARE_WRITE,
                    256:                               NULL,
                    257:                               OPEN_EXISTING,
                    258:                               Write ? FILE_FLAG_OVERLAPPED : 0,
                    259:                               NULL);
                    260: 
                    261:         if (DeviceHandle == INVALID_HANDLE_VALUE) {
                    262:             return MidiTranslateStatus();
                    263:         } else {
                    264:             gMidiType = TYPE_ADLIB;
                    265:         }
                    266:     }
                    267: 
                    268:     //
                    269:     // Load patches etc if we're actually going to write to the device
                    270:     //
                    271: 
                    272:     if (Write) {
                    273:         /*
                    274:          * always call MidiInit, in case we have not loaded the patches
                    275:          * for this device type. MidiInit can have a static bInit if needed
                    276:          */
                    277:         MidiInit();
                    278: 
                    279:         //
                    280:         // Create an event for waiting for volume changes and an
                    281:         // event for writes.
                    282:         //
                    283: 
                    284:         VolumeOverlapped.hEvent = CreateEvent(NULL, FALSE, TRUE, NULL);
                    285: 
                    286:         if (VolumeOverlapped.hEvent == NULL) {
                    287:             CloseHandle(DeviceHandle);
                    288: 
                    289:             return MidiTranslateStatus();
                    290:         }
                    291: 
                    292:         WriteOverlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
                    293: 
                    294:         if (WriteOverlapped.hEvent == NULL) {
                    295:             CloseHandle(VolumeOverlapped.hEvent);
                    296:             CloseHandle(DeviceHandle);
                    297: 
                    298:             return MidiTranslateStatus();
                    299:         }
                    300:     }
                    301: 
                    302:     //
                    303:     // Return our handle to the caller
                    304:     //
                    305: 
                    306:     *lpHandle = DeviceHandle;
                    307: 
                    308:     //
                    309:     // Set ourselves up to find out about volume changes
                    310:     //
                    311: 
                    312:     if (Write) {
                    313:         MidiCheckVolume();
                    314:     }
                    315: 
                    316: 
                    317:     return MMSYSERR_NOERROR;
                    318: 
                    319: }
                    320: 
                    321: /*
                    322:  *  Read the current volume setting direct from the kernel driver
                    323:  */
                    324: 
                    325: MMRESULT MidiGetVolume(LPDWORD lpVolume)
                    326: {
                    327:     HANDLE hDevice;
                    328:     MIDI_DD_VOLUME Vol;
                    329:     MMRESULT mRc;
                    330:     DWORD BytesReturned;
                    331: 
                    332:     //
                    333:     // Open a new device and get the volume
                    334:     //
                    335: 
                    336:     mRc = MidiOpenDevice(&hDevice, FALSE);   // Open for read only
                    337: 
                    338:     if (mRc == MMSYSERR_NOERROR) {
                    339: 
                    340:         if (!DeviceIoControl(hDevice,
                    341:                              IOCTL_MIDI_GET_VOLUME,
                    342:                              NULL,
                    343:                              0,
                    344:                              &Vol,
                    345:                              sizeof(MIDI_DD_VOLUME),
                    346:                              &BytesReturned,
                    347:                              NULL)) {
                    348:             mRc = MidiTranslateStatus();
                    349:         } else {
                    350:             *lpVolume = (DWORD)MAKELONG(HIWORD(Vol.Left), HIWORD(Vol.Right));
                    351:         }
                    352:         CloseHandle(hDevice);
                    353:     }
                    354: 
                    355:     return mRc;
                    356: }
                    357: 
                    358: /*
                    359:  *  Set the volume by calling the kernel driver - this will cause our
                    360:  *  IOCTL_SOUND_GET_CHANGED_VOLUME packet to complete
                    361:  */
                    362: 
                    363: MMRESULT MidiSetVolume(DWORD Left, DWORD Right)
                    364: {
                    365:     HANDLE hDevice;
                    366:     MIDI_DD_VOLUME Vol;
                    367:     MMRESULT mRc;
                    368:     DWORD BytesReturned;
                    369: 
                    370:     //
                    371:     // Open a new device and set the volume
                    372:     //
                    373: 
                    374:     Vol.Left = Left;
                    375:     Vol.Right = Right;
                    376: 
                    377:     mRc = MidiOpenDevice(&hDevice, FALSE);   // Open for read only
                    378: 
                    379:     if (mRc == MMSYSERR_NOERROR) {
                    380: 
                    381:         if (!DeviceIoControl(hDevice,
                    382:                              IOCTL_MIDI_SET_VOLUME,
                    383:                              &Vol,
                    384:                              sizeof(MIDI_DD_VOLUME),
                    385:                              NULL,
                    386:                              0,
                    387:                              &BytesReturned,
                    388:                              NULL)) {
                    389:             mRc = MidiTranslateStatus();
                    390:         }
                    391:         CloseHandle(hDevice);
                    392:     }
                    393: 
                    394:     return mRc;
                    395: }
                    396: 
                    397: 
                    398: /**************************************************************
                    399:  * MidiSendFM - Sends a byte to the FM chip.
                    400:  *
                    401:  * inputs
                    402:  *      WORD    wAddress - 0x00 to 0x1ff
                    403:  *      BYTE    bValue - value wirtten
                    404:  * returns
                    405:  *      none
                    406:  */
                    407: VOID FAR PASCAL MidiSendFM (DWORD wAddress, BYTE bValue)
                    408: {
                    409: 
                    410: 
                    411:     // NT :
                    412:     //
                    413:     // Pipe our port writes to the kernel driver
                    414:     // Note that MidiFlush is called again after each midi message
                    415:     // is processed by modMessage.
                    416:     //
                    417: 
                    418:     if (MidiPosition == SYNTH_DATA_SIZE) {
                    419:             MidiFlush();
                    420:     }
                    421: 
                    422:     DeviceData[MidiPosition].IoPort = wAddress < 0x100 ? 0x388 : 0x38a;
                    423:     DeviceData[MidiPosition].PortData = (WORD)(BYTE)wAddress;
                    424:     DeviceData[MidiPosition + 1].IoPort = wAddress < 0x100 ? 0x389 : 0x38b;
                    425:     DeviceData[MidiPosition + 1].PortData = (WORD)bValue;
                    426: 
                    427:     MidiPosition += 2;
                    428: 
                    429: }
                    430: 

unix.superglobalmegacorp.com

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