Added regedit unit test, a couple minor changes to regedit.
[wine] / dlls / winmm / wineoss / midi.c
1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
2
3 /*
4  * Sample MIDI Wine Driver for Open Sound System (basically Linux)
5  *
6  * Copyright 1994       Martin Ayotte
7  * Copyright 1998       Luiz Otavio L. Zorzella (init procedures)
8  * Copyright 1998/1999  Eric POUECH :
9  *              98/7    changes for making this MIDI driver work on OSS
10  *                      current support is limited to MIDI ports of OSS systems
11  *              98/9    rewriting MCI code for MIDI
12  *              98/11   splitted in midi.c and mcimidi.c
13  *
14  * This library is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU Lesser General Public
16  * License as published by the Free Software Foundation; either
17  * version 2.1 of the License, or (at your option) any later version.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27  */
28
29 #include "config.h"
30
31 #include <string.h>
32 #include <unistd.h>
33 #include <fcntl.h>
34 #ifdef HAVE_SYS_IOCTL_H
35 # include <sys/ioctl.h>
36 #endif
37
38 #include "windef.h"
39 #include "winbase.h"
40 #include "wingdi.h"
41 #include "winuser.h"
42 #include "mmddk.h"
43 #include "oss.h"
44 #include "wine/debug.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(midi);
47
48 #ifdef HAVE_OSS_MIDI
49
50 #define MIDI_SEQ "/dev/sequencer"
51
52 typedef struct {
53     int                 state;
54     DWORD               bufsize;
55     MIDIOPENDESC        midiDesc;
56     WORD                wFlags;
57     LPMIDIHDR           lpQueueHdr;
58     DWORD               dwTotalPlayed;
59     unsigned char       incoming[3];
60     unsigned char       incPrev;
61     char                incLen;
62     DWORD               startTime;
63 } WINE_MIDIIN;
64
65 typedef struct {
66     int                 state;
67     DWORD               bufsize;
68     MIDIOPENDESC        midiDesc;
69     WORD                wFlags;
70     LPMIDIHDR           lpQueueHdr;
71     DWORD               dwTotalPlayed;
72     void*               lpExtra;                /* according to port type (MIDI, FM...), extra data when needed */
73 } WINE_MIDIOUT;
74
75 static WINE_MIDIIN      MidiInDev [MAX_MIDIINDRV ];
76 static WINE_MIDIOUT     MidiOutDev[MAX_MIDIOUTDRV];
77
78 /* this is the total number of MIDI out devices found */
79 static  int             MODM_NUMDEVS = 0;
80 /* this is the number of FM synthetizers (index from 0 to
81    NUMFMSYNTHDEVS - 1) */
82 static  int             MODM_NUMFMSYNTHDEVS = 0;
83 /* this is the number of Midi ports (index from NUMFMSYNTHDEVS to
84    NUMFMSYNTHDEVS + NUMMIDIDEVS - 1) */
85 static  int             MODM_NUMMIDIDEVS = 0;
86
87 /* this is the total number of MIDI out devices found */
88 static  int             MIDM_NUMDEVS = 0;
89
90 static  int             midiSeqFD = -1;
91 static  int             numOpenMidiSeq = 0;
92 static  UINT            midiInTimerID = 0;
93 static  int             numStartedMidiIn = 0;
94
95 /* this structure holds pointers with information for each MIDI
96  * out device found.
97  */
98 static  LPMIDIOUTCAPSA  midiOutDevices[MAX_MIDIOUTDRV];
99
100 /* this structure holds pointers with information for each MIDI
101  * in device found.
102  */
103 static  LPMIDIINCAPSA   midiInDevices [MAX_MIDIINDRV];
104
105 /*
106  * FIXME : all tests on device ID for midXXX and modYYY are made against
107  * MAX_MIDIxxDRV (when they are made) but should be done against the actual
108  * number of midi devices found...
109  */
110
111 /*======================================================================*
112  *                  Low level MIDI implementation                       *
113  *======================================================================*/
114
115 static int midiOpenSeq(void);
116 static int midiCloseSeq(void);
117
118 /**************************************************************************
119  *                      unixToWindowsDeviceType                 [internal]
120  *
121  * return the Windows equivalent to a Unix Device Type
122  *
123  */
124 static  int     MIDI_UnixToWindowsDeviceType(int type)
125 {
126     /* MOD_MIDIPORT     output port
127      * MOD_SYNTH        generic internal synth
128      * MOD_SQSYNTH      square wave internal synth
129      * MOD_FMSYNTH      FM internal synth
130      * MOD_MAPPER       MIDI mapper
131      */
132
133     /* FIXME Is this really the correct equivalence from UNIX to
134        Windows Sound type */
135
136     switch (type) {
137     case SYNTH_TYPE_FM:     return MOD_FMSYNTH;
138     case SYNTH_TYPE_SAMPLE: return MOD_SYNTH;
139     case SYNTH_TYPE_MIDI:   return MOD_MIDIPORT;
140     default:
141         ERR("Cannot determine the type of this midi device. "
142             "Assuming FM Synth\n");
143         return MOD_FMSYNTH;
144     }
145     return MOD_FMSYNTH;
146 }
147
148 /**************************************************************************
149  *                      OSS_MidiInit                            [internal]
150  *
151  * Initializes the MIDI devices information variables
152  */
153 BOOL OSS_MidiInit(void)
154 {
155     int                 i, status, numsynthdevs = 255, nummididevs = 255;
156     struct synth_info   sinfo;
157     struct midi_info    minfo;
158     static      BOOL    bInitDone = FALSE;
159
160     if (bInitDone)
161         return TRUE;
162
163     TRACE("Initializing the MIDI variables.\n");
164     bInitDone = TRUE;
165
166     /* try to open device */
167     if (midiOpenSeq() == -1) {
168         return TRUE;
169     }
170
171     /* find how many Synth devices are there in the system */
172     status = ioctl(midiSeqFD, SNDCTL_SEQ_NRSYNTHS, &numsynthdevs);
173
174     if (status == -1) {
175         ERR("ioctl for nr synth failed.\n");
176         midiCloseSeq();
177         return TRUE;
178     }
179
180     if (numsynthdevs > MAX_MIDIOUTDRV) {
181         ERR("MAX_MIDIOUTDRV (%d) was enough for the number of devices (%d). "
182             "Some FM devices will not be available.\n",MAX_MIDIOUTDRV,numsynthdevs);
183         numsynthdevs = MAX_MIDIOUTDRV;
184     }
185
186     for (i = 0; i < numsynthdevs; i++) {
187         LPMIDIOUTCAPSA  tmplpCaps;
188
189         sinfo.device = i;
190         status = ioctl(midiSeqFD, SNDCTL_SYNTH_INFO, &sinfo);
191         if (status == -1) {
192             ERR("ioctl for synth info failed.\n");
193             midiCloseSeq();
194             return TRUE;
195         }
196
197         tmplpCaps = HeapAlloc(GetProcessHeap(), 0, sizeof(MIDIOUTCAPSA));
198         if (!tmplpCaps)
199             break;
200         /* We also have the information sinfo.synth_subtype, not used here
201          */
202
203         /* Manufac ID. We do not have access to this with soundcard.h
204          * Does not seem to be a problem, because in mmsystem.h only
205          * Microsoft's ID is listed.
206          */
207         tmplpCaps->wMid = 0x00FF;
208         tmplpCaps->wPid = 0x0001;       /* FIXME Product ID  */
209         /* Product Version. We simply say "1" */
210         tmplpCaps->vDriverVersion = 0x001;
211         strcpy(tmplpCaps->szPname, sinfo.name);
212
213         tmplpCaps->wTechnology = MIDI_UnixToWindowsDeviceType(sinfo.synth_type);
214         tmplpCaps->wVoices     = sinfo.nr_voices;
215
216         /* FIXME Is it possible to know the maximum
217          * number of simultaneous notes of a soundcard ?
218          * I believe we don't have this information, but
219          * it's probably equal or more than wVoices
220          */
221         tmplpCaps->wNotes      = sinfo.nr_voices;
222         tmplpCaps->wChannelMask= 0xFFFF;
223
224         /* FIXME Do we have this information?
225          * Assuming the soundcards can handle
226          * MIDICAPS_VOLUME and MIDICAPS_LRVOLUME but
227          * not MIDICAPS_CACHE.
228          */
229         tmplpCaps->dwSupport   = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME;
230
231         midiOutDevices[i] = tmplpCaps;
232
233         if (sinfo.capabilities & SYNTH_CAP_INPUT) {
234             FIXME("Synthesizer support MIDI in. Not supported yet (please report)\n");
235         }
236
237         TRACE("SynthOut[%d]\tname='%s' techn=%d voices=%d notes=%d chnMsk=%04x support=%ld\n"
238               "\tOSS info: synth subtype=%d capa=%lx\n",
239               i, tmplpCaps->szPname, tmplpCaps->wTechnology, tmplpCaps->wVoices,
240               tmplpCaps->wNotes, tmplpCaps->wChannelMask, tmplpCaps->dwSupport,
241               sinfo.synth_subtype, (long)sinfo.capabilities);
242     }
243
244     /* find how many MIDI devices are there in the system */
245     status = ioctl(midiSeqFD, SNDCTL_SEQ_NRMIDIS, &nummididevs);
246     if (status == -1) {
247         ERR("ioctl on nr midi failed.\n");
248         midiCloseSeq();
249         return TRUE;
250     }
251
252     /* FIXME: the two restrictions below could be loosen in some cases */
253     if (numsynthdevs + nummididevs > MAX_MIDIOUTDRV) {
254         ERR("MAX_MIDIOUTDRV was not enough for the number of devices. "
255             "Some MIDI devices will not be available.\n");
256         nummididevs = MAX_MIDIOUTDRV - numsynthdevs;
257     }
258
259     if (nummididevs > MAX_MIDIINDRV) {
260         ERR("MAX_MIDIINDRV (%d) was not enough for the number of devices (%d). "
261             "Some MIDI devices will not be available.\n",MAX_MIDIINDRV,nummididevs);
262         nummididevs = MAX_MIDIINDRV;
263     }
264
265     for (i = 0; i < nummididevs; i++) {
266         LPMIDIOUTCAPSA  tmplpOutCaps;
267         LPMIDIINCAPSA   tmplpInCaps;
268
269         minfo.device = i;
270         status = ioctl(midiSeqFD, SNDCTL_MIDI_INFO, &minfo);
271         if (status == -1) {
272             ERR("ioctl on midi info for device %d failed.\n", i);
273             midiCloseSeq();
274             return TRUE;
275         }
276
277         tmplpOutCaps = HeapAlloc(GetProcessHeap(), 0, sizeof(MIDIOUTCAPSA));
278         if (!tmplpOutCaps)
279             break;
280         /* This whole part is somewhat obscure to me. I'll keep trying to dig
281            info about it. If you happen to know, please tell us. The very
282            descritive minfo.dev_type was not used here.
283         */
284         /* Manufac ID. We do not have access to this with soundcard.h
285            Does not seem to be a problem, because in mmsystem.h only
286            Microsoft's ID is listed */
287         tmplpOutCaps->wMid = 0x00FF;
288         tmplpOutCaps->wPid = 0x0001;    /* FIXME Product ID */
289         /* Product Version. We simply say "1" */
290         tmplpOutCaps->vDriverVersion = 0x001;
291         strcpy(tmplpOutCaps->szPname, minfo.name);
292
293         tmplpOutCaps->wTechnology = MOD_MIDIPORT; /* FIXME Is this right? */
294         /* Does it make any difference? */
295         tmplpOutCaps->wVoices     = 16;
296         /* Does it make any difference? */
297         tmplpOutCaps->wNotes      = 16;
298         tmplpOutCaps->wChannelMask= 0xFFFF;
299
300         /* FIXME Does it make any difference? */
301         tmplpOutCaps->dwSupport   = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME;
302
303         midiOutDevices[numsynthdevs + i] = tmplpOutCaps;
304
305         tmplpInCaps = HeapAlloc(GetProcessHeap(), 0, sizeof(MIDIINCAPSA));
306         if (!tmplpInCaps)
307             break;
308         /* This whole part is somewhat obscure to me. I'll keep trying to dig
309            info about it. If you happen to know, please tell us. The very
310            descritive minfo.dev_type was not used here.
311         */
312         /* Manufac ID. We do not have access to this with soundcard.h
313            Does not seem to be a problem, because in mmsystem.h only
314            Microsoft's ID is listed */
315         tmplpInCaps->wMid = 0x00FF;
316         tmplpInCaps->wPid = 0x0001;     /* FIXME Product ID */
317         /* Product Version. We simply say "1" */
318         tmplpInCaps->vDriverVersion = 0x001;
319         strcpy(tmplpInCaps->szPname, minfo.name);
320
321         /* FIXME : could we get better information than that ? */
322         tmplpInCaps->dwSupport   = MIDICAPS_VOLUME|MIDICAPS_LRVOLUME;
323
324         midiInDevices[i] = tmplpInCaps;
325
326         TRACE("MidiOut[%d]\tname='%s' techn=%d voices=%d notes=%d chnMsk=%04x support=%ld\n"
327               "MidiIn [%d]\tname='%s' support=%ld\n"
328               "\tOSS info: midi dev-type=%d, capa=%lx\n",
329               i, tmplpOutCaps->szPname, tmplpOutCaps->wTechnology,
330               tmplpOutCaps->wVoices, tmplpOutCaps->wNotes,
331               tmplpOutCaps->wChannelMask, tmplpOutCaps->dwSupport,
332               i, tmplpInCaps->szPname, tmplpInCaps->dwSupport,
333               minfo.dev_type, (long)minfo.capabilities);
334     }
335
336     /* windows does not seem to differentiate Synth from MIDI devices */
337     MODM_NUMFMSYNTHDEVS = numsynthdevs;
338     MODM_NUMMIDIDEVS    = nummididevs;
339     MODM_NUMDEVS        = numsynthdevs + nummididevs;
340
341     MIDM_NUMDEVS        = nummididevs;
342
343     /* close file and exit */
344     midiCloseSeq();
345
346     return TRUE;
347 }
348
349 /**************************************************************************
350  *                      MIDI_NotifyClient                       [internal]
351  */
352 static DWORD MIDI_NotifyClient(UINT wDevID, WORD wMsg,
353                                DWORD dwParam1, DWORD dwParam2)
354 {
355     DWORD               dwCallBack;
356     UINT                uFlags;
357     HANDLE              hDev;
358     DWORD               dwInstance;
359
360     TRACE("wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",
361           wDevID, wMsg, dwParam1, dwParam2);
362
363     switch (wMsg) {
364     case MOM_OPEN:
365     case MOM_CLOSE:
366     case MOM_DONE:
367         if (wDevID > MAX_MIDIOUTDRV)
368             return MCIERR_INTERNAL;
369
370         dwCallBack = MidiOutDev[wDevID].midiDesc.dwCallback;
371         uFlags = MidiOutDev[wDevID].wFlags;
372         hDev = MidiOutDev[wDevID].midiDesc.hMidi;
373         dwInstance = MidiOutDev[wDevID].midiDesc.dwInstance;
374         break;
375
376     case MIM_OPEN:
377     case MIM_CLOSE:
378     case MIM_DATA:
379     case MIM_ERROR:
380         if (wDevID > MAX_MIDIINDRV)
381             return MCIERR_INTERNAL;
382
383         dwCallBack = MidiInDev[wDevID].midiDesc.dwCallback;
384         uFlags = MidiInDev[wDevID].wFlags;
385         hDev = MidiInDev[wDevID].midiDesc.hMidi;
386         dwInstance = MidiInDev[wDevID].midiDesc.dwInstance;
387         break;
388     default:
389         WARN("Unsupported MSW-MIDI message %u\n", wMsg);
390         return MCIERR_INTERNAL;
391     }
392
393     return DriverCallback(dwCallBack, uFlags, hDev, wMsg, dwInstance, dwParam1, dwParam2) ?
394         0 : MCIERR_INTERNAL;
395 }
396
397 static int midi_warn = 1;
398 /**************************************************************************
399  *                      midiOpenSeq                             [internal]
400  */
401 static int midiOpenSeq(void)
402 {
403     if (numOpenMidiSeq == 0) {
404         midiSeqFD = open(MIDI_SEQ, O_RDWR, 0);
405         if (midiSeqFD == -1) {
406             if (midi_warn)
407             {
408                 WARN("Can't open MIDI device '%s' ! (%s). If your "
409                         "program needs this (probably not): %s\n",
410                         MIDI_SEQ, strerror(errno),
411                         errno == ENOENT ?
412                         "create it ! (\"man MAKEDEV\" ?)" :
413                         errno == ENODEV ?
414                         "load MIDI sequencer kernel driver !" :
415                         errno == EACCES ?
416                         "grant access ! (\"man chmod\")" : ""
417                 );
418             }
419             midi_warn = 0;
420             return -1;
421         }
422         if (fcntl(midiSeqFD, F_SETFL, O_NONBLOCK) < 0) {
423             WARN("can't set sequencer fd to non-blocking, errno %d (%s)\n", errno, strerror(errno));
424             close(midiSeqFD);
425             midiSeqFD = -1;
426             return -1;
427         }
428         fcntl(midiSeqFD, F_SETFD, 1); /* set close on exec flag */
429         ioctl(midiSeqFD, SNDCTL_SEQ_RESET);
430     }
431     numOpenMidiSeq++;
432     return 0;
433 }
434
435 /**************************************************************************
436  *                      midiCloseSeq                            [internal]
437  */
438 static int midiCloseSeq(void)
439 {
440     if (--numOpenMidiSeq == 0) {
441         close(midiSeqFD);
442         midiSeqFD = -1;
443     }
444     return 0;
445 }
446
447 /* FIXME: this is a bad idea, it's even not static... */
448 SEQ_DEFINEBUF(1024);
449
450 /* FIXME: this is not reentrant, not static - because of global variable
451  * _seqbuf and al.
452  */
453 /**************************************************************************
454  *                      seqbuf_dump                             [internal]
455  */
456 void seqbuf_dump(void)
457 {
458     if (_seqbufptr) {
459         if (write(midiSeqFD, _seqbuf, _seqbufptr) == -1) {
460             WARN("Can't write data to sequencer %d, errno %d (%s)!\n",
461                  midiSeqFD, errno, strerror(errno));
462         }
463         /* FIXME:
464          *      in any case buffer is lost so that if many errors occur the buffer
465          * will not overrun
466          */
467         _seqbufptr = 0;
468     }
469 }
470
471 static void midReceiveChar(WORD wDevID, unsigned char value, DWORD dwTime)
472 {
473     DWORD               toSend = 0;
474
475     TRACE("Adding %02xh to %d[%d]\n", value, wDevID, MidiInDev[wDevID].incLen);
476
477     if (wDevID >= MAX_MIDIINDRV) {
478         WARN("bad devID\n");
479         return;
480     }
481     if (MidiInDev[wDevID].state == 0) {
482         TRACE("input not started, thrown away\n");
483         return;
484     }
485
486     if (MidiInDev[wDevID].state & 2) { /* system exclusive */
487         LPMIDIHDR       lpMidiHdr = MidiInDev[wDevID].lpQueueHdr;
488         WORD            sbfb = FALSE;
489
490         if (lpMidiHdr) {
491             LPBYTE      lpData = lpMidiHdr->lpData;
492
493             lpData[lpMidiHdr->dwBytesRecorded++] = value;
494             if (lpMidiHdr->dwBytesRecorded == lpMidiHdr->dwBufferLength) {
495                 sbfb = TRUE;
496             }
497         }
498         if (value == 0xF7) { /* then end */
499             MidiInDev[wDevID].state &= ~2;
500             sbfb = TRUE;
501         }
502         if (sbfb && lpMidiHdr != NULL) {
503             lpMidiHdr = MidiInDev[wDevID].lpQueueHdr;
504             lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
505             lpMidiHdr->dwFlags |= MHDR_DONE;
506             MidiInDev[wDevID].lpQueueHdr = (LPMIDIHDR)lpMidiHdr->lpNext;
507             if (MIDI_NotifyClient(wDevID, MIM_LONGDATA, (DWORD)lpMidiHdr, dwTime) != MMSYSERR_NOERROR) {
508                 WARN("Couldn't notify client\n");
509             }
510         }
511         return;
512     }
513
514 #define IS_CMD(_x)      (((_x) & 0x80) == 0x80)
515 #define IS_SYS_CMD(_x)  (((_x) & 0xF0) == 0xF0)
516
517     if (!IS_CMD(value) && MidiInDev[wDevID].incLen == 0) { /* try to reuse old cmd */
518         if (IS_CMD(MidiInDev[wDevID].incPrev) && !IS_SYS_CMD(MidiInDev[wDevID].incPrev)) {
519             MidiInDev[wDevID].incoming[0] = MidiInDev[wDevID].incPrev;
520             MidiInDev[wDevID].incLen = 1;
521             TRACE("Reusing old command %02xh\n", MidiInDev[wDevID].incPrev);
522         } else {
523             FIXME("error for midi-in, should generate MIM_ERROR notification:"
524                   " prev=%02Xh, incLen=%02Xh\n",
525                   MidiInDev[wDevID].incPrev, MidiInDev[wDevID].incLen);
526             return;
527         }
528     }
529     MidiInDev[wDevID].incoming[(int)(MidiInDev[wDevID].incLen++)] = value;
530     if (MidiInDev[wDevID].incLen == 1 && !IS_SYS_CMD(MidiInDev[wDevID].incoming[0])) {
531         /* store new cmd, just in case */
532         MidiInDev[wDevID].incPrev = MidiInDev[wDevID].incoming[0];
533     }
534
535 #undef IS_CMD
536 #undef IS_SYS_CMD
537
538     switch (MidiInDev[wDevID].incoming[0] & 0xF0) {
539     case MIDI_NOTEOFF:
540     case MIDI_NOTEON:
541     case MIDI_KEY_PRESSURE:
542     case MIDI_CTL_CHANGE:
543     case MIDI_PITCH_BEND:
544         if (MidiInDev[wDevID].incLen == 3) {
545             toSend = (MidiInDev[wDevID].incoming[2] << 16) |
546                 (MidiInDev[wDevID].incoming[1] <<  8) |
547                 (MidiInDev[wDevID].incoming[0] <<  0);
548         }
549         break;
550     case MIDI_PGM_CHANGE:
551     case MIDI_CHN_PRESSURE:
552         if (MidiInDev[wDevID].incLen == 2) {
553             toSend = (MidiInDev[wDevID].incoming[1] <<  8) |
554                 (MidiInDev[wDevID].incoming[0] <<  0);
555         }
556         break;
557     case MIDI_SYSTEM_PREFIX:
558         if (MidiInDev[wDevID].incoming[0] == 0xF0) {
559             MidiInDev[wDevID].state |= 2;
560             MidiInDev[wDevID].incLen = 0;
561         } else {
562             if (MidiInDev[wDevID].incLen == 1) {
563                 toSend = (MidiInDev[wDevID].incoming[0] <<  0);
564             }
565         }
566         break;
567     default:
568         WARN("This shouldn't happen (%02X)\n", MidiInDev[wDevID].incoming[0]);
569     }
570     if (toSend != 0) {
571         TRACE("Sending event %08lx\n", toSend);
572         MidiInDev[wDevID].incLen =      0;
573         dwTime -= MidiInDev[wDevID].startTime;
574         if (MIDI_NotifyClient(wDevID, MIM_DATA, toSend, dwTime) != MMSYSERR_NOERROR) {
575             WARN("Couldn't notify client\n");
576         }
577     }
578 }
579
580 static VOID WINAPI midTimeCallback(HWND hwnd, UINT msg, UINT id, DWORD dwTime)
581 {
582     unsigned    char            buffer[256];
583     int                         len, idx;
584
585     TRACE("(%04X, %d, %d, %lu)\n", hwnd, msg, id, dwTime);
586
587     len = read(midiSeqFD, buffer, sizeof(buffer));
588
589     if (len < 0) return;
590     if ((len % 4) != 0) {
591         WARN("Bad length %d, errno %d (%s)\n", len, errno, strerror(errno));
592         return;
593     }
594
595     for (idx = 0; idx < len; ) {
596         if (buffer[idx] & 0x80) {
597             TRACE(
598                   "Reading<8> %02x %02x %02x %02x %02x %02x %02x %02x\n",
599                   buffer[idx + 0], buffer[idx + 1],
600                   buffer[idx + 2], buffer[idx + 3],
601                   buffer[idx + 4], buffer[idx + 5],
602                   buffer[idx + 6], buffer[idx + 7]);
603             idx += 8;
604         } else {
605             switch (buffer[idx + 0]) {
606             case SEQ_WAIT:
607             case SEQ_ECHO:
608                 break;
609             case SEQ_MIDIPUTC:
610                 midReceiveChar(buffer[idx + 2], buffer[idx + 1], dwTime);
611                 break;
612             default:
613                 TRACE("Unsupported event %d\n", buffer[idx + 0]);
614                 break;
615             }
616             idx += 4;
617         }
618     }
619 }
620
621 /**************************************************************************
622  *                              midGetDevCaps                   [internal]
623  */
624 static DWORD midGetDevCaps(WORD wDevID, LPMIDIINCAPSA lpCaps, DWORD dwSize)
625 {
626     TRACE("(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize);
627
628     if (wDevID >= MIDM_NUMDEVS) return MMSYSERR_BADDEVICEID;
629     if (lpCaps == NULL)         return MMSYSERR_INVALPARAM;
630
631     memcpy(lpCaps, midiInDevices[wDevID], min(dwSize, sizeof(*lpCaps)));
632
633     return MMSYSERR_NOERROR;
634 }
635
636 /**************************************************************************
637  *                      midOpen                                 [internal]
638  */
639 static DWORD midOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
640 {
641     TRACE("(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
642
643     if (lpDesc == NULL) {
644         WARN("Invalid Parameter !\n");
645         return MMSYSERR_INVALPARAM;
646     }
647
648     /* FIXME :
649      *  how to check that content of lpDesc is correct ?
650      */
651     if (wDevID >= MAX_MIDIINDRV) {
652         WARN("wDevID too large (%u) !\n", wDevID);
653         return MMSYSERR_BADDEVICEID;
654     }
655     if (MidiInDev[wDevID].midiDesc.hMidi != 0) {
656         WARN("device already open !\n");
657         return MMSYSERR_ALLOCATED;
658     }
659     if ((dwFlags & MIDI_IO_STATUS) != 0) {
660         WARN("No support for MIDI_IO_STATUS in dwFlags yet, ignoring it\n");
661         dwFlags &= ~MIDI_IO_STATUS;
662     }
663     if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) {
664         FIXME("Bad dwFlags\n");
665         return MMSYSERR_INVALFLAG;
666     }
667
668     if (midiOpenSeq() < 0) {
669         return MMSYSERR_ERROR;
670     }
671
672     if (numStartedMidiIn++ == 0) {
673         midiInTimerID = SetTimer(0, 0, 250, midTimeCallback);
674         if (!midiInTimerID) {
675             numStartedMidiIn = 0;
676             WARN("Couldn't start timer for midi-in\n");
677             midiCloseSeq();
678             return MMSYSERR_ERROR;
679         }
680         TRACE("Starting timer (%u) for midi-in\n", midiInTimerID);
681     }
682
683     MidiInDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
684
685     MidiInDev[wDevID].lpQueueHdr = NULL;
686     MidiInDev[wDevID].dwTotalPlayed = 0;
687     MidiInDev[wDevID].bufsize = 0x3FFF;
688     MidiInDev[wDevID].midiDesc = *lpDesc;
689     MidiInDev[wDevID].state = 0;
690     MidiInDev[wDevID].incLen = 0;
691     MidiInDev[wDevID].startTime = 0;
692
693     if (MIDI_NotifyClient(wDevID, MIM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
694         WARN("can't notify client !\n");
695         return MMSYSERR_INVALPARAM;
696     }
697     return MMSYSERR_NOERROR;
698 }
699
700 /**************************************************************************
701  *                      midClose                                [internal]
702  */
703 static DWORD midClose(WORD wDevID)
704 {
705     int         ret = MMSYSERR_NOERROR;
706
707     TRACE("(%04X);\n", wDevID);
708
709     if (wDevID >= MAX_MIDIINDRV) {
710         WARN("wDevID too big (%u) !\n", wDevID);
711         return MMSYSERR_BADDEVICEID;
712     }
713     if (MidiInDev[wDevID].midiDesc.hMidi == 0) {
714         WARN("device not opened !\n");
715         return MMSYSERR_ERROR;
716     }
717     if (MidiInDev[wDevID].lpQueueHdr != 0) {
718         return MIDIERR_STILLPLAYING;
719     }
720
721     if (midiSeqFD == -1) {
722         WARN("ooops !\n");
723         return MMSYSERR_ERROR;
724     }
725     if (--numStartedMidiIn == 0) {
726         TRACE("Stopping timer for midi-in\n");
727         if (!KillTimer(0, midiInTimerID)) {
728             WARN("Couldn't stop timer for midi-in\n");
729         }
730         midiInTimerID = 0;
731     }
732     midiCloseSeq();
733
734     MidiInDev[wDevID].bufsize = 0;
735     if (MIDI_NotifyClient(wDevID, MIM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
736         WARN("can't notify client !\n");
737         ret = MMSYSERR_INVALPARAM;
738     }
739     MidiInDev[wDevID].midiDesc.hMidi = 0;
740     return ret;
741 }
742
743 /**************************************************************************
744  *                              midAddBuffer                    [internal]
745  */
746 static DWORD midAddBuffer(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
747 {
748     TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
749
750     if (lpMidiHdr == NULL)      return MMSYSERR_INVALPARAM;
751     if (sizeof(MIDIHDR) > dwSize) return MMSYSERR_INVALPARAM;
752     if (lpMidiHdr->dwBufferLength == 0) return MMSYSERR_INVALPARAM;
753     if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING;
754     if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED;
755
756     if (MidiInDev[wDevID].lpQueueHdr == 0) {
757         MidiInDev[wDevID].lpQueueHdr = lpMidiHdr;
758     } else {
759         LPMIDIHDR       ptr;
760
761         for (ptr = MidiInDev[wDevID].lpQueueHdr;
762              ptr->lpNext != 0;
763              ptr = (LPMIDIHDR)ptr->lpNext);
764         ptr->lpNext = (struct midihdr_tag*)lpMidiHdr;
765     }
766     return MMSYSERR_NOERROR;
767 }
768
769 /**************************************************************************
770  *                              midPrepare                      [internal]
771  */
772 static DWORD midPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
773 {
774     TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
775
776     if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0 ||
777         lpMidiHdr->lpData == 0 || lpMidiHdr->dwFlags != 0 ||
778         lpMidiHdr->dwBufferLength >= 0x10000ul)
779         return MMSYSERR_INVALPARAM;
780
781     lpMidiHdr->lpNext = 0;
782     lpMidiHdr->dwFlags |= MHDR_PREPARED;
783     lpMidiHdr->dwBytesRecorded = 0;
784
785     return MMSYSERR_NOERROR;
786 }
787
788 /**************************************************************************
789  *                              midUnprepare                    [internal]
790  */
791 static DWORD midUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
792 {
793     TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
794
795     if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0 ||
796         lpMidiHdr->lpData == 0 || lpMidiHdr->dwBufferLength >= 0x10000ul)
797         return MMSYSERR_INVALPARAM;
798
799     if (!(lpMidiHdr->dwFlags & MHDR_PREPARED)) return MIDIERR_UNPREPARED;
800     if (lpMidiHdr->dwFlags & MHDR_INQUEUE) return MIDIERR_STILLPLAYING;
801
802     lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
803
804     return MMSYSERR_NOERROR;
805 }
806
807 /**************************************************************************
808  *                      midReset                                [internal]
809  */
810 static DWORD midReset(WORD wDevID)
811 {
812     DWORD               dwTime = GetTickCount();
813
814     TRACE("(%04X);\n", wDevID);
815
816     while (MidiInDev[wDevID].lpQueueHdr) {
817         MidiInDev[wDevID].lpQueueHdr->dwFlags &= ~MHDR_INQUEUE;
818         MidiInDev[wDevID].lpQueueHdr->dwFlags |= MHDR_DONE;
819         /* FIXME: when called from 16 bit, lpQueueHdr needs to be a segmented ptr */
820         if (MIDI_NotifyClient(wDevID, MIM_LONGDATA,
821                               (DWORD)MidiInDev[wDevID].lpQueueHdr, dwTime) != MMSYSERR_NOERROR) {
822             WARN("Couldn't notify client\n");
823         }
824         MidiInDev[wDevID].lpQueueHdr = (LPMIDIHDR)MidiInDev[wDevID].lpQueueHdr->lpNext;
825     }
826
827     return MMSYSERR_NOERROR;
828 }
829
830
831 /**************************************************************************
832  *                      midStart                                [internal]
833  */
834 static DWORD midStart(WORD wDevID)
835 {
836     TRACE("(%04X);\n", wDevID);
837
838     /* FIXME : should test value of wDevID */
839
840     MidiInDev[wDevID].state = 1;
841     MidiInDev[wDevID].startTime = GetTickCount();
842     return MMSYSERR_NOERROR;
843 }
844
845 /**************************************************************************
846  *                      midStop                                 [internal]
847  */
848 static DWORD midStop(WORD wDevID)
849 {
850     TRACE("(%04X);\n", wDevID);
851
852     /* FIXME : should test value of wDevID */
853     MidiInDev[wDevID].state = 0;
854     return MMSYSERR_NOERROR;
855 }
856
857 /*-----------------------------------------------------------------------*/
858
859 typedef struct sVoice {
860     int                 note;                   /* 0 means not used */
861     int                 channel;
862     unsigned            cntMark : 30,
863                         status : 2;
864 #define sVS_UNUSED      0
865 #define sVS_PLAYING     1
866 #define sVS_SUSTAINED   2
867 } sVoice;
868
869 typedef struct sChannel {
870     int                 program;
871
872     int                 bender;
873     int                 benderRange;
874     /* controlers */
875     int                 bank;           /* CTL_BANK_SELECT */
876     int                 volume;         /* CTL_MAIN_VOLUME */
877     int                 balance;        /* CTL_BALANCE     */
878     int                 expression;     /* CTL_EXPRESSION  */
879     int                 sustain;        /* CTL_SUSTAIN     */
880
881     unsigned char       nrgPmtMSB;      /* Non register Parameters */
882     unsigned char       nrgPmtLSB;
883     unsigned char       regPmtMSB;      /* Non register Parameters */
884     unsigned char       regPmtLSB;
885 } sChannel;
886
887 typedef struct sFMextra {
888     unsigned            counter;
889     int                 drumSetMask;
890     sChannel            channel[16];    /* MIDI has only 16 channels */
891     sVoice              voice[1];       /* dyn allocated according to sound card */
892     /* do not append fields below voice[1] since the size of this structure
893      * depends on the number of available voices on the FM synth...
894      */
895 } sFMextra;
896
897 extern  unsigned char midiFMInstrumentPatches[16 * 128];
898 extern  unsigned char midiFMDrumsPatches     [16 * 128];
899
900 /**************************************************************************
901  *                      modFMLoad                               [internal]
902  */
903 static int modFMLoad(int dev)
904 {
905     int                         i;
906     struct sbi_instrument       sbi;
907
908     sbi.device = dev;
909     sbi.key = FM_PATCH;
910
911     memset(sbi.operators + 16, 0, 16);
912     for (i = 0; i < 128; i++) {
913         sbi.channel = i;
914         memcpy(sbi.operators, midiFMInstrumentPatches + i * 16, 16);
915
916         if (write(midiSeqFD, (char*)&sbi, sizeof(sbi)) == -1) {
917             WARN("Couldn't write patch for instrument %d, errno %d (%s)!\n", sbi.channel, errno, strerror(errno));
918             return -1;
919         }
920     }
921     for (i = 0; i < 128; i++) {
922         sbi.channel = 128 + i;
923         memcpy(sbi.operators, midiFMDrumsPatches + i * 16, 16);
924
925         if (write(midiSeqFD, (char*)&sbi, sizeof(sbi)) == -1) {
926             WARN("Couldn't write patch for drum %d, errno %d (%s)!\n", sbi.channel, errno, strerror(errno));
927             return -1;
928         }
929     }
930     return 0;
931 }
932
933 /**************************************************************************
934  *                      modFMReset                              [internal]
935  */
936 static  void modFMReset(WORD wDevID)
937 {
938     sFMextra*   extra   = (sFMextra*)MidiOutDev[wDevID].lpExtra;
939     sVoice*     voice   = extra->voice;
940     sChannel*   channel = extra->channel;
941     int         i;
942
943     for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
944         if (voice[i].status != sVS_UNUSED) {
945             SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64);
946         }
947         SEQ_KEY_PRESSURE(wDevID, i, 127, 0);
948         SEQ_CONTROL(wDevID, i, SEQ_VOLMODE, VOL_METHOD_LINEAR);
949         voice[i].note = 0;
950         voice[i].channel = -1;
951         voice[i].cntMark = 0;
952         voice[i].status = sVS_UNUSED;
953     }
954     for (i = 0; i < 16; i++) {
955         channel[i].program = 0;
956         channel[i].bender = 8192;
957         channel[i].benderRange = 2;
958         channel[i].bank = 0;
959         channel[i].volume = 127;
960         channel[i].balance = 64;
961         channel[i].expression = 0;
962         channel[i].sustain = 0;
963     }
964     extra->counter = 0;
965     extra->drumSetMask = 1 << 9; /* channel 10 is normally drums, sometimes 16 also */
966     SEQ_DUMPBUF();
967 }
968
969 #define         IS_DRUM_CHANNEL(_xtra, _chn)    ((_xtra)->drumSetMask & (1 << (_chn)))
970
971 /**************************************************************************
972  *                              modGetDevCaps                   [internal]
973  */
974 static DWORD modGetDevCaps(WORD wDevID, LPMIDIOUTCAPSA lpCaps, DWORD dwSize)
975 {
976     TRACE("(%04X, %p, %08lX);\n", wDevID, lpCaps, dwSize);
977
978     if (wDevID >= MODM_NUMDEVS) return MMSYSERR_BADDEVICEID;
979     if (lpCaps == NULL)         return MMSYSERR_INVALPARAM;
980
981     memcpy(lpCaps, midiOutDevices[wDevID], min(dwSize, sizeof(*lpCaps)));
982
983     return MMSYSERR_NOERROR;
984 }
985
986 /**************************************************************************
987  *                      modOpen                                 [internal]
988  */
989 static DWORD modOpen(WORD wDevID, LPMIDIOPENDESC lpDesc, DWORD dwFlags)
990 {
991     TRACE("(%04X, %p, %08lX);\n", wDevID, lpDesc, dwFlags);
992     if (lpDesc == NULL) {
993         WARN("Invalid Parameter !\n");
994         return MMSYSERR_INVALPARAM;
995     }
996     if (wDevID >= MAX_MIDIOUTDRV) {
997         TRACE("MAX_MIDIOUTDRV reached !\n");
998         return MMSYSERR_BADDEVICEID;
999     }
1000     if (MidiOutDev[wDevID].midiDesc.hMidi != 0) {
1001         WARN("device already open !\n");
1002         return MMSYSERR_ALLOCATED;
1003     }
1004     if ((dwFlags & ~CALLBACK_TYPEMASK) != 0) {
1005         WARN("bad dwFlags\n");
1006         return MMSYSERR_INVALFLAG;
1007     }
1008     if (midiOutDevices[wDevID] == NULL) {
1009         TRACE("un-allocated wDevID\n");
1010         return MMSYSERR_BADDEVICEID;
1011     }
1012
1013     MidiOutDev[wDevID].lpExtra = 0;
1014
1015     switch (midiOutDevices[wDevID]->wTechnology) {
1016     case MOD_FMSYNTH:
1017         {
1018             void*       extra = HeapAlloc(GetProcessHeap(), 0,
1019                                           sizeof(struct sFMextra) +
1020                                           sizeof(struct sVoice) * (midiOutDevices[wDevID]->wVoices - 1));
1021
1022             if (extra == 0) {
1023                 WARN("can't alloc extra data !\n");
1024                 return MMSYSERR_NOMEM;
1025             }
1026             MidiOutDev[wDevID].lpExtra = extra;
1027             if (midiOpenSeq() < 0) {
1028                 MidiOutDev[wDevID].lpExtra = 0;
1029                 HeapFree(GetProcessHeap(), 0, extra);
1030                 return MMSYSERR_ERROR;
1031             }
1032             if (modFMLoad(wDevID) < 0) {
1033                 midiCloseSeq();
1034                 MidiOutDev[wDevID].lpExtra = 0;
1035                 HeapFree(GetProcessHeap(), 0, extra);
1036                 return MMSYSERR_ERROR;
1037             }
1038             modFMReset(wDevID);
1039         }
1040         break;
1041     case MOD_MIDIPORT:
1042         if (midiOpenSeq() < 0) {
1043             return MMSYSERR_ALLOCATED;
1044         }
1045         break;
1046     default:
1047         WARN("Technology not supported (yet) %d !\n",
1048              midiOutDevices[wDevID]->wTechnology);
1049         return MMSYSERR_NOTENABLED;
1050     }
1051
1052     MidiOutDev[wDevID].wFlags = HIWORD(dwFlags & CALLBACK_TYPEMASK);
1053
1054     MidiOutDev[wDevID].lpQueueHdr = NULL;
1055     MidiOutDev[wDevID].dwTotalPlayed = 0;
1056     MidiOutDev[wDevID].bufsize = 0x3FFF;
1057     MidiOutDev[wDevID].midiDesc = *lpDesc;
1058
1059     if (MIDI_NotifyClient(wDevID, MOM_OPEN, 0L, 0L) != MMSYSERR_NOERROR) {
1060         WARN("can't notify client !\n");
1061         return MMSYSERR_INVALPARAM;
1062     }
1063     TRACE("Successful !\n");
1064     return MMSYSERR_NOERROR;
1065 }
1066
1067
1068 /**************************************************************************
1069  *                      modClose                                [internal]
1070  */
1071 static DWORD modClose(WORD wDevID)
1072 {
1073     int ret = MMSYSERR_NOERROR;
1074
1075     TRACE("(%04X);\n", wDevID);
1076
1077     if (MidiOutDev[wDevID].midiDesc.hMidi == 0) {
1078         WARN("device not opened !\n");
1079         return MMSYSERR_ERROR;
1080     }
1081     /* FIXME: should test that no pending buffer is still in the queue for
1082      * playing */
1083
1084     if (midiSeqFD == -1) {
1085         WARN("can't close !\n");
1086         return MMSYSERR_ERROR;
1087     }
1088
1089     switch (midiOutDevices[wDevID]->wTechnology) {
1090     case MOD_FMSYNTH:
1091     case MOD_MIDIPORT:
1092         midiCloseSeq();
1093         break;
1094     default:
1095         WARN("Technology not supported (yet) %d !\n",
1096              midiOutDevices[wDevID]->wTechnology);
1097         return MMSYSERR_NOTENABLED;
1098     }
1099
1100     if (MidiOutDev[wDevID].lpExtra != 0) {
1101         HeapFree(GetProcessHeap(), 0, MidiOutDev[wDevID].lpExtra);
1102         MidiOutDev[wDevID].lpExtra = 0;
1103     }
1104
1105     MidiOutDev[wDevID].bufsize = 0;
1106     if (MIDI_NotifyClient(wDevID, MOM_CLOSE, 0L, 0L) != MMSYSERR_NOERROR) {
1107         WARN("can't notify client !\n");
1108         ret = MMSYSERR_INVALPARAM;
1109     }
1110     MidiOutDev[wDevID].midiDesc.hMidi = 0;
1111     return ret;
1112 }
1113
1114 /**************************************************************************
1115  *                      modData                                 [internal]
1116  */
1117 static DWORD modData(WORD wDevID, DWORD dwParam)
1118 {
1119     WORD        evt = LOBYTE(LOWORD(dwParam));
1120     WORD        d1  = HIBYTE(LOWORD(dwParam));
1121     WORD        d2  = LOBYTE(HIWORD(dwParam));
1122
1123     TRACE("(%04X, %08lX);\n", wDevID, dwParam);
1124
1125     if (midiSeqFD == -1) {
1126         WARN("can't play !\n");
1127         return MIDIERR_NODEVICE;
1128     }
1129     switch (midiOutDevices[wDevID]->wTechnology) {
1130     case MOD_FMSYNTH:
1131         /* FIXME:
1132          *      - chorus depth controller is not used
1133          */
1134         {
1135             sFMextra*   extra   = (sFMextra*)MidiOutDev[wDevID].lpExtra;
1136             sVoice*     voice   = extra->voice;
1137             sChannel*   channel = extra->channel;
1138             int         chn = (evt & 0x0F);
1139             int         i, nv;
1140
1141             switch (evt & 0xF0) {
1142             case MIDI_NOTEOFF:
1143                 for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1144                                 /* don't stop sustained notes */
1145                     if (voice[i].status == sVS_PLAYING && voice[i].channel == chn && voice[i].note == d1) {
1146                         voice[i].status = sVS_UNUSED;
1147                         SEQ_STOP_NOTE(wDevID, i, d1, d2);
1148                     }
1149                 }
1150                 break;
1151             case MIDI_NOTEON:
1152                 if (d2 == 0) { /* note off if velocity == 0 */
1153                     for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1154                         /* don't stop sustained notes */
1155                         if (voice[i].status == sVS_PLAYING && voice[i].channel == chn && voice[i].note == d1) {
1156                             voice[i].status = sVS_UNUSED;
1157                             SEQ_STOP_NOTE(wDevID, i, d1, 64);
1158                         }
1159                     }
1160                     break;
1161                 }
1162                 /* finding out in this order :
1163                  *      - an empty voice
1164                  *      - if replaying the same note on the same channel
1165                  *      - the older voice (LRU)
1166                  */
1167                 for (i = nv = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1168                     if (voice[i].status == sVS_UNUSED ||
1169                         (voice[i].note == d1 && voice[i].channel == chn)) {
1170                         nv = i;
1171                         break;
1172                     }
1173                     if (voice[i].cntMark < voice[0].cntMark) {
1174                         nv = i;
1175                     }
1176                 }
1177                 TRACE(
1178                       "playing on voice=%d, pgm=%d, pan=0x%02X, vol=0x%02X, "
1179                       "bender=0x%02X, note=0x%02X, vel=0x%02X\n",
1180                       nv, channel[chn].program,
1181                       channel[chn].balance,
1182                       channel[chn].volume,
1183                       channel[chn].bender, d1, d2);
1184
1185                 SEQ_SET_PATCH(wDevID, nv, IS_DRUM_CHANNEL(extra, chn) ?
1186                               (128 + d1) : channel[chn].program);
1187                 SEQ_BENDER_RANGE(wDevID, nv, channel[chn].benderRange * 100);
1188                 SEQ_BENDER(wDevID, nv, channel[chn].bender);
1189                 SEQ_CONTROL(wDevID, nv, CTL_PAN, channel[chn].balance);
1190                 SEQ_CONTROL(wDevID, nv, CTL_EXPRESSION, channel[chn].expression);
1191 #if 0
1192                 /* FIXME: does not really seem to work on my SB card and
1193                  * screws everything up... so lay it down
1194                  */
1195                 SEQ_CONTROL(wDevID, nv, CTL_MAIN_VOLUME, channel[chn].volume);
1196 #endif
1197                 SEQ_START_NOTE(wDevID, nv, d1, d2);
1198                 voice[nv].status = channel[chn].sustain ? sVS_SUSTAINED : sVS_PLAYING;
1199                 voice[nv].note = d1;
1200                 voice[nv].channel = chn;
1201                 voice[nv].cntMark = extra->counter++;
1202                 break;
1203             case MIDI_KEY_PRESSURE:
1204                 for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1205                     if (voice[i].status != sVS_UNUSED && voice[i].channel == chn && voice[i].note == d1) {
1206                         SEQ_KEY_PRESSURE(wDevID, i, d1, d2);
1207                     }
1208                 }
1209                 break;
1210             case MIDI_CTL_CHANGE:
1211                 switch (d1) {
1212                 case CTL_BANK_SELECT:   channel[chn].bank = d2;         break;
1213                 case CTL_MAIN_VOLUME:   channel[chn].volume = d2;       break;
1214                 case CTL_PAN:           channel[chn].balance = d2;      break;
1215                 case CTL_EXPRESSION:    channel[chn].expression = d2;   break;
1216                 case CTL_SUSTAIN:       channel[chn].sustain = d2;
1217                     if (d2) {
1218                         for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1219                             if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) {
1220                                 voice[i].status = sVS_SUSTAINED;
1221                             }
1222                         }
1223                     } else {
1224                         for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1225                             if (voice[i].status == sVS_SUSTAINED && voice[i].channel == chn) {
1226                                 voice[i].status = sVS_UNUSED;
1227                                 SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64);
1228                             }
1229                         }
1230                     }
1231                     break;
1232                 case CTL_NONREG_PARM_NUM_LSB:   channel[chn].nrgPmtLSB = d2;    break;
1233                 case CTL_NONREG_PARM_NUM_MSB:   channel[chn].nrgPmtMSB = d2;    break;
1234                 case CTL_REGIST_PARM_NUM_LSB:   channel[chn].regPmtLSB = d2;    break;
1235                 case CTL_REGIST_PARM_NUM_MSB:   channel[chn].regPmtMSB = d2;    break;
1236                 case CTL_DATA_ENTRY:
1237                     switch ((channel[chn].regPmtMSB << 8) | channel[chn].regPmtLSB) {
1238                     case 0x0000:
1239                         if (channel[chn].benderRange != d2) {
1240                             channel[chn].benderRange = d2;
1241                             for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1242                                 if (voice[i].channel == chn) {
1243                                     SEQ_BENDER_RANGE(wDevID, i, channel[chn].benderRange);
1244                                 }
1245                             }
1246                         }
1247                         break;
1248
1249                     case 0x7F7F:
1250                         channel[chn].benderRange = 2;
1251                         for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1252                             if (voice[i].channel == chn) {
1253                                 SEQ_BENDER_RANGE(wDevID, i, channel[chn].benderRange);
1254                             }
1255                         }
1256                         break;
1257                     default:
1258                         TRACE("Data entry: regPmt=0x%02x%02x, nrgPmt=0x%02x%02x with %x\n",
1259                               channel[chn].regPmtMSB, channel[chn].regPmtLSB,
1260                               channel[chn].nrgPmtMSB, channel[chn].nrgPmtLSB,
1261                               d2);
1262                         break;
1263                     }
1264                     break;
1265
1266                 case 0x78: /* all sounds off */
1267                     /* FIXME: I don't know if I have to take care of the channel
1268                      * for this control ?
1269                      */
1270                     for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1271                         if (voice[i].status != sVS_UNUSED && voice[i].channel == chn) {
1272                             voice[i].status = sVS_UNUSED;
1273                             SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64);
1274                         }
1275                     }
1276                     break;
1277                 case 0x7B: /* all notes off */
1278                     /* FIXME: I don't know if I have to take care of the channel
1279                      * for this control ?
1280                      */
1281                     for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1282                         if (voice[i].status == sVS_PLAYING && voice[i].channel == chn) {
1283                             voice[i].status = sVS_UNUSED;
1284                             SEQ_STOP_NOTE(wDevID, i, voice[i].note, 64);
1285                         }
1286                     }
1287                     break;
1288                 default:
1289                     TRACE("Dropping MIDI control event 0x%02x(%02x) on channel %d\n",
1290                           d1, d2, chn);
1291                     break;
1292                 }
1293                 break;
1294             case MIDI_PGM_CHANGE:
1295                 channel[chn].program = d1;
1296                 break;
1297             case MIDI_CHN_PRESSURE:
1298                 for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1299                     if (voice[i].status != sVS_UNUSED && voice[i].channel == chn) {
1300                         SEQ_KEY_PRESSURE(wDevID, i, voice[i].note, d1);
1301                     }
1302                 }
1303                 break;
1304             case MIDI_PITCH_BEND:
1305                 channel[chn].bender = (d2 << 7) + d1;
1306                 for (i = 0; i < midiOutDevices[wDevID]->wVoices; i++) {
1307                     if (voice[i].channel == chn) {
1308                         SEQ_BENDER(wDevID, i, channel[chn].bender);
1309                     }
1310                 }
1311                 break;
1312             case MIDI_SYSTEM_PREFIX:
1313                 switch (evt & 0x0F) {
1314                 case 0x0F:      /* Reset */
1315                     modFMReset(wDevID);
1316                     break;
1317                 default:
1318                     WARN("Unsupported (yet) system event %02x\n", evt & 0x0F);
1319                 }
1320                 break;
1321             default:
1322                 WARN("Internal error, shouldn't happen (event=%08x)\n", evt & 0xF0);
1323                 return MMSYSERR_NOTENABLED;
1324             }
1325         }
1326         break;
1327     case MOD_MIDIPORT:
1328         {
1329             int dev = wDevID - MODM_NUMFMSYNTHDEVS;
1330             if (dev < 0) {
1331                 WARN("Internal error on devID (%u) !\n", wDevID);
1332                 return MIDIERR_NODEVICE;
1333             }
1334
1335             switch (evt & 0xF0) {
1336             case MIDI_NOTEOFF:
1337             case MIDI_NOTEON:
1338             case MIDI_KEY_PRESSURE:
1339             case MIDI_CTL_CHANGE:
1340             case MIDI_PITCH_BEND:
1341                 SEQ_MIDIOUT(dev, evt);
1342                 SEQ_MIDIOUT(dev, d1);
1343                 SEQ_MIDIOUT(dev, d2);
1344                 break;
1345             case MIDI_PGM_CHANGE:
1346             case MIDI_CHN_PRESSURE:
1347                 SEQ_MIDIOUT(dev, evt);
1348                 SEQ_MIDIOUT(dev, d1);
1349                 break;
1350             case MIDI_SYSTEM_PREFIX:
1351                 switch (evt & 0x0F) {
1352                 case 0x00:      /* System Exclusive, don't do it on modData,
1353                                  * should require modLongData*/
1354                 case 0x01:      /* Undefined */
1355                 case 0x04:      /* Undefined. */
1356                 case 0x05:      /* Undefined. */
1357                 case 0x07:      /* End of Exclusive. */
1358                 case 0x09:      /* Undefined. */
1359                 case 0x0D:      /* Undefined. */
1360                     break;
1361                 case 0x06:      /* Tune Request */
1362                 case 0x08:      /* Timing Clock. */
1363                 case 0x0A:      /* Start. */
1364                 case 0x0B:      /* Continue */
1365                 case 0x0C:      /* Stop */
1366                 case 0x0E:      /* Active Sensing. */
1367                     SEQ_MIDIOUT(dev, evt);
1368                     break;
1369                 case 0x0F:      /* Reset */
1370                                 /* SEQ_MIDIOUT(dev, evt);
1371                                    this other way may be better */
1372                     SEQ_MIDIOUT(dev, MIDI_SYSTEM_PREFIX);
1373                     SEQ_MIDIOUT(dev, 0x7e);
1374                     SEQ_MIDIOUT(dev, 0x7f);
1375                     SEQ_MIDIOUT(dev, 0x09);
1376                     SEQ_MIDIOUT(dev, 0x01);
1377                     SEQ_MIDIOUT(dev, 0xf7);
1378                     break;
1379                 case 0x03:      /* Song Select. */
1380                     SEQ_MIDIOUT(dev, evt);
1381                     SEQ_MIDIOUT(dev, d1);
1382                 case 0x02:      /* Song Position Pointer. */
1383                     SEQ_MIDIOUT(dev, evt);
1384                     SEQ_MIDIOUT(dev, d1);
1385                     SEQ_MIDIOUT(dev, d2);
1386                 }
1387                 break;
1388             }
1389         }
1390         break;
1391     default:
1392         WARN("Technology not supported (yet) %d !\n",
1393              midiOutDevices[wDevID]->wTechnology);
1394         return MMSYSERR_NOTENABLED;
1395     }
1396
1397     SEQ_DUMPBUF();
1398
1399     return MMSYSERR_NOERROR;
1400 }
1401
1402 /**************************************************************************
1403  *              modLongData                                     [internal]
1404  */
1405 static DWORD modLongData(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
1406 {
1407     int         count;
1408     LPBYTE      lpData;
1409
1410     TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
1411
1412     if (midiSeqFD == -1) {
1413         WARN("can't play !\n");
1414         return MIDIERR_NODEVICE;
1415     }
1416
1417     lpData = lpMidiHdr->lpData;
1418
1419     if (lpData == NULL)
1420         return MIDIERR_UNPREPARED;
1421     if (!(lpMidiHdr->dwFlags & MHDR_PREPARED))
1422         return MIDIERR_UNPREPARED;
1423     if (lpMidiHdr->dwFlags & MHDR_INQUEUE)
1424         return MIDIERR_STILLPLAYING;
1425     lpMidiHdr->dwFlags &= ~MHDR_DONE;
1426     lpMidiHdr->dwFlags |= MHDR_INQUEUE;
1427
1428     /* FIXME: MS doc is not 100% clear. Will lpData only contain system exclusive
1429      * data, or can it also contain raw MIDI data, to be split up and sent to
1430      * modShortData() ?
1431      * If the latest is true, then the following WARNing will fire up
1432      */
1433     if (lpData[0] != 0xF0 || lpData[lpMidiHdr->dwBufferLength - 1] != 0xF7) {
1434         WARN("Alledged system exclusive buffer is not correct\n\tPlease report with MIDI file\n");
1435     }
1436
1437     TRACE("dwBufferLength=%lu !\n", lpMidiHdr->dwBufferLength);
1438     TRACE("                 %02X %02X %02X ... %02X %02X %02X\n",
1439           lpData[0], lpData[1], lpData[2], lpData[lpMidiHdr->dwBufferLength-3],
1440           lpData[lpMidiHdr->dwBufferLength-2], lpData[lpMidiHdr->dwBufferLength-1]);
1441
1442     switch (midiOutDevices[wDevID]->wTechnology) {
1443     case MOD_FMSYNTH:
1444         /* FIXME: I don't think there is much to do here */
1445         break;
1446     case MOD_MIDIPORT:
1447         if (lpData[0] != 0xF0) {
1448             /* Send end of System Exclusive */
1449             SEQ_MIDIOUT(wDevID - MODM_NUMFMSYNTHDEVS, 0xF0);
1450             WARN("Adding missing 0xF0 marker at the beginning of "
1451                  "system exclusive byte stream\n");
1452         }
1453         for (count = 0; count < lpMidiHdr->dwBytesRecorded; count++) {
1454             SEQ_MIDIOUT(wDevID - MODM_NUMFMSYNTHDEVS, lpData[count]);
1455         }
1456         if (lpData[count - 1] != 0xF7) {
1457             /* Send end of System Exclusive */
1458             SEQ_MIDIOUT(wDevID - MODM_NUMFMSYNTHDEVS, 0xF7);
1459             WARN("Adding missing 0xF7 marker at the end of "
1460                  "system exclusive byte stream\n");
1461         }
1462         SEQ_DUMPBUF();
1463         break;
1464     default:
1465         WARN("Technology not supported (yet) %d !\n",
1466              midiOutDevices[wDevID]->wTechnology);
1467         return MMSYSERR_NOTENABLED;
1468     }
1469
1470     lpMidiHdr->dwFlags &= ~MHDR_INQUEUE;
1471     lpMidiHdr->dwFlags |= MHDR_DONE;
1472     if (MIDI_NotifyClient(wDevID, MOM_DONE, (DWORD)lpMidiHdr, 0L) != MMSYSERR_NOERROR) {
1473         WARN("can't notify client !\n");
1474         return MMSYSERR_INVALPARAM;
1475     }
1476     return MMSYSERR_NOERROR;
1477 }
1478
1479 /**************************************************************************
1480  *                      modPrepare                              [internal]
1481  */
1482 static DWORD modPrepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
1483 {
1484     TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
1485
1486     if (midiSeqFD == -1) {
1487         WARN("can't prepare !\n");
1488         return MMSYSERR_NOTENABLED;
1489     }
1490
1491     /* MS doc says taht dwFlags must be set to zero, but (kinda funny) MS mciseq drivers
1492      * asks to prepare MIDIHDR which dwFlags != 0.
1493      * So at least check for the inqueue flag
1494      */
1495     if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0 ||
1496         lpMidiHdr->lpData == 0 || (lpMidiHdr->dwFlags & MHDR_INQUEUE) != 0 ||
1497         lpMidiHdr->dwBufferLength >= 0x10000ul) {
1498         WARN("%p %p %08lx %d/%ld\n", lpMidiHdr, lpMidiHdr->lpData,
1499                    lpMidiHdr->dwFlags, sizeof(MIDIHDR), dwSize);
1500         return MMSYSERR_INVALPARAM;
1501     }
1502
1503     lpMidiHdr->lpNext = 0;
1504     lpMidiHdr->dwFlags |= MHDR_PREPARED;
1505     lpMidiHdr->dwFlags &= ~MHDR_DONE;
1506     return MMSYSERR_NOERROR;
1507 }
1508
1509 /**************************************************************************
1510  *                              modUnprepare                    [internal]
1511  */
1512 static DWORD modUnprepare(WORD wDevID, LPMIDIHDR lpMidiHdr, DWORD dwSize)
1513 {
1514     TRACE("(%04X, %p, %08lX);\n", wDevID, lpMidiHdr, dwSize);
1515
1516     if (midiSeqFD == -1) {
1517         WARN("can't unprepare !\n");
1518         return MMSYSERR_NOTENABLED;
1519     }
1520
1521     if (dwSize < sizeof(MIDIHDR) || lpMidiHdr == 0)
1522         return MMSYSERR_INVALPARAM;
1523     if (lpMidiHdr->dwFlags & MHDR_INQUEUE)
1524         return MIDIERR_STILLPLAYING;
1525     lpMidiHdr->dwFlags &= ~MHDR_PREPARED;
1526     return MMSYSERR_NOERROR;
1527 }
1528
1529 /**************************************************************************
1530  *                      modReset                                [internal]
1531  */
1532 static DWORD modReset(WORD wDevID)
1533 {
1534     unsigned chn;
1535
1536     TRACE("(%04X);\n", wDevID);
1537
1538     /* stop all notes */
1539     /* FIXME: check if 0x78B0 is channel dependant or not. I coded it so that
1540      * it's channel dependent...
1541      */
1542     for (chn = 0; chn < 16; chn++) {
1543         /* turn off every note */
1544         modData(wDevID, 0x7800 | MIDI_CTL_CHANGE | chn);
1545         /* remove sustain on all channels */
1546         modData(wDevID, (CTL_SUSTAIN << 8) | MIDI_CTL_CHANGE | chn);
1547     }
1548     /* FIXME: the LongData buffers must also be returned to the app */
1549     return MMSYSERR_NOERROR;
1550 }
1551
1552 #endif /* HAVE_OSS_MIDI */
1553
1554 /*======================================================================*
1555  *                          MIDI entry points                           *
1556  *======================================================================*/
1557
1558 /**************************************************************************
1559  *                      midMessage (WINEOSS.4)
1560  */
1561 DWORD WINAPI OSS_midMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
1562                             DWORD dwParam1, DWORD dwParam2)
1563 {
1564     TRACE("(%04X, %04X, %08lX, %08lX, %08lX);\n",
1565           wDevID, wMsg, dwUser, dwParam1, dwParam2);
1566     switch (wMsg) {
1567 #ifdef HAVE_OSS_MIDI
1568     case DRVM_INIT:
1569     case DRVM_ENABLE:
1570     case DRVM_DISABLE:
1571         /* FIXME: Pretend this is supported */
1572         return 0;
1573     case MIDM_OPEN:
1574         return midOpen(wDevID, (LPMIDIOPENDESC)dwParam1, dwParam2);
1575     case MIDM_CLOSE:
1576         return midClose(wDevID);
1577     case MIDM_ADDBUFFER:
1578         return midAddBuffer(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1579     case MIDM_PREPARE:
1580         return midPrepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1581     case MIDM_UNPREPARE:
1582         return midUnprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1583     case MIDM_GETDEVCAPS:
1584         return midGetDevCaps(wDevID, (LPMIDIINCAPSA)dwParam1,dwParam2);
1585     case MIDM_GETNUMDEVS:
1586         return MIDM_NUMDEVS;
1587     case MIDM_RESET:
1588         return midReset(wDevID);
1589     case MIDM_START:
1590         return midStart(wDevID);
1591     case MIDM_STOP:
1592         return midStop(wDevID);
1593 #endif
1594     default:
1595         TRACE("Unsupported message\n");
1596     }
1597     return MMSYSERR_NOTSUPPORTED;
1598 }
1599
1600 /**************************************************************************
1601  *                              modMessage (WINEOSS.5)
1602  */
1603 DWORD WINAPI OSS_modMessage(UINT wDevID, UINT wMsg, DWORD dwUser,
1604                             DWORD dwParam1, DWORD dwParam2)
1605 {
1606     TRACE("(%04X, %04X, %08lX, %08lX, %08lX);\n",
1607           wDevID, wMsg, dwUser, dwParam1, dwParam2);
1608
1609     switch (wMsg) {
1610 #ifdef HAVE_OSS_MIDI
1611     case DRVM_INIT:
1612     case DRVM_EXIT:
1613     case DRVM_ENABLE:
1614     case DRVM_DISABLE:
1615         /* FIXME: Pretend this is supported */
1616         return 0;
1617     case MODM_OPEN:
1618         return modOpen(wDevID, (LPMIDIOPENDESC)dwParam1, dwParam2);
1619     case MODM_CLOSE:
1620         return modClose(wDevID);
1621     case MODM_DATA:
1622         return modData(wDevID, dwParam1);
1623     case MODM_LONGDATA:
1624         return modLongData(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1625     case MODM_PREPARE:
1626         return modPrepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1627     case MODM_UNPREPARE:
1628         return modUnprepare(wDevID, (LPMIDIHDR)dwParam1, dwParam2);
1629     case MODM_GETDEVCAPS:
1630         return modGetDevCaps(wDevID, (LPMIDIOUTCAPSA)dwParam1, dwParam2);
1631     case MODM_GETNUMDEVS:
1632         return MODM_NUMDEVS;
1633     case MODM_GETVOLUME:
1634         return 0;
1635     case MODM_SETVOLUME:
1636         return 0;
1637     case MODM_RESET:
1638         return modReset(wDevID);
1639 #endif
1640     default:
1641         TRACE("Unsupported message\n");
1642     }
1643     return MMSYSERR_NOTSUPPORTED;
1644 }
1645
1646 /*-----------------------------------------------------------------------*/