1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
4 * Sample MIDI Wine Driver for Linux
6 * Copyright 1994 Martin Ayotte
11 * 98/7 changes for making this MIDI driver work on OSS
12 * current support is limited to MIDI ports of OSS systems
13 * 98/9 rewriting MCI code for MIDI
14 * 98/11 splitted in midi.c and mcimidi.c
23 #if defined(__FreeBSD__) || defined(__OpenBSD__)
24 #include <sys/errno.h>
26 #include <sys/ioctl.h>
27 #include "wine/winuser16.h"
29 #include "multimedia.h"
44 LPMIDIOPENDESC midiDesc;
49 unsigned char incoming[3];
50 unsigned char incPrev;
62 LPMIDIOPENDESC midiDesc;
67 void* lpExtra; /* according to port type (MIDI, FM...), extra data when needed */
71 static WINE_MIDIIN MidiInDev [MAX_MIDIINDRV ];
72 static WINE_MIDIOUT MidiOutDev[MAX_MIDIOUTDRV];
74 /* this is the total number of MIDI out devices found */
76 /* this is the number of FM synthetizers (index from 0 to
77 NUMFMSYNTHDEVS - 1) */
78 int MODM_NUMFMSYNTHDEVS = 0;
79 /* this is the number of Midi ports (index from NUMFMSYNTHDEVS to
80 NUMFMSYNTHDEVS + NUMMIDIDEVS - 1) */
81 int MODM_NUMMIDIDEVS = 0;
83 /* this is the total number of MIDI out devices found */
87 static int midiSeqFD = -1;
88 static int numOpenMidiSeq = 0;
89 static UINT32 midiInTimerID = 0;
90 static int numStartedMidiIn = 0;
93 /* this structure holds pointers with information for each MIDI
96 LPMIDIOUTCAPS16 midiOutDevices[MAX_MIDIOUTDRV];
98 /* this structure holds pointers with information for each MIDI
101 LPMIDIINCAPS16 midiInDevices [MAX_MIDIINDRV];
104 * FIXME : all tests on device ID for midXXX and modYYY are made against
105 * MAX_MIDIxxDRV (when they are made) but should be done against the actual
106 * number of midi devices found...
107 * check also when HAVE_OSS is defined that midiDesc is not NULL
110 /*======================================================================*
111 * Low level MIDI implemantation *
112 *======================================================================*/
113 #ifdef SNDCTL_MIDI_INFO
114 /**************************************************************************
115 * MIDI_NotifyClient [internal]
117 static DWORD MIDI_NotifyClient(UINT16 wDevID, WORD wMsg,
118 DWORD dwParam1, DWORD dwParam2)
125 TRACE(midi,"wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",
126 wDevID, wMsg, dwParam1, dwParam2);
132 if (wDevID > MAX_MIDIOUTDRV)
133 return MCIERR_INTERNAL;
135 dwCallBack = MidiOutDev[wDevID].midiDesc->dwCallback;
136 uFlags = MidiOutDev[wDevID].wFlags;
137 hDev = MidiOutDev[wDevID].midiDesc->hMidi;
138 dwInstance = MidiOutDev[wDevID].midiDesc->dwInstance;
145 if (wDevID > MAX_MIDIINDRV)
146 return MCIERR_INTERNAL;
148 dwCallBack = MidiInDev[wDevID].midiDesc->dwCallback;
149 uFlags = MidiInDev[wDevID].wFlags;
150 hDev = MidiInDev[wDevID].midiDesc->hMidi;
151 dwInstance = MidiInDev[wDevID].midiDesc->dwInstance;
154 WARN(midi, "Unsupported MSW-MIDI message %u\n", wMsg);
155 return MCIERR_INTERNAL;
158 return DriverCallback(dwCallBack, uFlags, hDev, wMsg, dwInstance, dwParam1, dwParam2) ?
163 /**************************************************************************
164 * midiOpenSeq [internal]
166 static int midiOpenSeq(void)
168 if (numOpenMidiSeq == 0) {
169 midiSeqFD = open(MIDI_SEQ, O_RDWR, 0);
170 if (midiSeqFD == -1) {
171 ERR(midi, "can't open '%s' ! (%d)\n", MIDI_SEQ, errno);
174 if (fcntl(midiSeqFD, F_SETFL, O_NONBLOCK) < 0) {
175 WARN(midi, "can't set sequencer fd to non blocking (%d)\n", errno);
180 ioctl(midiSeqFD, SNDCTL_SEQ_RESET);
186 /**************************************************************************
187 * midiCloseSeq [internal]
189 static int midiCloseSeq(void)
191 if (--numOpenMidiSeq == 0) {
198 /* FIXME: this is a bad idea, it's even not static... */
201 /* FIXME: this is not reentrant, not static - because of global variable
203 /**************************************************************************
204 * seqbuf_dump [internal]
206 void seqbuf_dump(void)
209 if (write(midiSeqFD, _seqbuf, _seqbufptr) == -1) {
210 WARN(midi, "Can't write data to sequencer (%d/%d)!\n",
214 * in any case buffer is lost so that if many errors occur the buffer
220 #endif /* HAVE_OSS */
224 static void midReceiveChar(WORD wDevID, unsigned char value, DWORD dwTime)
228 TRACE(midi, "Adding %02xh to %d[%d]\n", value, wDevID, MidiInDev[wDevID].incLen);
230 if (wDevID >= MAX_MIDIINDRV) {
231 WARN(midi, "bad devID\n");
234 if (MidiInDev[wDevID].state == 0) {
235 TRACE(midi, "input not started, thrown away\n");
239 if (MidiInDev[wDevID].state & 2) { /* system exclusive */
240 LPMIDIHDR ptr = MidiInDev[wDevID].lpQueueHdr;
244 ((LPSTR)(ptr->reserved))[ptr->dwBytesRecorded++] = value;
245 if (ptr->dwBytesRecorded == ptr->dwBufferLength) {
249 if (value == 0xF7) { /* then end */
250 MidiInDev[wDevID].state &= ~2;
253 if (sbfb && ptr != NULL) {
254 ptr = MidiInDev[wDevID].lpQueueHdr;
255 ptr->dwFlags &= ~MHDR_INQUEUE;
256 ptr->dwFlags |= MHDR_DONE;
257 MidiInDev[wDevID].lpQueueHdr = (LPMIDIHDR)ptr->lpNext;
258 if (MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD)ptr, dwTime) != MMSYSERR_NOERROR) {
259 WARN(midi, "Couldn't notify client\n");
265 #define IS_CMD(_x) (((_x) & 0x80) == 0x80)
266 #define IS_SYS_CMD(_x) (((_x) & 0xF0) == 0xF0)
268 if (!IS_CMD(value) && MidiInDev[wDevID].incLen == 0) { /* try to reuse old cmd */
269 if (IS_CMD(MidiInDev[wDevID].incPrev) && !IS_SYS_CMD(MidiInDev[wDevID].incPrev)) {
270 MidiInDev[wDevID].incoming[0] = MidiInDev[wDevID].incPrev;
271 MidiInDev[wDevID].incLen = 1;
272 TRACE(midi, "Reusing old command %02xh\n", MidiInDev[wDevID].incPrev);
274 FIXME(midi, "error for midi-in, should generate MIM_ERROR notification:"
275 " prev=%02Xh, incLen=%02Xh\n",
276 MidiInDev[wDevID].incPrev, MidiInDev[wDevID].incLen);
280 MidiInDev[wDevID].incoming[(int)(MidiInDev[wDevID].incLen++)] = value;
281 if (MidiInDev[wDevID].incLen == 1 && !IS_SYS_CMD(MidiInDev[wDevID].incoming[0])) {
282 /* store new cmd, just in case */
283 MidiInDev[wDevID].incPrev = MidiInDev[wDevID].incoming[0];
287 #undef IS_SYS_CMD(_x)
289 switch (MidiInDev[wDevID].incoming[0] & 0xF0) {
292 case MIDI_KEY_PRESSURE:
293 case MIDI_CTL_CHANGE:
294 case MIDI_PITCH_BEND:
295 if (MidiInDev[wDevID].incLen == 3) {
296 toSend = (MidiInDev[wDevID].incoming[2] << 16) |
297 (MidiInDev[wDevID].incoming[1] << 8) |
298 (MidiInDev[wDevID].incoming[0] << 0);
301 case MIDI_PGM_CHANGE:
302 case MIDI_CHN_PRESSURE:
303 if (MidiInDev[wDevID].incLen == 2) {
304 toSend = (MidiInDev[wDevID].incoming[1] << 8) |
305 (MidiInDev[wDevID].incoming[0] << 0);
308 case MIDI_SYSTEM_PREFIX:
309 if (MidiInDev[wDevID].incoming[0] == 0xF0) {
310 MidiInDev[wDevID].state |= 2;
311 MidiInDev[wDevID].incLen = 0;
313 if (MidiInDev[wDevID].incLen == 1) {
314 toSend = (MidiInDev[wDevID].incoming[0] << 0);
319 WARN(midi, "This shouldn't happen (%02X)\n", MidiInDev[wDevID].incoming[0]);
322 TRACE(midi, "Sending event %08lx\n", toSend);
323 MidiInDev[wDevID].incLen = 0;
324 dwTime -= MidiInDev[wDevID].startTime;
325 if (MIDI_NotifyClient(wDevID, MIM_DATA, toSend, dwTime) != MMSYSERR_NOERROR) {
326 WARN(midi, "Couldn't notify client\n");
331 static VOID WINAPI midTimeCallback(HWND32 hwnd, UINT32 msg, UINT32 id, DWORD dwTime)
333 unsigned char buffer[256];
336 TRACE(midi, "(%04X, %d, %d, %lu)\n", hwnd, msg, id, dwTime);
338 len = read(midiSeqFD, buffer, sizeof(buffer));
340 if ((len % 4) != 0) {
341 WARN(midi, "bad length %d (%d)\n", len, errno);
345 for (idx = 0; idx < len; ) {
346 if (buffer[idx] & 0x80) {
348 "reading<8> %02x %02x %02x %02x %02x %02x %02x %02x\n",
349 buffer[idx + 0], buffer[idx + 1],
350 buffer[idx + 2], buffer[idx + 3],
351 buffer[idx + 4], buffer[idx + 5],
352 buffer[idx + 6], buffer[idx + 7]);
355 switch (buffer[idx + 0]) {
360 midReceiveChar(buffer[idx + 2], buffer[idx + 1], dwTime);
363 TRACE(midi, "Unsupported event %d\n", buffer[idx + 0]);
370 #endif /* HAVE_OSS */
372 /**************************************************************************
373 * midGetDevCaps [internal]
375 static DWORD midGetDevCaps(WORD wDevID, LPMIDIINCAPS16 lpCaps, DWORD dwSize)
377 LPMIDIINCAPS16 tmplpCaps;
379 TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize);
381 if (wDevID >= MIDM_NUMDEVS) {
382 return MMSYSERR_BADDEVICEID;
384 if (lpCaps == NULL) {
385 return MMSYSERR_INVALPARAM;
388 tmplpCaps = midiInDevices[wDevID];
389 lpCaps->wMid = tmplpCaps->wMid;
390 lpCaps->wPid = tmplpCaps->wPid;
391 lpCaps->vDriverVersion = tmplpCaps->vDriverVersion;
392 strcpy(lpCaps->szPname, tmplpCaps->szPname);
393 if (dwSize == sizeof(MIDIINCAPS16)) {
394 /* we should run win 95, so make use of dwSupport */
395 lpCaps->dwSupport = tmplpCaps->dwSupport;
396 } else if (dwSize != sizeof(MIDIINCAPS16) - sizeof(DWORD)) {
397 TRACE(midi, "bad size for lpCaps\n");
398 return MMSYSERR_INVALPARAM;
401 return MMSYSERR_NOERROR;
404 /**************************************************************************
407 static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
409 TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
411 if (lpDesc == NULL) {
412 WARN(midi, "Invalid Parameter !\n");
413 return MMSYSERR_INVALPARAM;
416 * how to check that content of lpDesc is correct ?
418 if (wDevID >= MAX_MIDIINDRV) {
419 WARN(midi,"wDevID too large (%u) !\n", wDevID);
420 return MMSYSERR_BADDEVICEID;
422 if (MidiInDev[wDevID].midiDesc != 0) {
423 WARN(midi, "device already open !\n");
424 return MMSYSERR_ALLOCATED;
426 if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) {
427 FIXME(midi, "No support for MIDI_IO_STATUS in dwFlags\n");
428 return MMSYSERR_INVALFLAG;
432 if (midiOpenSeq() < 0) {
433 return MMSYSERR_ERROR;
436 if (numStartedMidiIn++ == 0) {
437 midiInTimerID = SetTimer32(0, 0, 250, midTimeCallback);
438 if (!midiInTimerID) {
439 numStartedMidiIn = 0;
440 WARN(midi, "Couldn't start timer for midi-in\n");
442 return MMSYSERR_ERROR;
444 TRACE(midi, "Starting timer (%u) for midi-in\n", midiInTimerID);
448 int midi = open(MIDI_DEV, O_WRONLY, 0);
450 MidiInDev[wDevID].unixdev = 0;
452 WARN(midi,"can't open '%s' (%d)!\n", MIDI_DEV, errno);
453 return MMSYSERR_ALLOCATED;
455 MidiInDev[wDevID].unixdev = midi;
457 #endif /* HAVE_OSS */
459 MidiInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
460 switch (MidiInDev[wDevID].wFlags) {
462 TRACE(midi,"CALLBACK_NULL !\n");
465 TRACE(midi, "CALLBACK_WINDOW !\n");
468 TRACE(midi, "CALLBACK_TASK !\n");
471 TRACE(midi, "CALLBACK_FUNCTION (%08lX)!\n", lpDesc->dwCallback);
474 MidiInDev[wDevID].lpQueueHdr = NULL;
475 MidiInDev[wDevID].dwTotalPlayed = 0;
476 MidiInDev[wDevID].bufsize = 0x3FFF;
477 MidiInDev[wDevID].midiDesc = lpDesc;
478 MidiInDev[wDevID].state = 0;
480 MidiInDev[wDevID].incLen = 0;
481 MidiInDev[wDevID].startTime = 0;
482 #endif /* HAVE_OSS */
483 if (MIDI_NotifyClient(wDevID, MIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
484 WARN(midi,"can't notify client !\n");
485 return MMSYSERR_INVALPARAM;
487 return MMSYSERR_NOERROR;
490 /**************************************************************************
491 * midClose [internal]
493 static DWORD midClose(WORD wDevID)
495 int ret = MMSYSERR_NOERROR;
497 TRACE(midi, "(%04X);\n", wDevID);
499 if (wDevID >= MAX_MIDIINDRV) {
500 WARN(midi,"wDevID too bif (%u) !\n", wDevID);
501 return MMSYSERR_BADDEVICEID;
503 if (MidiInDev[wDevID].midiDesc == 0) {
504 WARN(midi, "device not opened !\n");
505 return MMSYSERR_ERROR;
507 if (MidiInDev[wDevID].lpQueueHdr != 0) {
508 return MIDIERR_STILLPLAYING;
512 if (midiSeqFD == -1) {
513 WARN(midi,"ooops !\n");
514 return MMSYSERR_ERROR;
516 if (--numStartedMidiIn == 0) {
517 TRACE(midi, "Stopping timer for midi-in\n");
518 if (!KillTimer32(0, midiInTimerID)) {
519 WARN(midi, "Couldn't stop timer for midi-in\n");
525 if (MidiInDev[wDevID].unixdev == 0) {
526 WARN(midi,"ooops !\n");
527 return MMSYSERR_ERROR;
529 close(MidiInDev[wDevID].unixdev);
530 MidiInDev[wDevID].unixdev = 0;
531 #endif /* HAVE_OSS */
532 MidiInDev[wDevID].bufsize = 0;
533 if (MIDI_NotifyClient(wDevID, MIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
534 WARN(midi,"can't notify client !\n");
535 ret = MMSYSERR_INVALPARAM;
537 MidiInDev[wDevID].midiDesc = 0;
541 /**************************************************************************
542 * midAddBuffer [internal]
544 static DWORD midAddBuffer(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
546 TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
548 if (lpMidiHdr == NULL) return MMSYSERR_INVALPARAM;
549 if (sizeof(MIDIHDR) != dwSize) return MMSYSERR_INVALPARAM;
550 if (lpMidiHdr->dwBufferLength == 0) return MMSYSERR_INVALPARAM;
551 if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING;
552 if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED;
554 if (MidiInDev[wDevID].lpQueueHdr == 0) {
555 MidiInDev[wDevID].lpQueueHdr = lpMidiHdr;
559 for (ptr = MidiInDev[wDevID].lpQueueHdr;
561 ptr = (LPMIDIHDR)ptr->lpNext);
562 ptr->lpNext = (struct midihdr_tag*)lpMidiHdr;
564 return MMSYSERR_NOERROR;
567 /**************************************************************************
568 * midPrepare [internal]
570 static DWORD midPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
572 TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
574 if (dwSize != sizeof(MIDIHDR) || lpMidiHdr == 0 ||
575 lpMidiHdr->lpData == 0 || lpMidiHdr->dwFlags != 0 ||
576 lpMidiHdr->dwBufferLength >= 0x10000ul)
577 return MMSYSERR_INVALPARAM;
579 lpMidiHdr->lpNext = 0;
580 lpMidiHdr->dwFlags |= MHDR_PREPARED;
581 lpMidiHdr->dwBytesRecorded = 0;
583 return MMSYSERR_NOERROR;
586 /**************************************************************************
587 * midUnprepare [internal]
589 static DWORD midUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
591 TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
593 if (dwSize != sizeof(MIDIHDR) || lpMidiHdr == 0 ||
594 lpMidiHdr->lpData == 0 || lpMidiHdr->dwBufferLength >= 0x10000ul)
595 return MMSYSERR_INVALPARAM;
597 if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED;
598 if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING;
600 lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
602 return MMSYSERR_NOERROR;
605 /**************************************************************************
606 * midReset [internal]
608 static DWORD midReset(WORD wDevID)
610 DWORD dwTime = GetTickCount();
612 TRACE(midi, "(%04X);\n", wDevID);
614 while (MidiInDev[wDevID].lpQueueHdr) {
615 MidiInDev[wDevID].lpQueueHdr->dwFlags &= ~MHDR_INQUEUE;
616 MidiInDev[wDevID].lpQueueHdr->dwFlags |= MHDR_DONE;
617 if (MIDI_NotifyClient(wDevID, MIM_LONGDATA,
618 (DWORD)MidiInDev[wDevID].lpQueueHdr, dwTime) != MMSYSERR_NOERROR) {
619 WARN(midi, "Couldn't notify client\n");
621 MidiInDev[wDevID].lpQueueHdr = (LPMIDIHDR)MidiInDev[wDevID].lpQueueHdr->lpNext;
624 return MMSYSERR_NOERROR;
628 /**************************************************************************
629 * midStart [internal]
631 static DWORD midStart(WORD wDevID)
633 TRACE(midi, "(%04X);\n", wDevID);
635 /* FIXME : should test value of wDevID */
638 MidiInDev[wDevID].state = 1;
639 MidiInDev[wDevID].startTime = GetTickCount();
640 return MMSYSERR_NOERROR;
642 return MMSYSERR_NOTENABLED;
643 #endif /* HAVE_OSS */
646 /**************************************************************************
649 static DWORD midStop(WORD wDevID)
651 TRACE(midi, "(%04X);\n", wDevID);
653 /* FIXME : should test value of wDevID */
656 MidiInDev[wDevID].state = 0;
657 return MMSYSERR_NOERROR;
659 return MMSYSERR_NOTENABLED;
660 #endif /* HAVE_OSS */
663 /*-----------------------------------------------------------------------*/
667 typedef struct sVoice {
668 int note; /* 0 means not used */
670 unsigned cntMark : 30,
673 #define sVS_PLAYING 1
674 #define sVS_SUSTAINED 2
677 typedef struct sChannel {
683 int bank; /* CTL_BANK_SELECT */
684 int volume; /* CTL_MAIN_VOLUME */
685 int balance; /* CTL_BALANCE */
686 int expression; /* CTL_EXPRESSION */
687 int sustain; /* CTL_SUSTAIN */
689 unsigned char nrgPmtMSB; /* Non register Parameters */
690 unsigned char nrgPmtLSB;
691 unsigned char regPmtMSB; /* Non register Parameters */
692 unsigned char regPmtLSB;
695 typedef struct sFMextra {
698 sChannel channel[16]; /* MIDI has only 16 channels */
699 sVoice voice[1]; /* dyn allocated according to sound card */
700 /* do not append fields below voice[1] since the size of this structure
701 * depends on the number of available voices on the FM synth...
705 extern unsigned char midiFMInstrumentPatches[16 * 128];
706 extern unsigned char midiFMDrumsPatches [16 * 128];
708 /**************************************************************************
709 * modFMLoad [internal]
711 static int modFMLoad(int dev)
714 struct sbi_instrument sbi;
719 memset(sbi.operators + 16, 0, 16);
720 for (i = 0; i < 128; i++) {
722 memcpy(sbi.operators, midiFMInstrumentPatches + i * 16, 16);
724 if (write(midiSeqFD, (char*)&sbi, sizeof(sbi)) == -1) {
725 WARN(midi, "Couldn't write patch for instrument %d (%d)!\n", sbi.channel, errno);
729 for (i = 0; i < 128; i++) {
730 sbi.channel = 128 + i;
731 memcpy(sbi.operators, midiFMDrumsPatches + i * 16, 16);
733 if (write(midiSeqFD, (char*)&sbi, sizeof(sbi)) == -1) {
734 WARN(midi, "Couldn't write patch for drum %d (%d)!\n", sbi.channel, errno);
741 /**************************************************************************
742 * modFMReset [internal]
744 static void modFMReset(WORD wDevID)
746 sFMextra* extra = (sFMextra*)MidiOutDev[wDevID].lpExtra;
747 sVoice* voice = extra->voice;
748 sChannel* channel = extra->channel;
751 for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
752 if (voice[i].status != sVS_UNUSED) {
753 SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64);
755 SEQ_KEY_PRESSURE(wDevID, i, 127, 0);
756 SEQ_CONTROL(wDevID, i, SEQ_VOLMODE, VOL_METHOD_LINEAR);
758 voice[i].channel = -1;
759 voice[i].cntMark = 0;
760 voice[i].status = sVS_UNUSED;
762 for (i = 0; i < 16; i++) {
763 channel[i].program = 0;
764 channel[i].bender = 8192;
765 channel[i].benderRange = 2;
767 channel[i].volume = 127;
768 channel[i].balance = 64;
769 channel[i].expression = 0;
770 channel[i].sustain = 0;
773 extra->drumSetMask = 1 << 9; /* channel 10 is normally drums, sometimes 16 also */
777 #define IS_DRUM_CHANNEL(_xtra, _chn) ((_xtra)->drumSetMask & (1 << (_chn)))
779 #endif /* HAVE_OSS */
781 /**************************************************************************
782 * modGetDevCaps [internal]
784 static DWORD modGetDevCaps(WORD wDevID, LPMIDIOUTCAPS16 lpCaps,
787 TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize);
788 if (wDevID == (WORD) MIDI_MAPPER) {
789 lpCaps->wMid = 0x00FF; /* Manufac ID */
790 lpCaps->wPid = 0x0001; /* Product ID */
791 lpCaps->vDriverVersion = 0x001; /* Product Version */
792 strcpy(lpCaps->szPname, "MIDI Mapper (not functional yet)");
793 /* FIXME Does it make any difference ? */
794 lpCaps->wTechnology = MOD_FMSYNTH;
795 lpCaps->wVoices = 14; /* FIXME */
796 lpCaps->wNotes = 14; /* FIXME */
797 /* FIXME Does it make any difference ? */
798 lpCaps->dwSupport = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME;
800 LPMIDIOUTCAPS16 tmplpCaps;
802 if (wDevID >= MODM_NUMDEVS) {
803 TRACE(midi, "MAX_MIDIOUTDRV reached !\n");
804 return MMSYSERR_BADDEVICEID;
806 /* FIXME There is a way to do it so easily, but I'm too
807 * sleepy to think and I want to test
810 tmplpCaps = midiOutDevices[wDevID];
811 lpCaps->wMid = tmplpCaps->wMid;
812 lpCaps->wPid = tmplpCaps->wPid;
813 lpCaps->vDriverVersion = tmplpCaps->vDriverVersion;
814 strcpy(lpCaps->szPname, tmplpCaps->szPname);
815 lpCaps->wTechnology = tmplpCaps->wTechnology;
816 lpCaps->wVoices = tmplpCaps->wVoices;
817 lpCaps->wNotes = tmplpCaps->wNotes;
818 lpCaps->dwSupport = tmplpCaps->dwSupport;
820 return MMSYSERR_NOERROR;
823 /**************************************************************************
826 static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
828 TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
829 if (lpDesc == NULL) {
830 WARN(midi, "Invalid Parameter !\n");
831 return MMSYSERR_INVALPARAM;
833 if (wDevID >= MAX_MIDIOUTDRV) {
834 TRACE(midi,"MAX_MIDIOUTDRV reached !\n");
835 return MMSYSERR_BADDEVICEID;
837 if (MidiOutDev[wDevID].midiDesc != 0) {
838 WARN(midi, "device already open !\n");
839 return MMSYSERR_ALLOCATED;
841 if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) {
842 WARN(midi, "bad dwFlags\n");
843 return MMSYSERR_INVALFLAG;
845 if (midiOutDevices[wDevID] == NULL) {
846 TRACE(midi, "un-allocated wDevID\n");
847 return MMSYSERR_BADDEVICEID;
851 MidiOutDev[wDevID].lpExtra = 0;
853 switch (midiOutDevices[wDevID]->wTechnology) {
856 void* extra = xmalloc(sizeof(struct sFMextra) +
857 sizeof(struct sVoice) *
858 (midiOutDevices[wDevID]->wVoices - 1));
861 WARN(midi, "can't alloc extra data !\n");
862 return MMSYSERR_NOMEM;
864 MidiOutDev[wDevID].lpExtra = extra;
865 if (midiOpenSeq() < 0) {
866 MidiOutDev[wDevID].lpExtra = 0;
868 return MMSYSERR_ERROR;
870 if (modFMLoad(wDevID) < 0) {
872 MidiOutDev[wDevID].lpExtra = 0;
874 return MMSYSERR_ERROR;
880 if (midiOpenSeq() < 0) {
881 return MMSYSERR_ALLOCATED;
885 WARN(midi,"Technology not supported (yet) %d !\n",
886 midiOutDevices[wDevID]->wTechnology);
887 return MMSYSERR_NOTENABLED;
891 int midi = open (MIDI_DEV, O_WRONLY, 0);
892 MidiOutDev[wDevID].unixdev = 0;
894 WARN(midi, "can't open !\n");
895 return MMSYSERR_ALLOCATED;
897 MidiOutDev[wDevID].unixdev = midi;
899 #endif /* HAVE_OSS */
901 MidiOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
902 switch (MidiOutDev[wDevID].wFlags) {
904 TRACE(midi,"CALLBACK_NULL !\n");
907 TRACE(midi, "CALLBACK_WINDOW !\n");
910 TRACE(midi, "CALLBACK_TASK !\n");
913 TRACE(midi, "CALLBACK_FUNCTION !\n");
916 MidiOutDev[wDevID].lpQueueHdr = NULL;
917 MidiOutDev[wDevID].dwTotalPlayed = 0;
918 MidiOutDev[wDevID].bufsize = 0x3FFF;
919 MidiOutDev[wDevID].midiDesc = lpDesc;
921 if (MIDI_NotifyClient(wDevID, MOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
922 WARN(midi,"can't notify client !\n");
923 return MMSYSERR_INVALPARAM;
925 TRACE(midi, "Succesful !\n");
926 return MMSYSERR_NOERROR;
930 /**************************************************************************
931 * modClose [internal]
933 static DWORD modClose(WORD wDevID)
935 int ret = MMSYSERR_NOERROR;
937 TRACE(midi, "(%04X);\n", wDevID);
939 if (MidiOutDev[wDevID].midiDesc == 0) {
940 WARN(midi, "device not opened !\n");
941 return MMSYSERR_ERROR;
943 /* FIXME: should test that no pending buffer is still in the queue for
947 if (midiSeqFD == -1) {
948 WARN(midi,"can't close !\n");
949 return MMSYSERR_ERROR;
952 switch (midiOutDevices[wDevID]->wTechnology) {
958 WARN(midi,"Technology not supported (yet) %d !\n",
959 midiOutDevices[wDevID]->wTechnology);
960 return MMSYSERR_NOTENABLED;
963 if (MidiOutDev[wDevID].lpExtra != 0) {
964 free(MidiOutDev[wDevID].lpExtra);
965 MidiOutDev[wDevID].lpExtra = 0;
968 if (MidiOutDev[wDevID].unixdev == 0) {
969 WARN(midi,"can't close !\n");
970 return MMSYSERR_NOTENABLED;
972 close(MidiOutDev[wDevID].unixdev);
973 MidiOutDev[wDevID].unixdev = 0;
974 #endif /* HAVE_OSS */
976 MidiOutDev[wDevID].bufsize = 0;
977 if (MIDI_NotifyClient(wDevID, MOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
978 WARN(midi,"can't notify client !\n");
979 ret = MMSYSERR_INVALPARAM;
981 MidiOutDev[wDevID].midiDesc = 0;
985 /**************************************************************************
988 static DWORD modData(WORD wDevID, DWORD dwParam)
990 WORD evt = LOBYTE(LOWORD(dwParam));
991 WORD d1 = HIBYTE(LOWORD(dwParam));
992 WORD d2 = LOBYTE(HIWORD(dwParam));
994 TRACE(midi, "(%04X, %08lX);\n", wDevID, dwParam);
997 if (midiSeqFD == -1) {
998 WARN(midi,"can't play !\n");
999 return MIDIERR_NODEVICE;
1001 switch (midiOutDevices[wDevID]->wTechnology) {
1004 * - chorus depth controller is not used
1007 sFMextra* extra = (sFMextra*)MidiOutDev[wDevID].lpExtra;
1008 sVoice* voice = extra->voice;
1009 sChannel* channel = extra->channel;
1010 int chn = (evt & 0x0F);
1013 switch (evt & 0xF0) {
1015 for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1016 /* don't stop sustained notes */
1017 if (voice[i].status == sVS_PLAYING && voice[i].channel == chn && voice[i].note == d1) {
1018 voice[i].status = sVS_UNUSED;
1019 SEQ_STOP_NOTE(wDevID, i, d1, d2);
1024 if (d2 == 0) { /* note off if velocity == 0 */
1025 for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1026 /* don't stop sustained notes */
1027 if (voice[i].status == sVS_PLAYING && voice[i].channel == chn && voice[i].note == d1) {
1028 voice[i].status = sVS_UNUSED;
1029 SEQ_STOP_NOTE(wDevID, i, d1, 64);
1034 /* finding out in this order :
1036 * - if replaying the same note on the same channel
1037 * - the older voice (LRU)
1039 for (i = nv = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1040 if (voice[i].status == sVS_UNUSED ||
1041 (voice[i].note == d1 && voice[i].channel == chn)) {
1045 if (voice[i].cntMark < voice[0].cntMark) {
1050 "playing on voice=%d, pgm=%d, pan=0x%02X, vol=0x%02X, "
1051 "bender=0x%02X, note=0x%02X, vel=0x%02X\n",
1052 nv, channel[chn].program,
1053 channel[chn].balance,
1054 channel[chn].volume,
1055 channel[chn].bender, d1, d2);
1057 SEQ_SET_PATCH(wDevID, nv, IS_DRUM_CHANNEL(extra, chn) ?
1058 (128 + d1) : channel[chn].program);
1059 SEQ_BENDER_RANGE(wDevID, nv, channel[chn].benderRange * 100);
1060 SEQ_BENDER(wDevID, nv, channel[chn].bender);
1061 SEQ_CONTROL(wDevID, nv, CTL_PAN, channel[chn].balance);
1062 SEQ_CONTROL(wDevID, nv, CTL_EXPRESSION, channel[chn].expression);
1064 /* FIXME: does not really seem to work on my SB card and
1065 * screws everything up... so lay it down
1067 SEQ_CONTROL(wDevID, nv, CTL_MAIN_VOLUME, channel[chn].volume);
1069 SEQ_START_NOTE(wDevID, nv, d1, d2);
1070 voice[nv].status = channel[chn].sustain ? sVS_SUSTAINED : sVS_PLAYING;
1071 voice[nv].note = d1;
1072 voice[nv].channel = chn;
1073 voice[nv].cntMark = extra->counter++;
1075 case MIDI_KEY_PRESSURE:
1076 for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1077 if (voice[i].status != sVS_UNUSED && voice[i].channel == chn && voice[i].note == d1) {
1078 SEQ_KEY_PRESSURE(wDevID, i, d1, d2);
1082 case MIDI_CTL_CHANGE:
1084 case CTL_BANK_SELECT: channel[chn].bank = d2; break;
1085 case CTL_MAIN_VOLUME: channel[chn].volume = d2; break;
1086 case CTL_PAN: channel[chn].balance = d2; break;
1087 case CTL_EXPRESSION: channel[chn].expression = d2; break;
1088 case CTL_SUSTAIN: channel[chn].sustain = d2;
1090 for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1091 if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) {
1092 voice[i].status = sVS_SUSTAINED;
1096 for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1097 if (voice[i].status == sVS_SUSTAINED && voice[i].channel == chn) {
1098 voice[i].status = sVS_UNUSED;
1099 SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64);
1104 case CTL_NONREG_PARM_NUM_LSB: channel[chn].nrgPmtLSB = d2; break;
1105 case CTL_NONREG_PARM_NUM_MSB: channel[chn].nrgPmtMSB = d2; break;
1106 case CTL_REGIST_PARM_NUM_LSB: channel[chn].regPmtLSB = d2; break;
1107 case CTL_REGIST_PARM_NUM_MSB: channel[chn].regPmtMSB = d2; break;
1109 case CTL_DATA_ENTRY:
1110 switch ((channel[chn].regPmtMSB << 8) | channel[chn].regPmtLSB) {
1112 if (channel[chn].benderRange != d2) {
1113 channel[chn].benderRange = d2;
1114 for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1115 if (voice[i].channel == chn) {
1116 SEQ_BENDER_RANGE(wDevID, i, channel[chn].benderRange);
1123 channel[chn].benderRange = 2;
1124 for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1125 if (voice[i].channel == chn) {
1126 SEQ_BENDER_RANGE(wDevID, i, channel[chn].benderRange);
1131 TRACE(midi, "Data entry: regPmt=0x%02x%02x, nrgPmt=0x%02x%02x with %x\n",
1132 channel[chn].regPmtMSB, channel[chn].regPmtLSB,
1133 channel[chn].nrgPmtMSB, channel[chn].nrgPmtLSB,
1139 case 0x78: /* all sounds off */
1140 /* FIXME: I don't know if I have to take care of the channel
1141 * for this control ?
1143 for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1144 if (voice[i].status != sVS_UNUSED && voice[i].channel == chn) {
1145 voice[i].status = sVS_UNUSED;
1146 SEQ_STOP_NOTE(wDevID, i, voice[i].note, 0);
1150 case 0x7B: /* all notes off */
1151 /* FIXME: I don't know if I have to take care of the channel
1152 * for this control ?
1154 for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1155 if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) {
1156 voice[i].status = sVS_UNUSED;
1157 SEQ_STOP_NOTE(wDevID, i, voice[i].note, 0);
1162 TRACE(midi, "Dropping MIDI control event 0x%02x(%02x) on channel %d\n",
1167 case MIDI_PGM_CHANGE:
1168 channel[chn].program = d1;
1170 case MIDI_CHN_PRESSURE:
1171 for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1172 if (voice[i].status != sVS_UNUSED && voice[i].channel == chn) {
1173 SEQ_KEY_PRESSURE(wDevID, i, voice[i].note, d1);
1177 case MIDI_PITCH_BEND:
1178 channel[chn].bender = (d2 << 7) + d1;
1179 for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1180 if (voice[i].channel == chn) {
1181 SEQ_BENDER(wDevID, i, channel[chn].bender);
1185 case MIDI_SYSTEM_PREFIX:
1186 switch (evt & 0x0F) {
1187 case 0x0F: /* Reset */
1191 WARN(midi, "Unsupported (yet) system event %02x\n", evt & 0x0F);
1195 WARN(midi, "Internal error, shouldn't happen (event=%08x)\n", evt & 0xF0);
1196 return MMSYSERR_NOTENABLED;
1202 int dev = wDevID - MODM_NUMFMSYNTHDEVS;
1204 WARN(midi, "Internal error on devID (%u) !\n", wDevID);
1205 return MIDIERR_NODEVICE;
1208 switch (evt & 0xF0) {
1211 case MIDI_KEY_PRESSURE:
1212 case MIDI_CTL_CHANGE:
1213 case MIDI_PITCH_BEND:
1214 SEQ_MIDIOUT(dev, evt);
1215 SEQ_MIDIOUT(dev, d1);
1216 SEQ_MIDIOUT(dev, d2);
1218 case MIDI_PGM_CHANGE:
1219 case MIDI_CHN_PRESSURE:
1220 SEQ_MIDIOUT(dev, evt);
1221 SEQ_MIDIOUT(dev, d1);
1223 case MIDI_SYSTEM_PREFIX:
1224 switch (evt & 0x0F) {
1225 case 0x00: /* System Exclusive, don't do it on modData,
1226 * should require modLongData*/
1227 case 0x01: /* Undefined */
1228 case 0x04: /* Undefined. */
1229 case 0x05: /* Undefined. */
1230 case 0x07: /* End of Exclusive. */
1231 case 0x09: /* Undefined. */
1232 case 0x0D: /* Undefined. */
1234 case 0x06: /* Tune Request */
1235 case 0x08: /* Timing Clock. */
1236 case 0x0A: /* Start. */
1237 case 0x0B: /* Continue */
1238 case 0x0C: /* Stop */
1239 case 0x0E: /* Active Sensing. */
1240 SEQ_MIDIOUT(dev, evt);
1242 case 0x0F: /* Reset */
1243 /* SEQ_MIDIOUT(dev, evt);
1244 this other way may be better */
1245 SEQ_MIDIOUT(dev, MIDI_SYSTEM_PREFIX);
1246 SEQ_MIDIOUT(dev, 0x7e);
1247 SEQ_MIDIOUT(dev, 0x7f);
1248 SEQ_MIDIOUT(dev, 0x09);
1249 SEQ_MIDIOUT(dev, 0x01);
1250 SEQ_MIDIOUT(dev, 0xf7);
1252 case 0x03: /* Song Select. */
1253 SEQ_MIDIOUT(dev, evt);
1254 SEQ_MIDIOUT(dev, d1);
1255 case 0x02: /* Song Position Pointer. */
1256 SEQ_MIDIOUT(dev, evt);
1257 SEQ_MIDIOUT(dev, d1);
1258 SEQ_MIDIOUT(dev, d2);
1265 WARN(midi, "Technology not supported (yet) %d !\n",
1266 midiOutDevices[wDevID]->wTechnology);
1267 return MMSYSERR_NOTENABLED;
1272 if (MidiOutDev[wDevID].unixdev == 0) {
1273 WARN(midi,"can't play !\n");
1274 return MIDIERR_NODEVICE;
1277 WORD event = LOWORD(dwParam);
1278 if (write (MidiOutDev[wDevID].unixdev,
1279 &event, sizeof(event)) != sizeof(WORD)) {
1280 WARN(midi, "error writting unixdev !\n");
1283 #endif /* HAVE_OSS */
1284 return MMSYSERR_NOERROR;
1287 /**************************************************************************
1288 * modLongData [internal]
1290 static DWORD modLongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
1294 TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
1297 if (midiSeqFD == -1) {
1298 WARN(midi,"can't play !\n");
1299 return MIDIERR_NODEVICE;
1301 #else /* HAVE_OSS */
1302 if (MidiOutDev[wDevID].unixdev == 0) {
1303 WARN(midi,"can't play !\n");
1304 return MIDIERR_NODEVICE;
1306 #endif /* HAVE_OSS */
1308 if (lpMidiHdr->lpData == NULL)
1309 return MIDIERR_UNPREPARED;
1310 if (!(lpMidiHdr->dwFlags & MHDR_PREPARED))
1311 return MIDIERR_UNPREPARED;
1312 if (lpMidiHdr->dwFlags & MHDR_INQUEUE)
1313 return MIDIERR_STILLPLAYING;
1314 lpMidiHdr->dwFlags &= ~MHDR_DONE;
1315 lpMidiHdr->dwFlags |= MHDR_INQUEUE;
1317 TRACE(midi, "dwBytesRecorded %lu !\n", lpMidiHdr->dwBytesRecorded);
1318 TRACE(midi, " %02X %02X %02X %02X\n",
1319 ((LPBYTE)(lpMidiHdr->reserved))[0],
1320 ((LPBYTE)(lpMidiHdr->reserved))[1],
1321 ((LPBYTE)(lpMidiHdr->reserved))[2],
1322 ((LPBYTE)(lpMidiHdr->reserved))[3]);
1324 switch (midiOutDevices[wDevID]->wTechnology) {
1326 /* FIXME: I don't think there is much to do here */
1329 if (((LPBYTE)lpMidiHdr->reserved)[0] != 0xF0) {
1330 /* Send end of System Exclusive */
1331 SEQ_MIDIOUT(wDevID - MODM_NUMFMSYNTHDEVS, 0xF0);
1332 TRACE(midi, "Adding missing 0xF0 marker at the begining of "
1333 "system exclusive byte stream\n");
1335 for (count = 0; count < lpMidiHdr->dwBytesRecorded; count++) {
1336 SEQ_MIDIOUT(wDevID - MODM_NUMFMSYNTHDEVS,
1337 ((LPBYTE)lpMidiHdr->reserved)[count]);
1339 if (((LPBYTE)lpMidiHdr->reserved)[count - 1] != 0xF7) {
1340 /* Send end of System Exclusive */
1341 SEQ_MIDIOUT(wDevID - MODM_NUMFMSYNTHDEVS, 0xF7);
1342 TRACE(midi, "Adding missing 0xF7 marker at the end of "
1343 "system exclusive byte stream\n");
1348 WARN(midi, "Technology not supported (yet) %d !\n",
1349 midiOutDevices[wDevID]->wTechnology);
1350 return MMSYSERR_NOTENABLED;
1352 #else /* HAVE_OSS */
1354 LPWORD ptr = (LPWORD)lpMidiHdr->reserved;
1357 for (count = 0; count < lpMidiHdr->dwBytesRecorded; count++) {
1358 if (write(MidiOutDev[wDevID].unixdev,
1359 ptr, sizeof(WORD)) != sizeof(WORD))
1365 TRACE(midi, "after write count = %d\n",count);
1366 if (count != lpMidiHdr->dwBytesRecorded) {
1367 WARN(midi, "error writting unixdev #%d ! (%d != %ld)\n",
1368 MidiOutDev[wDevID].unixdev, count,
1369 lpMidiHdr->dwBytesRecorded);
1370 TRACE(midi, "\terrno = %d error = %s\n",en,strerror(en));
1371 return MMSYSERR_NOTENABLED;
1374 #endif /* HAVE_OSS */
1376 lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1377 lpMidiHdr->dwFlags |= MHDR_DONE;
1378 if (MIDI_NotifyClient(wDevID, MOM_DONE, (DWORD)lpMidiHdr, 0L) != MMSYSERR_NOERROR) {
1379 WARN(midi,"can't notify client !\n");
1380 return MMSYSERR_INVALPARAM;
1382 return MMSYSERR_NOERROR;
1385 /**************************************************************************
1386 * modPrepare [internal]
1388 static DWORD modPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
1390 TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
1393 if (midiSeqFD == -1) {
1394 WARN(midi,"can't prepare !\n");
1395 return MMSYSERR_NOTENABLED;
1397 #else /* HAVE_OSS */
1398 if (MidiOutDev[wDevID].unixdev == 0) {
1399 WARN(midi,"can't prepare !\n");
1400 return MMSYSERR_NOTENABLED;
1402 #endif /* HAVE_OSS */
1403 if (dwSize != sizeof(MIDIHDR) || lpMidiHdr == 0 ||
1404 lpMidiHdr->lpData == 0 || lpMidiHdr->dwFlags != 0 ||
1405 lpMidiHdr->dwBufferLength >= 0x10000ul)
1406 return MMSYSERR_INVALPARAM;
1408 lpMidiHdr->lpNext = 0;
1409 lpMidiHdr->dwFlags |= MHDR_PREPARED;
1410 lpMidiHdr->dwFlags &= ~MHDR_DONE;
1411 return MMSYSERR_NOERROR;
1414 /**************************************************************************
1415 * modUnprepare [internal]
1417 static DWORD modUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
1419 TRACE(midi, "(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
1422 if (midiSeqFD == -1) {
1423 WARN(midi,"can't unprepare !\n");
1424 return MMSYSERR_NOTENABLED;
1426 #else /* HAVE_OSS */
1427 if (MidiOutDev[wDevID].unixdev == 0) {
1428 WARN(midi,"can't unprepare !\n");
1429 return MMSYSERR_NOTENABLED;
1431 #endif /* HAVE_OSS */
1432 if (dwSize != sizeof(MIDIHDR) || lpMidiHdr == 0)
1433 return MMSYSERR_INVALPARAM;
1434 if (lpMidiHdr->dwFlags & MHDR_INQUEUE)
1435 return MIDIERR_STILLPLAYING;
1436 lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
1437 return MMSYSERR_NOERROR;
1440 /**************************************************************************
1441 * modReset [internal]
1443 static DWORD modReset(WORD wDevID)
1445 TRACE(midi, "(%04X);\n", wDevID);
1446 /* FIXME: this function should :
1447 * turn off every note, remove sustain on all channels
1448 * remove any pending buffers
1450 return MMSYSERR_NOTENABLED;
1454 /*======================================================================*
1455 * MIDI entry points *
1456 *======================================================================*/
1458 /**************************************************************************
1459 * midMessage [sample driver]
1461 DWORD WINAPI midMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1462 DWORD dwParam1, DWORD dwParam2)
1464 TRACE(midi, "(%04X, %04X, %08lX, %08lX, %08lX);\n",
1465 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1467 #ifdef SNDCTL_MIDI_INFO
1469 return midOpen(wDevID,(LPMIDIOPENDESC)dwParam1, dwParam2);
1471 return midClose(wDevID);
1472 case MIDM_ADDBUFFER:
1473 return midAddBuffer(wDevID,(LPMIDIHDR)dwParam1, dwParam2);
1475 return midPrepare(wDevID,(LPMIDIHDR)dwParam1, dwParam2);
1476 case MIDM_UNPREPARE:
1477 return midUnprepare(wDevID,(LPMIDIHDR)dwParam1, dwParam2);
1478 case MIDM_GETDEVCAPS:
1479 return midGetDevCaps(wDevID,(LPMIDIINCAPS16)dwParam1,dwParam2);
1480 case MIDM_GETNUMDEVS:
1481 return MIDM_NUMDEVS;
1483 return midReset(wDevID);
1485 return midStart(wDevID);
1487 return midStop(wDevID);
1490 TRACE(midi, "Unsupported message\n");
1492 return MMSYSERR_NOTSUPPORTED;
1495 /**************************************************************************
1496 * modMessage [sample driver]
1498 DWORD WINAPI modMessage(WORD wDevID, WORD wMsg, DWORD dwUser,
1499 DWORD dwParam1, DWORD dwParam2)
1501 TRACE(midi, "(%04X, %04X, %08lX, %08lX, %08lX);\n",
1502 wDevID, wMsg, dwUser, dwParam1, dwParam2);
1505 #ifdef SNDCTL_MIDI_INFO
1507 return modOpen(wDevID, (LPMIDIOPENDESC)dwParam1, dwParam2);
1509 return modClose(wDevID);
1511 return modData(wDevID, dwParam1);
1513 return modLongData(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1515 return modPrepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1516 case MODM_UNPREPARE:
1517 return modUnprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1518 case MODM_GETDEVCAPS:
1519 return modGetDevCaps(wDevID,(LPMIDIOUTCAPS16)dwParam1,dwParam2);
1520 case MODM_GETNUMDEVS:
1521 return MODM_NUMDEVS;
1522 case MODM_GETVOLUME:
1524 case MODM_SETVOLUME:
1527 return modReset(wDevID);
1530 TRACE(midi, "Unsupported message\n");
1532 return MMSYSERR_NOTSUPPORTED;
1535 /**************************************************************************
1536 * MIDI_DriverProc32 [sample driver]
1538 LONG MIDI_DriverProc32(DWORD dwDevID, HDRVR16 hDriv, DWORD wMsg,
1539 DWORD dwParam1, DWORD dwParam2)
1542 case DRV_LOAD: return 1;
1543 case DRV_FREE: return 1;
1544 case DRV_OPEN: return 1;
1545 case DRV_CLOSE: return 1;
1546 case DRV_ENABLE: return 1;
1547 case DRV_DISABLE: return 1;
1548 case DRV_QUERYCONFIGURE: return 1;
1549 case DRV_CONFIGURE: MessageBox32A(0, "Sample Midi Linux Driver !", "MMLinux Driver", MB_OK); return 1;
1550 case DRV_INSTALL: return DRVCNF_RESTART;
1551 case DRV_REMOVE: return DRVCNF_RESTART;
1553 TRACE(midi, "Sending msg=%lu to default driver proc\n", wMsg);
1554 return DefDriverProc16(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1558 /**************************************************************************
1559 * MIDI_DriverProc16 [sample driver]
1561 LONG MIDI_DriverProc16(DWORD dwDevID, HDRVR16 hDriv, WORD wMsg,
1562 DWORD dwParam1, DWORD dwParam2)
1565 case DRV_LOAD: return 1;
1566 case DRV_FREE: return 1;
1567 case DRV_OPEN: return 1;
1568 case DRV_CLOSE: return 1;
1569 case DRV_ENABLE: return 1;
1570 case DRV_DISABLE: return 1;
1571 case DRV_QUERYCONFIGURE: return 1;
1572 case DRV_CONFIGURE: MessageBox32A(0, "Sample Midi Linux Driver !", "MMLinux Driver", MB_OK); return 1;
1573 case DRV_INSTALL: return DRVCNF_RESTART;
1574 case DRV_REMOVE: return DRVCNF_RESTART;
1576 TRACE(midi, "Sending msg=%u to default driver proc\n", wMsg);
1577 return DefDriverProc32(dwDevID, hDriv, wMsg, dwParam1, dwParam2);
1581 /*-----------------------------------------------------------------------*/