|
|
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.