|
|
1.1 ! root 1: /* ! 2: * ! 3: * Copyright (c) 1992 Microsoft Corporation ! 4: * ! 5: */ ! 6: ! 7: /* ! 8: * midi.c ! 9: * ! 10: * Midi FM Synthesis routines. converts midi messages into calls to ! 11: * FM Synthesis functions - currently supports base adlib (in adlib.c) ! 12: * and opl3 synthesisers (in opl3.c). ! 13: * ! 14: * 15 Dec 92 Geraint Davies - based on a combination of the adlib ! 15: * and WSS midi drivers. ! 16: */ ! 17: ! 18: ! 19: #include <windows.h> ! 20: #include <mmsystem.h> ! 21: ! 22: #include "mmddk.h" ! 23: #include "driver.h" ! 24: ! 25: #include "adlib.h" ! 26: #include "opl3.h" ! 27: ! 28: ! 29: /*********************************************************** ! 30: global memory */ ! 31: ! 32: ! 33: PORTALLOC gMidiInClient; // input client information structure ! 34: DWORD dwRefTime; // time when midi input was opened ! 35: ! 36: DWORD dwMsgTime; // timestamp (in ms) of current msg ! 37: DWORD dwMsg = 0L; // short midi message ! 38: BYTE bBytesLeft = 0; // number of bytes needed to complete message ! 39: BYTE bBytePos = 0; // position in short message buffer ! 40: DWORD dwCurData = 0L; // position in long message buffer ! 41: BOOL fSysex = FALSE; // are we in sysex mode? ! 42: BYTE status = 0; ! 43: BYTE fMidiInStarted = 0; /* has the midi been started */ ! 44: LPMIDIHDR lpMIQueue = NULL; ! 45: BYTE gbMidiInUse = 0; /* if MIDI is in use */ ! 46: ! 47: static WORD wMidiOutEntered = 0; // reentrancy check ! 48: static PORTALLOC gMidiOutClient; // client information ! 49: ! 50: /* transformation of linear velocity value to ! 51: logarithmic attenuation */ ! 52: BYTE gbVelocityAtten[32] = { ! 53: 40, 36, 32, 28, 23, 21, 19, 17, ! 54: 15, 14, 13, 12, 11, 10, 9, 8, ! 55: 7, 6, 5, 5, 4, 4, 3, 3, ! 56: 2, 2, 1, 1, 1, 0, 0, 0 }; ! 57: ! 58: short giBend[NUMCHANNELS]; /* bend for each channel */ ! 59: BYTE gbPatch[NUMCHANNELS]; /* patch number mapped to */ ! 60: ! 61: /* --- interface functions ---------------------------------- */ ! 62: ! 63: /* ! 64: * the functions in this section call out to adlib.c or opl3.c ! 65: * depending on which device we have installed. ! 66: */ ! 67: ! 68: ! 69: /*************************************************************** ! 70: MidiNoteOn - This turns a note on. (Including drums, with ! 71: a patch # of the drum Note + 128) ! 72: ! 73: inputs ! 74: BYTE bPatch - MIDI patch number ! 75: BYTE bNote - MIDI note number ! 76: BYTE bChannel - MIDI channel # ! 77: BYTE bVelocity - Velocity # ! 78: short iBend - current pitch bend from -32768, to 32767 ! 79: returns ! 80: WORD - note slot #, or 0xffff if its inaudible ! 81: */ ! 82: VOID NEAR PASCAL MidiNoteOn (BYTE bPatch, ! 83: BYTE bNote, BYTE bChannel, BYTE bVelocity, ! 84: short iBend) ! 85: { ! 86: switch(gMidiType) { ! 87: case TYPE_OPL3: ! 88: Opl3_NoteOn(bPatch, bNote, bChannel, bVelocity, iBend); ! 89: break; ! 90: ! 91: case TYPE_ADLIB: ! 92: Adlib_NoteOn(bPatch, bNote, bChannel, bVelocity, iBend); ! 93: break; ! 94: } ! 95: return; ! 96: } ! 97: ! 98: ! 99: /************************************************************** ! 100: MidiNoteOff - This turns a note off. (Including drums, ! 101: with a patch # of the drum note + 128) ! 102: ! 103: inputs ! 104: BYTE bPatch - MIDI patch # ! 105: BYTE bNote - MIDI note number ! 106: BYTE bChannel - MIDI channel # ! 107: returns ! 108: none ! 109: */ ! 110: VOID FAR PASCAL MidiNoteOff (BYTE bPatch, ! 111: BYTE bNote, BYTE bChannel) ! 112: { ! 113: switch (gMidiType) { ! 114: case TYPE_OPL3: ! 115: Opl3_NoteOff(bPatch, bNote, bChannel); ! 116: break; ! 117: ! 118: case TYPE_ADLIB: ! 119: Adlib_NoteOff(bPatch, bNote, bChannel); ! 120: break; ! 121: } ! 122: } ! 123: ! 124: /************************************************************** ! 125: MidiAllNotesOff - switch off all active voices. ! 126: ! 127: inputs - none ! 128: returns - none ! 129: */ ! 130: VOID MidiAllNotesOff(void) ! 131: { ! 132: switch (gMidiType) { ! 133: case TYPE_OPL3: ! 134: Opl3_AllNotesOff(); ! 135: break; ! 136: ! 137: case TYPE_ADLIB: ! 138: Adlib_AllNotesOff(); ! 139: break; ! 140: } ! 141: } ! 142: ! 143: ! 144: /************************************************************** ! 145: MidiNewVolume - This should be called if a volume level ! 146: has changed. This will adjust the levels of all the playing ! 147: voices. ! 148: ! 149: inputs ! 150: WORD wLeft - left attenuation (1.5 db units) ! 151: WORD wRight - right attenuation (ignore if mono) ! 152: returns ! 153: none ! 154: */ ! 155: VOID FAR PASCAL MidiNewVolume (WORD wLeft, WORD wRight) ! 156: { ! 157: switch (gMidiType) { ! 158: case TYPE_OPL3: ! 159: Opl3_NewVolume(wLeft, wRight); ! 160: break; ! 161: ! 162: case TYPE_ADLIB: ! 163: Adlib_NewVolume(wLeft, wRight); ! 164: break; ! 165: } ! 166: ! 167: } ! 168: ! 169: /*************************************************************** ! 170: MidiChannelVolume - set the volume level for an individual channel. ! 171: ! 172: inputs ! 173: BYTE bChannel - channel number to change ! 174: WORD wAtten - attenuation in 1.5 db units ! 175: ! 176: returns ! 177: none ! 178: */ ! 179: VOID FAR PASCAL MidiChannelVolume(BYTE bChannel, WORD wAtten) ! 180: { ! 181: ! 182: switch (gMidiType) { ! 183: case TYPE_OPL3: ! 184: Opl3_ChannelVolume(bChannel, wAtten); ! 185: break; ! 186: ! 187: case TYPE_ADLIB: ! 188: Adlib_ChannelVolume(bChannel, wAtten); ! 189: break; ! 190: } ! 191: ! 192: } ! 193: ! 194: ! 195: ! 196: /*************************************************************** ! 197: MidiSetPan - set the left-right pan position. ! 198: ! 199: inputs ! 200: BYTE bChannel - channel number to alter ! 201: BYTE bPan - 0 for left, 127 for right or somewhere in the middle. ! 202: ! 203: returns - none ! 204: */ ! 205: VOID FAR PASCAL MidiSetPan(BYTE bChannel, BYTE bPan) ! 206: { ! 207: switch (gMidiType) { ! 208: case TYPE_OPL3: ! 209: Opl3_SetPan(bChannel, bPan); ! 210: break; ! 211: ! 212: case TYPE_ADLIB: ! 213: Adlib_SetPan(bChannel, bPan); ! 214: break; ! 215: } ! 216: ! 217: } ! 218: ! 219: /*************************************************************** ! 220: MidiPitchBend - This pitch bends a channel. ! 221: ! 222: inputs ! 223: BYTE bChannel - channel ! 224: short iBend - Values from -32768 to 32767, being ! 225: -2 to +2 half steps ! 226: returns ! 227: none ! 228: */ ! 229: VOID NEAR PASCAL MidiPitchBend (BYTE bChannel, ! 230: short iBend) ! 231: { ! 232: switch (gMidiType) { ! 233: case TYPE_OPL3: ! 234: Opl3_PitchBend(bChannel, iBend); ! 235: break; ! 236: ! 237: case TYPE_ADLIB: ! 238: Adlib_PitchBend(bChannel, iBend); ! 239: break; ! 240: } ! 241: ! 242: } ! 243: ! 244: /*************************************************************** ! 245: MidiBoardInit - initialise board and load patches as necessary. ! 246: ! 247: * inputs - none ! 248: * returns - 0 for success or the error code ! 249: */ ! 250: WORD MidiBoardInit(void) ! 251: { ! 252: /* ! 253: * load patch tables and reset board ! 254: */ ! 255: ! 256: switch (gMidiType) { ! 257: case TYPE_OPL3: ! 258: return( Opl3_BoardInit()); ! 259: break; ! 260: ! 261: case TYPE_ADLIB: ! 262: return (Adlib_BoardInit()); ! 263: break; ! 264: } ! 265: return(MMSYSERR_ERROR); ! 266: } ! 267: ! 268: /* ! 269: * MidiBoardReset - silence the board and set all voices off. ! 270: */ ! 271: VOID MidiBoardReset(void) ! 272: { ! 273: BYTE i; ! 274: ! 275: /* ! 276: * switch off pitch bend (we own this, not the opl3/adlib code) ! 277: */ ! 278: for (i = 0; i < NUMCHANNELS; i++) ! 279: giBend[i] = 0; ! 280: ! 281: /* ! 282: * set all voices off, set channel atten to default, ! 283: * & silence board. ! 284: */ ! 285: switch (gMidiType) { ! 286: case TYPE_OPL3: ! 287: Opl3_BoardReset(); ! 288: break; ! 289: ! 290: case TYPE_ADLIB: ! 291: Adlib_BoardReset(); ! 292: break; ! 293: } ! 294: } ! 295: ! 296: ! 297: ! 298: /* --- midi interpretation -------------------------------------*/ ! 299: ! 300: ! 301: /*************************************************************** ! 302: MidiMessage - This handles a MIDI message. This ! 303: does not do running status. ! 304: ! 305: inputs ! 306: DWORD dwData - up to 4 bytes of MIDI data ! 307: depending upon the message. ! 308: returns ! 309: none ! 310: */ ! 311: VOID NEAR PASCAL MidiMessage (DWORD dwData) ! 312: { ! 313: BYTE bChannel, bVelocity, bNote; ! 314: WORD wTemp; ! 315: ! 316: // D1("\nMidiMessage"); ! 317: bChannel = (BYTE) dwData & (BYTE)0x0f; ! 318: bVelocity = (BYTE) (dwData >> 16) & (BYTE)0x7f; ! 319: bNote = (BYTE) ((WORD) dwData >> 8) & (BYTE)0x7f; ! 320: ! 321: switch ((BYTE)dwData & 0xf0) { ! 322: case 0x90: ! 323: #ifdef DEBUG ! 324: { ! 325: char szTemp[4]; ! 326: szTemp[0] = "0123456789abcdef"[bNote >> 4]; ! 327: szTemp[1] = "0123456789abcdef"[bNote & 0x0f]; ! 328: szTemp[2] = ' '; ! 329: szTemp[3] = 0; ! 330: if ((bChannel == 9) && bVelocity) D1(szTemp); ! 331: } ! 332: #endif ! 333: /* turn key on, or key off if volume == 0 */ ! 334: if (bVelocity) { ! 335: MidiNoteOn ( ! 336: (BYTE) ((bChannel == DRUMCHANNEL) ? ! 337: (BYTE) (bNote + 128) : (BYTE) gbPatch[bChannel]), ! 338: bNote, bChannel, bVelocity, (short) giBend[bChannel]); ! 339: break; ! 340: }; ! 341: ! 342: /* else, continue through and turn key off */ ! 343: case 0x80: ! 344: /* turn key off */ ! 345: MidiNoteOff ( ! 346: (BYTE) ((bChannel == DRUMCHANNEL) ? ! 347: (BYTE) (bNote + 128) : (BYTE) gbPatch[bChannel]), ! 348: bNote, bChannel); ! 349: break; ! 350: ! 351: case 0xb0: ! 352: // D1("\nChangeControl"); ! 353: /* change control */ ! 354: switch (bNote) { ! 355: case 7: ! 356: /* change channel volume */ ! 357: MidiChannelVolume( ! 358: gbVelocityAtten[(bVelocity & 0x7f) >> 2], ! 359: bChannel); ! 360: ! 361: break; ! 362: case 8: ! 363: case 10: ! 364: /* change the pan level */ ! 365: MidiSetPan(bChannel, bVelocity); ! 366: break; ! 367: }; ! 368: break; ! 369: ! 370: case 0xc0: ! 371: /* program change */ ! 372: ! 373: #if DBG ! 374: if (wDebugLevel > 1) { ! 375: char szTemp[64]; ! 376: ! 377: wsprintfA(szTemp, "0x%x: patch chan %d>%d\n",dwData, bChannel, bNote); ! 378: OutputDebugStringA(szTemp); ! 379: ! 380: } ! 381: #endif ! 382: ! 383: /* change patch */ ! 384: gbPatch[bChannel] = bNote; ! 385: break; ! 386: ! 387: case 0xe0: ! 388: // D1("\nBend"); ! 389: /* pitch bend */ ! 390: wTemp = ((WORD) bVelocity << 9) | ((WORD) bNote << 2); ! 391: giBend[bChannel] = (short) (WORD) (wTemp + 0x8000); ! 392: MidiPitchBend (bChannel, giBend[bChannel]); ! 393: ! 394: break; ! 395: }; ! 396: ! 397: return; ! 398: } ! 399: ! 400: /**************************************************************************** ! 401: * @doc INTERNAL ! 402: * ! 403: * @api void | midiCallback | This calls DriverCallback for a midi device. ! 404: * ! 405: * @parm NPPORTALLOC| pPort | Pointer to the PORTALLOC. ! 406: * ! 407: * @parm WORD | msg | The message to send. ! 408: * ! 409: * @parm DWORD | dw1 | Message-dependent parameter. ! 410: * ! 411: * @parm DWORD | dw2 | Message-dependent parameter. ! 412: * ! 413: * @rdesc There is no return value. ! 414: ***************************************************************************/ ! 415: void NEAR PASCAL midiCallback(NPPORTALLOC pPort, WORD msg, DWORD dw1, DWORD dw2) ! 416: { ! 417: ! 418: // invoke the callback function, if it exists. dwFlags contains driver- ! 419: // specific flags in the LOWORD and generic driver flags in the HIWORD ! 420: if (pPort->dwCallback) ! 421: DriverCallback(pPort->dwCallback, // client's callback DWORD ! 422: HIWORD(pPort->dwFlags) | DCB_NOSWITCH, // callback flags ! 423: pPort->hMidi, // handle to the wave device ! 424: msg, // the message ! 425: pPort->dwInstance, // client's instance data ! 426: dw1, // first DWORD ! 427: dw2); // second DWORD ! 428: } ! 429: ! 430: /**************************************************************************** ! 431: * @doc INTERNAL ! 432: * ! 433: * @api void | midBufferWrite | This function writes a byte into the long ! 434: * message buffer. If the buffer is full or a SYSEX_ERROR or ! 435: * end-of-sysex byte is received, the buffer is marked as 'done' and ! 436: * it's owner is called back. ! 437: * ! 438: * @parm BYTE | byte | The byte received. ! 439: * ! 440: * @rdesc There is no return value ! 441: ***************************************************************************/ ! 442: static void NEAR PASCAL midBufferWrite(BYTE byte) ! 443: { ! 444: LPMIDIHDR lpmh; ! 445: WORD msg; ! 446: ! 447: // if no buffers, nothing happens ! 448: if (lpMIQueue == NULL) ! 449: return; ! 450: ! 451: lpmh = lpMIQueue; ! 452: ! 453: if (byte == SYSEX_ERROR) { ! 454: D2("sysexerror"); ! 455: msg = MIM_LONGERROR; ! 456: } ! 457: else { ! 458: D2("bufferwrite"); ! 459: msg = MIM_LONGDATA; ! 460: *((HPSTR)(lpmh->lpData) + dwCurData++) = byte; ! 461: } ! 462: ! 463: // if end of sysex, buffer full or error, send them back the buffer ! 464: if ((byte == SYSEX_ERROR) || (byte == 0xF7) || (dwCurData >= lpmh->dwBufferLength)) { ! 465: D2("bufferdone"); ! 466: lpMIQueue = lpMIQueue->lpNext; ! 467: lpmh->dwBytesRecorded = dwCurData; ! 468: dwCurData = 0L; ! 469: lpmh->dwFlags |= MHDR_DONE; ! 470: lpmh->dwFlags &= ~MHDR_INQUEUE; ! 471: midiCallback(&gMidiInClient, msg, (DWORD)lpmh, dwMsgTime); ! 472: } ! 473: ! 474: return; ! 475: } ! 476: ! 477: ! 478: ! 479: /**************************************************************************** ! 480: ! 481: This function conforms to the standard MIDI output driver message proc ! 482: modMessage, which is documented in mmddk.d. ! 483: ! 484: ***************************************************************************/ ! 485: DWORD FAR PASCAL _loadds modMessage(UINT id, ! 486: UINT msg, DWORD dwUser, DWORD dwParam1, DWORD dwParam2) ! 487: { ! 488: LPMIDIHDR lpHdr; ! 489: #ifdef FOGHORN ! 490: WORD wTemp1, wTemp2; ! 491: #endif ! 492: LPSTR lpBuf; /* current spot in the long msg buf */ ! 493: DWORD dwBytesRead; /* how far are we in the buffer */ ! 494: DWORD dwMsg = 0; /* short midi message sent to synth */ ! 495: BYTE bBytePos=0; /* shift current byte by dwBytePos*s */ ! 496: BYTE bBytesLeft = 0; /* how many dat bytes needed */ ! 497: BYTE curByte; /* current byte in long buffer */ ! 498: UINT mRc; /* Return code */ ! 499: ! 500: #ifdef WIN16 ! 501: if (!fEnabled || gfMidiSuspended) { ! 502: D1("modMessage called while disabled"); ! 503: } else { ! 504: if (msg == MODM_GETNUMDEVS) ! 505: else ! 506: return MMSYSERR_NOTENABLED; ! 507: } ! 508: #endif // WIN16 ! 509: ! 510: ! 511: // this driver only supports one device ! 512: if (id != 0) { ! 513: D1("invalid midi device id"); ! 514: return MMSYSERR_BADDEVICEID; ! 515: } ! 516: ! 517: switch (msg) { ! 518: case MODM_GETNUMDEVS: ! 519: D1("MODM_GETNUMDEVS"); ! 520: #ifdef WIN16 ! 521: mRc = 1L; ! 522: #else ! 523: // ! 524: // Check if the kernel driver got loaded OK ! 525: // ! 526: { ! 527: HANDLE hDevice; ! 528: if (MidiOpenDevice(&hDevice, FALSE) == MMSYSERR_NOERROR) { ! 529: CloseHandle(hDevice); ! 530: mRc = 1L; ! 531: } else { ! 532: mRc = 0L; ! 533: } ! 534: } ! 535: #endif // WIN16 ! 536: break; ! 537: ! 538: case MODM_GETDEVCAPS: ! 539: D1("MODM_GETDEVCAPS"); ! 540: modGetDevCaps((LPBYTE)dwParam1, (WORD)dwParam2); ! 541: mRc = 0L; ! 542: break; ! 543: ! 544: case MODM_OPEN: ! 545: D1("MODM_OPEN"); ! 546: ! 547: /* open the midi */ ! 548: if (MidiOpen()) ! 549: return MMSYSERR_ALLOCATED; ! 550: ! 551: /* call up the volume control */ ! 552: #ifdef WIN16 ! 553: VolSendMsg (FH_MIDI_BEGIN); ! 554: #endif // WIN16 ! 555: ! 556: // save client information ! 557: gMidiOutClient.dwCallback = ((LPMIDIOPENDESC)dwParam1)->dwCallback; ! 558: gMidiOutClient.dwInstance = ((LPMIDIOPENDESC)dwParam1)->dwInstance; ! 559: gMidiOutClient.hMidi = ((LPMIDIOPENDESC)dwParam1)->hMidi; ! 560: gMidiOutClient.dwFlags = dwParam2; ! 561: ! 562: // notify client ! 563: midiCallback(&gMidiOutClient, MOM_OPEN, 0L, 0L); ! 564: ! 565: /* were in use */ ! 566: gbMidiInUse = TRUE; ! 567: ! 568: mRc = 0L; ! 569: break; ! 570: ! 571: case MODM_CLOSE: ! 572: D1("MODM_CLOSE"); ! 573: ! 574: /* shut up the FM synthesizer */ ! 575: MidiClose(); ! 576: ! 577: /* tell volume about this */ ! 578: #ifdef WIN16 ! 579: VolSendMsg (FH_MIDI_END); ! 580: #endif // WIN16 ! 581: ! 582: // notify client ! 583: midiCallback(&gMidiOutClient, MOM_CLOSE, 0L, 0L); ! 584: ! 585: /* were not used any more */ ! 586: gbMidiInUse = FALSE; ! 587: ! 588: mRc = 0L; ! 589: break; ! 590: ! 591: case MODM_RESET: ! 592: D1("MODM_RESET"); ! 593: ! 594: // ! 595: // turn off FM synthesis ! 596: // ! 597: // note that we increment our 're-entered' counter so that a ! 598: // background interrupt handler doesn't mess up our resetting ! 599: // of the synth by calling midiOut[Short|Long]Msg.. just ! 600: // practicing safe midi. NOTE: this should never be necessary ! 601: // if a midi app is PROPERLY written! ! 602: // ! 603: wMidiOutEntered++; ! 604: { ! 605: if (wMidiOutEntered == 1) ! 606: { ! 607: MidiReset(); ! 608: dwParam1 = 0L; ! 609: } ! 610: else ! 611: { ! 612: D1("MODM_RESET reentered!"); ! 613: dwParam1 = MIDIERR_NOTREADY; ! 614: } ! 615: } ! 616: wMidiOutEntered--; ! 617: mRc = (dwParam1); ! 618: break; ! 619: ! 620: case MODM_DATA: // message is in dwParam1 ! 621: #ifndef WIN16 ! 622: MidiCheckVolume(); // See if the volume has changed ! 623: #endif // WIN16 ! 624: ! 625: // make sure we're not being reentered ! 626: wMidiOutEntered++; ! 627: if (wMidiOutEntered > 1) { ! 628: D1("MODM_DATA reentered!"); ! 629: wMidiOutEntered--; ! 630: return MIDIERR_NOTREADY; ! 631: } ! 632: ! 633: /* if have repeated messages */ ! 634: if (dwParam1 & 0x00000080) /* status byte */ ! 635: status = LOBYTE(LOWORD(dwParam1)); ! 636: else ! 637: dwParam1 = (dwParam1 << 8) | ((DWORD) status); ! 638: ! 639: /* if not, have an FM synthesis message */ ! 640: MidiMessage (dwParam1); ! 641: ! 642: wMidiOutEntered--; ! 643: mRc = 0L; ! 644: break; ! 645: ! 646: case MODM_LONGDATA: // far pointer to header in dwParam1 ! 647: ! 648: #ifndef WIN16 ! 649: MidiCheckVolume(); // See if the volume has changed ! 650: #endif // WIN16 ! 651: ! 652: // make sure we're not being reentered ! 653: wMidiOutEntered++; ! 654: if (wMidiOutEntered > 1) { ! 655: D1("MODM_LONGDATA reentered!"); ! 656: wMidiOutEntered--; ! 657: return MIDIERR_NOTREADY; ! 658: } ! 659: ! 660: // check if it's been prepared ! 661: lpHdr = (LPMIDIHDR)dwParam1; ! 662: if (!(lpHdr->dwFlags & MHDR_PREPARED)) { ! 663: wMidiOutEntered--; ! 664: return MIDIERR_UNPREPARED; ! 665: } ! 666: ! 667: lpBuf = lpHdr->lpData; ! 668: dwBytesRead = 0; ! 669: curByte = *lpBuf; ! 670: ! 671: while (TRUE) { ! 672: /* if its a system realtime message send it and continue ! 673: this does not affect the running status */ ! 674: ! 675: if (curByte >= 0xf8) ! 676: MidiMessage (0x000000ff & curByte); ! 677: else if (curByte >= 0xf0) { ! 678: status = 0; /* kill running status */ ! 679: dwMsg = 0L; /* throw away any incomplete data */ ! 680: bBytePos = 0; /* start at beginning of message */ ! 681: ! 682: switch (curByte) { ! 683: case 0xf0: /* sysex - ignore */ ! 684: case 0xf7: ! 685: break; ! 686: case 0xf4: /* system common, no data */ ! 687: case 0xf5: ! 688: case 0xf6: ! 689: MidiMessage (0x000000ff & curByte); ! 690: break; ! 691: case 0xf1: /* system common, one data byte */ ! 692: case 0xf3: ! 693: dwMsg |= curByte; ! 694: bBytesLeft = 1; ! 695: bBytePos = 1; ! 696: break; ! 697: case 0xf2: /* system common, 2 data bytes */ ! 698: dwMsg |= curByte; ! 699: bBytesLeft = 2; ! 700: bBytePos = 1; ! 701: break; ! 702: }; ! 703: } ! 704: /* else its a channel message */ ! 705: else if (curByte >= 0x80) { ! 706: status = curByte; ! 707: dwMsg = 0L; ! 708: ! 709: switch (curByte & 0xf0) { ! 710: case 0xc0: /* channel message, one data */ ! 711: case 0xd0: ! 712: dwMsg |= curByte; ! 713: bBytesLeft = 1; ! 714: bBytePos = 1; ! 715: break; ! 716: case 0x80: /* two bytes */ ! 717: case 0x90: ! 718: case 0xa0: ! 719: case 0xb0: ! 720: case 0xe0: ! 721: dwMsg |= curByte; ! 722: bBytesLeft = 2; ! 723: bBytePos = 1; ! 724: break; ! 725: }; ! 726: } ! 727: ! 728: /* else if its an expected data byte */ ! 729: else if (bBytePos != 0) { ! 730: dwMsg |= ((DWORD)curByte) << (bBytePos++ * 8); ! 731: if (--bBytesLeft == 0) { ! 732: ! 733: MidiMessage (dwMsg); ! 734: ! 735: if (status) { ! 736: dwMsg |= status; ! 737: bBytesLeft = bBytePos - (BYTE)1; ! 738: bBytePos = 1; ! 739: } ! 740: else { ! 741: dwMsg = 0L; ! 742: bBytePos = 0; ! 743: }; ! 744: }; ! 745: }; ! 746: ! 747: /* read the next byte if there is one */ ! 748: /* remember we have already read and processed one byte that ! 749: * we have not yet counted- so we need to pre-inc, not post-inc ! 750: */ ! 751: if (++dwBytesRead >= lpHdr->dwBufferLength) break; ! 752: curByte = *++lpBuf; ! 753: }; /* while TRUE */ ! 754: ! 755: /* return buffer to client */ ! 756: lpHdr->dwFlags |= MHDR_DONE; ! 757: midiCallback (&gMidiOutClient, MOM_DONE, dwParam1, 0L); ! 758: ! 759: wMidiOutEntered--; ! 760: mRc = 0L; ! 761: break; ! 762: ! 763: #ifdef WIN16 ! 764: case MODM_SETVOLUME: ! 765: gwLinVol[VOL_MIDI][VOL_LEFT] = LOWORD(dwParam1); ! 766: gwLinVol[VOL_MIDI][VOL_RIGHT] = HIWORD(dwParam1); ! 767: VolSetMidiVolume (VolLinearToLog ((WORD)dwParam1), ! 768: VolLinearToLog ((WORD) (dwParam1 >> 16) )); ! 769: mRc = 0L; ! 770: mRc = MidiSetVolume(LOWORD(dwParam1) << 16, HIWORD(dwParam1) << 16); ! 771: break; ! 772: ! 773: case MODM_GETVOLUME: ! 774: *((DWORD FAR *)dwParam1) = ! 775: MAKELONG ( ! 776: gwLinVol[VOL_MIDI][VOL_LEFT], ! 777: gwLinVol[VOL_MIDI][VOL_RIGHT]); ! 778: mRc = 0L; ! 779: break; ! 780: #else ! 781: case MODM_SETVOLUME: ! 782: mRc = MidiSetVolume(LOWORD(dwParam1) << 16, HIWORD(dwParam1) << 16); ! 783: break; ! 784: ! 785: case MODM_GETVOLUME: ! 786: mRc = MidiGetVolume((LPDWORD)dwParam1); ! 787: break; ! 788: #endif // WIN16 ! 789: ! 790: ! 791: #ifdef FOGHORN ! 792: case MODM_VUMETER: ! 793: /* there is a duplicate in auxil.c which must be ! 794: kept up to date */ ! 795: /* if we're out of range then 0 volume */ ! 796: if (dwParam1 >= 16) { ! 797: *((DWORD FAR *)dwParam2) = 0; ! 798: return 0; ! 799: }; ! 800: ! 801: if (!gbMidiInUse) { ! 802: *((DWORD FAR *) dwParam2) = 0; ! 803: return MMSYSERR_ALLOCATED; ! 804: }; ! 805: ! 806: /* find out what the values are */ ! 807: wTemp1 = (WORD) gbLeftLevel[dwParam1] << 9; ! 808: wTemp2 = (WORD) gbRightLevel[dwParam1] << 9; ! 809: gbLeftLevel[dwParam1] = gbRightLevel[dwParam1] = 0; ! 810: *((DWORD FAR *) dwParam2) = ((DWORD) wTemp2 << 16) | wTemp1; ! 811: mRc = 0L; ! 812: break; ! 813: ! 814: case MODM_SETPATCH: ! 815: /* there is a duplicate in auxil.c which must be ! 816: kept up to date */ ! 817: wTemp1 = (LOWORD(dwParam2)); ! 818: if (wTemp1 >= 256) ! 819: wTemp1 = 0; ! 820: MidiSetPatch ((BYTE) wTemp1, (LPSTR) dwParam1, HIWORD(dwParam2)); ! 821: mRc = 0L; ! 822: break; ! 823: ! 824: case MODM_GETPATCH: ! 825: /* there is a duplicate in auxil.c which must be ! 826: kept up to date */ ! 827: wTemp1 = (LOWORD(dwParam2)); ! 828: if (wTemp1 >= 256) ! 829: wTemp1 = 0; ! 830: MidiGetPatch ((BYTE) wTemp1, (LPSTR) dwParam1, HIWORD(dwParam2)); ! 831: mRc = 0L; ! 832: break; ! 833: #endif ! 834: default: ! 835: return MMSYSERR_NOTSUPPORTED; ! 836: } ! 837: #ifndef WIN16 ! 838: MidiFlush(); ! 839: #endif // WIN16 ! 840: ! 841: return mRc; ! 842: ! 843: ! 844: // should never get here... ! 845: return MMSYSERR_NOTSUPPORTED; ! 846: } ! 847: ! 848: ! 849: static TCHAR BCODE gszDefPatchLib[] = TEXT("SYNTH.PAT"); ! 850: static TCHAR BCODE gszIniKeyPatchLib[] = INI_STR_PATCHLIB; ! 851: static TCHAR BCODE gszIniDrvSection[] = INI_DRIVER; ! 852: static TCHAR BCODE gszIniDrvFile[] = INI_SOUND; ! 853: static TCHAR BCODE gszSysIniSection[] = TEXT("synth.dll"); ! 854: static TCHAR BCODE gszSysIniFile[] = TEXT("System.Ini"); ! 855: ! 856: ! 857: ! 858: ! 859: /**************************************************************** ! 860: MidiInit - Initializes the FM synthesis chip and internal ! 861: variables. This assumes that HwInit() has been called ! 862: and that a card location has been found. This loads in ! 863: the patch information. ! 864: ! 865: inputs ! 866: none ! 867: returns ! 868: WORD - 0 if successful, else error ! 869: */ ! 870: WORD FAR PASCAL MidiInit (VOID) ! 871: { ! 872: // WORD i; ! 873: ! 874: D1 ("\nMidiInit"); ! 875: ! 876: // don't reset the patch map - it will be initialised at loadtime to 0 ! 877: // (because its static data) and we should not change it after that ! 878: // since the mci sequencer will not re-send patch change messages. ! 879: // ! 880: // ! 881: // /* reset all channels to patch 0 */ ! 882: // for (i = 0; i < NUMCHANNELS; i++) { ! 883: // gbPatch[i] = 0; ! 884: // } ! 885: ! 886: /* initialise the h/w specific patch tables */ ! 887: return MidiBoardInit(); ! 888: } ! 889: ! 890: ! 891: /***************************************************************** ! 892: MidiOpen - This should be called when a midi file is opened. ! 893: It initializes some variables and locks the patch global ! 894: memories. ! 895: ! 896: inputs ! 897: none ! 898: returns ! 899: UINT - 0 if succedes, else error ! 900: */ ! 901: UINT FAR PASCAL MidiOpen (VOID) ! 902: { ! 903: MMRESULT mRc; ! 904: ! 905: D1("\nMidiOpen"); ! 906: ! 907: ! 908: // ! 909: // For 32-bit we must open our kernel device ! 910: // ! 911: ! 912: mRc = MidiOpenDevice(&MidiDeviceHandle, TRUE); ! 913: ! 914: if (mRc != MMSYSERR_NOERROR) { ! 915: return mRc; ! 916: } ! 917: ! 918: ! 919: /* ! 920: * reset the device (set default channel attenuation etc) ! 921: */ ! 922: MidiBoardReset(); ! 923: ! 924: return 0; ! 925: } ! 926: ! 927: /*************************************************************** ! 928: MidiClose - This kills the playing midi voices and closes the kernel driver ! 929: ! 930: inputs ! 931: none ! 932: returns ! 933: none ! 934: */ ! 935: VOID FAR PASCAL MidiClose (VOID) ! 936: { ! 937: ! 938: D1("\nMidiClose"); ! 939: ! 940: /* make sure all notes turned off */ ! 941: MidiAllNotesOff(); ! 942: ! 943: MidiCloseDevice(MidiDeviceHandle); ! 944: } ! 945: ! 946: /** void FAR PASCAL MidiReset(void) ! 947: * ! 948: * DESCRIPTION: ! 949: * ! 950: * ! 951: * ARGUMENTS: ! 952: * (void) ! 953: * ! 954: * RETURN (void FAR PASCAL): ! 955: * ! 956: * ! 957: * NOTES: ! 958: * ! 959: ** cjp */ ! 960: ! 961: void FAR PASCAL MidiReset(void) ! 962: { ! 963: ! 964: D1("\nMidiReset"); ! 965: ! 966: /* make sure all notes turned off */ ! 967: MidiAllNotesOff(); ! 968: ! 969: /* silence the board and reset board-specific variables */ ! 970: MidiBoardReset(); ! 971: ! 972: ! 973: } /* MidiReset() */ ! 974: ! 975: ! 976: /***************************************************************************** ! 977: * @doc INTERNAL ! 978: * ! 979: * @api void | modGetDevCaps | Get the capabilities of the port. ! 980: * ! 981: * @parm LPBYTE | lpCaps | Far pointer to a MIDIOUTCAPS structure. ! 982: * ! 983: * @parm UINT | wSize | Size of the MIDIOUTCAPS structure. ! 984: * ! 985: * @rdesc There is no return value. ! 986: ****************************************************************************/ ! 987: void FAR PASCAL modGetDevCaps(LPBYTE lpCaps, UINT wSize) ! 988: { ! 989: MIDIOUTCAPS mc; ! 990: ! 991: mc.wMid = MM_MICROSOFT; ! 992: mc.wPid = MM_ADLIB; ! 993: mc.wTechnology = MOD_FMSYNTH; ! 994: mc.wVoices = 128; ! 995: ! 996: mc.wChannelMask = 0xffff; // all channels ! 997: mc.vDriverVersion = 0x100; ! 998: if (gMidiType == TYPE_OPL3) { ! 999: mc.wNotes = 12; ! 1000: mc.dwSupport = MIDICAPS_VOLUME | MIDICAPS_LRVOLUME; ! 1001: } else { ! 1002: mc.wNotes = 11; ! 1003: mc.dwSupport = MIDICAPS_VOLUME; ! 1004: } ! 1005: LoadString(ghModule, SR_STR_DRIVERMIDIOUT, mc.szPname, sizeof(mc.szPname)); ! 1006: ! 1007: AsMemCopy(lpCaps, &mc, min(wSize,sizeof(mc))); ! 1008: } ! 1009:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.