Annotation of ntddk/src/mmedia/synth/dll/midint.c, revision 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.