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