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