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