1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
4 * Sample MIDI Wine Driver for Linux
6 * Copyright 1994 Martin Ayotte
11 * 98/7 changes for making this MIDI driver work on OSS
12 * current support is limited to MIDI ports of OSS systems
13 * 98/9 rewriting MCI code for MIDI
22 #include <sys/ioctl.h>
25 #include "multimedia.h"
40 LPMIDIOPENDESC midiDesc
;
45 unsigned char incoming
[3];
46 unsigned char incPrev
;
58 LPMIDIOPENDESC midiDesc
;
63 void* lpExtra
; /* according to port type (MIDI, FM...), extra data when needed */
68 DWORD dwFirst
; /* offset in file of track */
69 DWORD dwLast
; /* number of bytes in file of track */
70 DWORD dwIndex
; /* current index in file (dwFirst <= dwIndex < dwLast) */
71 DWORD dwLength
; /* number of pulses in this track */
72 DWORD dwEventPulse
; /* current pulse # (event) pointed by dwIndex */
73 DWORD dwEventData
; /* current data (event) pointed by dwIndex */
74 WORD wEventLength
; /* current length (event) pointed by dwIndex */
75 WORD wStatus
: 1, /* 1 : playing, 0 : done */
81 int nUseCount
; /* Incremented for each shared open */
82 BOOL16 fShareable
; /* TRUE if first open was shareable */
83 WORD wNotifyDeviceID
; /* MCI device ID with a pending notification */
84 HANDLE16 hCallback
; /* Callback handle for pending notification */
85 HMMIO32 hFile
; /* mmio file handle open as Element */
90 MCI_OPEN_PARMS16 openParms
;
92 MCI_MIDITRACK
* tracks
;
99 static WINE_MIDIIN MidiInDev
[MAX_MIDIINDRV
];
100 static WINE_MIDIOUT MidiOutDev
[MAX_MIDIOUTDRV
];
101 static WINE_MCIMIDI MCIMidiDev
[MAX_MCIMIDIDRV
];
103 /* this is the total number of MIDI out devices found */
104 int MODM_NUMDEVS
= 0;
105 /* this is the number of FM synthetizers (index from 0 to
106 NUMFMSYNTHDEVS - 1) */
107 int MODM_NUMFMSYNTHDEVS
= 0;
108 /* this is the number of Midi ports (index from NUMFMSYNTHDEVS to
109 NUMFMSYNTHDEVS + NUMMIDIDEVS - 1) */
110 int MODM_NUMMIDIDEVS
= 0;
112 /* this is the total number of MIDI out devices found */
113 int MIDM_NUMDEVS
= 0;
116 static int midiSeqFD
= -1;
117 static int numOpenMidiSeq
= 0;
118 static UINT32 midiInTimerID
= 0;
119 static int numStartedMidiIn
= 0;
120 #endif /* HAVE_OSS */
122 /* this structure holds pointers with information for each MIDI
125 LPMIDIOUTCAPS16 midiOutDevices
[MAX_MIDIOUTDRV
];
127 /* this structure holds pointers with information for each MIDI
130 LPMIDIINCAPS16 midiInDevices
[MAX_MIDIINDRV
];
133 * FIXME : all tests on device ID for midXXX and modYYY are made against
134 * MAX_MIDIxxDRV (when they are made) but should be done against the actual
135 * number of midi devices found...
136 * check also when HAVE_OSS is defined that midiDesc is not NULL
139 /**************************************************************************
140 * MIDI_NotifyClient [internal]
142 static DWORD
MIDI_NotifyClient(UINT16 wDevID
, WORD wMsg
,
143 DWORD dwParam1
, DWORD dwParam2
)
150 TRACE(midi
,"wDevID = %04X wMsg = %d dwParm1 = %04lX dwParam2 = %04lX\n",
151 wDevID
, wMsg
, dwParam1
, dwParam2
);
157 if (wDevID
> MAX_MIDIOUTDRV
)
158 return MCIERR_INTERNAL
;
160 dwCallBack
= MidiOutDev
[wDevID
].midiDesc
->dwCallback
;
161 uFlags
= MidiOutDev
[wDevID
].wFlags
;
162 hDev
= MidiOutDev
[wDevID
].midiDesc
->hMidi
;
163 dwInstance
= MidiOutDev
[wDevID
].midiDesc
->dwInstance
;
170 if (wDevID
> MAX_MIDIINDRV
)
171 return MCIERR_INTERNAL
;
173 dwCallBack
= MidiInDev
[wDevID
].midiDesc
->dwCallback
;
174 uFlags
= MidiInDev
[wDevID
].wFlags
;
175 hDev
= MidiInDev
[wDevID
].midiDesc
->hMidi
;
176 dwInstance
= MidiInDev
[wDevID
].midiDesc
->dwInstance
;
179 WARN(midi
, "Unsupported MSW-MIDI message %u\n", wMsg
);
180 return MCIERR_INTERNAL
;
183 return DriverCallback(dwCallBack
, uFlags
, hDev
, wMsg
, dwInstance
, dwParam1
, dwParam2
) ?
187 /**************************************************************************
188 * MIDI_ReadByte [internal]
190 static DWORD
MIDI_ReadByte(UINT16 wDevID
, BYTE
*lpbyt
)
193 if (mmioRead32(MCIMidiDev
[wDevID
].hFile
, (HPSTR
)lpbyt
,
194 (long) sizeof(BYTE
)) == (long) sizeof(BYTE
)) {
198 WARN(midi
, "error reading wDevID=%04X\n", wDevID
);
199 return MCIERR_INTERNAL
;
203 /**************************************************************************
204 * MIDI_ReadWord [internal]
206 static DWORD
MIDI_ReadWord(UINT16 wDevID
, LPWORD lpw
)
211 if (MIDI_ReadByte(wDevID
, &hibyte
) == 0) {
212 if (MIDI_ReadByte(wDevID
, &lobyte
) == 0) {
213 *lpw
= ((WORD
)hibyte
<< 8) + lobyte
;
218 WARN(midi
, "error reading wDevID=%04X\n", wDevID
);
219 return MCIERR_INTERNAL
;
222 /**************************************************************************
223 * MIDI_ReadLong [internal]
225 static DWORD
MIDI_ReadLong(UINT16 wDevID
, LPDWORD lpdw
)
230 if (MIDI_ReadWord(wDevID
, &hiword
) == 0) {
231 if (MIDI_ReadWord(wDevID
, &loword
) == 0) {
232 *lpdw
= MAKELONG(loword
, hiword
);
237 WARN(midi
, "error reading wDevID=%04X\n", wDevID
);
238 return MCIERR_INTERNAL
;
241 /**************************************************************************
242 * MIDI_ReadVaryLen [internal]
244 static WORD
MIDI_ReadVaryLen(UINT16 wDevID
, LPDWORD lpdw
)
251 return MCIERR_INTERNAL
;
254 if (MIDI_ReadByte(wDevID
, &byte
) != 0) {
255 WARN(midi
, "error reading wDevID=%04X\n", wDevID
);
258 value
= (value
<< 7) + (byte
& 0x7F);
260 } while (byte
& 0x80);
263 TRACE(midi, "val=%08lX \n", value);
268 /**************************************************************************
269 * MIDI_ReadNextEvent [internal]
271 static DWORD
MIDI_ReadNextEvent(UINT16 wDevID
, MCI_MIDITRACK
* mmt
)
279 if (mmioSeek32(MCIMidiDev
[wDevID
].hFile
, mmt
->dwIndex
, SEEK_SET
) != mmt
->dwIndex
) {
280 WARN(midi
, "can't seek at %08lX \n", mmt
->dwIndex
);
281 return MCIERR_INTERNAL
;
283 evtLength
= MIDI_ReadVaryLen(wDevID
, &evtPulse
) + 1; /* > 0 */
284 MIDI_ReadByte(wDevID
, &b1
);
288 evtLength
+= MIDI_ReadVaryLen(wDevID
, &tmp
);
292 MIDI_ReadByte(wDevID
, &b2
); evtLength
++;
294 evtLength
+= MIDI_ReadVaryLen(wDevID
, &tmp
);
295 if (evtLength
>= 0x10000u
) {
296 /* this limitation shouldn't be a problem */
297 WARN(midi
, "Ouch !! Implementation limitation to 64k bytes for a MIDI event is overflowed\n");
300 hw
= LOWORD(evtLength
);
305 if (b1
& 0x80) { // use running status ?
306 mmt
->wLastCommand
= b1
;
307 MIDI_ReadByte(wDevID
, &b2
); evtLength
++;
310 b1
= mmt
->wLastCommand
;
312 switch ((b1
>> 4) & 0x07) {
313 case 0: case 1: case 2: case 3: case 6:
314 MIDI_ReadByte(wDevID
, &b3
); evtLength
++;
320 WARN(midi
, "Strange indeed b1=0x%02x\n", b1
);
324 if (mmt
->dwIndex
+ evtLength
> mmt
->dwLast
)
325 return MCIERR_INTERNAL
;
327 mmt
->dwEventPulse
+= evtPulse
;
328 mmt
->dwEventData
= (hw
<< 16) + (b2
<< 8) + b1
;
329 mmt
->wEventLength
= evtLength
;
332 TRACE(midi, "[%u] => pulse=%08lx(%08lx), data=%08lx, length=%u\n",
333 mmt->wTrackNr, mmt->dwEventPulse, evtPulse,
334 mmt->dwEventData, mmt->wEventLength);
339 /**************************************************************************
340 * MIDI_ReadMTrk [internal]
342 static DWORD
MIDI_ReadMTrk(UINT16 wDevID
, MCI_MIDITRACK
* mmt
)
347 if (mmioRead32(MCIMidiDev
[wDevID
].hFile
, (HPSTR
)&fourcc
,
348 (long) sizeof(FOURCC
)) != (long) sizeof(FOURCC
)) {
349 return MCIERR_INTERNAL
;
352 if (fourcc
!= mmioFOURCC('M', 'T', 'r', 'k')) {
353 WARN(midi
, "cannot synchronize on MTrk !\n");
354 return MCIERR_INTERNAL
;
357 if (MIDI_ReadLong(wDevID
, &toberead
) != 0) {
358 return MCIERR_INTERNAL
;
360 mmt
->dwFirst
= mmioSeek32(MCIMidiDev
[wDevID
].hFile
, 0, SEEK_CUR
); /* >= 0 */
361 mmt
->dwLast
= mmt
->dwFirst
+ toberead
;
363 /* compute # of pulses in this track */
364 mmt
->dwIndex
= mmt
->dwFirst
;
365 mmt
->dwEventPulse
= 0;
366 while (MIDI_ReadNextEvent(wDevID
, mmt
) == 0 &&
367 LOWORD(mmt
->dwEventData
) != 0x2FFF) {
368 mmt
->dwIndex
+= mmt
->wEventLength
;
370 mmt
->dwLength
= mmt
->dwEventPulse
;
372 TRACE(midi
, "Track %u has %lu bytes and %lu pulses\n",
373 mmt
->wTrackNr
, toberead
, mmt
->dwLength
);
375 /* reset track data */
376 mmt
->wStatus
= 1; /* ok, playing */
377 mmt
->dwIndex
= mmt
->dwFirst
;
378 mmt
->dwEventPulse
= 0;
380 if (mmioSeek32(MCIMidiDev
[wDevID
].hFile
, 0, SEEK_CUR
) != mmt
->dwLast
) {
381 WARN(midi
, "Ouch, out of sync seek=%lu track=%lu\n",
382 mmioSeek32(MCIMidiDev
[wDevID
].hFile
, 0, SEEK_CUR
), mmt
->dwLast
);
383 /* position at end of this track, to be ready to read next track */
384 mmioSeek32(MCIMidiDev
[wDevID
].hFile
, mmt
->dwLast
, SEEK_SET
);
390 /**************************************************************************
391 * MIDI_ReadMThd [internal]
393 static DWORD
MIDI_ReadMThd(UINT16 wDevID
, DWORD dwOffset
)
399 TRACE(midi
, "(%04X, %08lX);\n", wDevID
, dwOffset
);
400 if (mmioSeek32(MCIMidiDev
[wDevID
].hFile
, dwOffset
, SEEK_SET
) != dwOffset
) {
401 WARN(midi
, "can't seek at %08lX begin of 'MThd' \n", dwOffset
);
402 return MCIERR_INTERNAL
;
404 if (mmioRead32(MCIMidiDev
[wDevID
].hFile
, (HPSTR
)&fourcc
,
405 (long) sizeof(FOURCC
)) != (long) sizeof(FOURCC
))
406 return MCIERR_INTERNAL
;
408 if (fourcc
!= mmioFOURCC('M', 'T', 'h', 'd')) {
409 WARN(midi
, "cannot synchronize on MThd !\n");
410 return MCIERR_INTERNAL
;
413 if (MIDI_ReadLong(wDevID
, &toberead
) != 0 || toberead
< 3 * sizeof(WORD
))
414 return MCIERR_INTERNAL
;
415 if (MIDI_ReadWord(wDevID
, &MCIMidiDev
[wDevID
].wFormat
) != 0)
416 return MCIERR_INTERNAL
;
417 if (MIDI_ReadWord(wDevID
, &MCIMidiDev
[wDevID
].nTracks
) != 0)
418 return MCIERR_INTERNAL
;
419 if (MIDI_ReadWord(wDevID
, &MCIMidiDev
[wDevID
].nDivision
) != 0)
420 return MCIERR_INTERNAL
;
422 TRACE(midi
, "toberead=0x%08lX, wFormat=0x%04X nTracks=0x%04X nDivision=0x%04X\n",
423 toberead
, MCIMidiDev
[wDevID
].wFormat
,
424 MCIMidiDev
[wDevID
].nTracks
,
425 MCIMidiDev
[wDevID
].nDivision
);
427 if (MCIMidiDev
[wDevID
].nDivision
> 0x8000) {
428 WARN(midi
, "Handling SMPTE time in MIDI files is not (yet) supported\n"
429 "Please report with MIDI file !\n");
430 return MCIERR_INTERNAL
;
433 switch (MCIMidiDev
[wDevID
].wFormat
) {
435 if (MCIMidiDev
[wDevID
].nTracks
!= 1) {
436 WARN(midi
, "Got type 0 file whose number of track is not 1. Setting it to 1\n");
437 MCIMidiDev
[wDevID
].nTracks
= 1;
444 WARN(midi
, "Handling MIDI files which format = %d is not (yet) supported\n"
445 "Please report with MIDI file !\n", MCIMidiDev
[wDevID
].wFormat
);
446 return MCIERR_INTERNAL
;
449 if (MCIMidiDev
[wDevID
].nTracks
& 0x8000) {
450 /* this shouldn't be a problem... */
451 WARN(midi
, "Ouch !! Implementation limitation to 32k tracks per MIDI file is overflowed\n");
452 MCIMidiDev
[wDevID
].nTracks
= 0x7FFF;
454 MCIMidiDev
[wDevID
].tracks
= xmalloc(sizeof(MCI_MIDITRACK
) * MCIMidiDev
[wDevID
].nTracks
);
456 toberead
-= 3 * sizeof(WORD
);
458 TRACE(midi
, "Size of MThd > 6, skipping %ld extra bytes\n", toberead
);
459 mmioSeek32(MCIMidiDev
[wDevID
].hFile
, toberead
, SEEK_CUR
);
462 for (nt
= 0; nt
< MCIMidiDev
[wDevID
].nTracks
; nt
++) {
463 MCIMidiDev
[wDevID
].tracks
[nt
].wTrackNr
= nt
;
464 if (MIDI_ReadMTrk(wDevID
, &MCIMidiDev
[wDevID
].tracks
[nt
]) != 0) {
465 WARN(midi
, "can't read 'MTrk' header \n");
466 return MCIERR_INTERNAL
;
473 /**************************************************************************
474 * MIDI_mciOpen [internal]
476 static DWORD
MIDI_mciOpen(UINT16 wDevID
, DWORD dwFlags
, void* lp
, BOOL32 is32
)
478 MIDIOPENDESC MidiDesc
;
482 TRACE(midi
, "(%08lX, %p)\n", dwFlags
, lp
);
484 if (lp
== NULL
) return MCIERR_INTERNAL
;
486 if (MCIMidiDev
[wDevID
].nUseCount
> 0) {
487 /* The driver already open on this channel */
488 /* If the driver was opened shareable before and this open specifies */
489 /* shareable then increment the use count */
490 if (MCIMidiDev
[wDevID
].fShareable
&& (dwFlags
& MCI_OPEN_SHAREABLE
))
491 ++MCIMidiDev
[wDevID
].nUseCount
;
493 return MCIERR_MUST_USE_SHAREABLE
;
495 MCIMidiDev
[wDevID
].nUseCount
= 1;
496 MCIMidiDev
[wDevID
].fShareable
= dwFlags
& MCI_OPEN_SHAREABLE
;
497 MCIMidiDev
[wDevID
].hMidiHdr
= USER_HEAP_ALLOC(sizeof(MIDIHDR
));
500 if (is32
) dwDeviceID
= ((LPMCI_OPEN_PARMS32A
)lp
)->wDeviceID
;
501 else dwDeviceID
= ((LPMCI_OPEN_PARMS16
)lp
)->wDeviceID
;
503 TRACE(midi
, "wDevID=%04X (lpParams->wDeviceID=%08lX)\n", wDevID
, dwDeviceID
);
504 /* lpParms->wDeviceID = wDevID;*/
505 TRACE(midi
, "before OPEN_ELEMENT\n");
506 if (dwFlags
& MCI_OPEN_ELEMENT
) {
507 LPSTR lpstrElementName
;
509 if (is32
) lpstrElementName
= ((LPMCI_OPEN_PARMS32A
)lp
)->lpstrElementName
;
510 else lpstrElementName
= (LPSTR
)PTR_SEG_TO_LIN(((LPMCI_OPEN_PARMS16
)lp
)->lpstrElementName
);
512 TRACE(midi
, "MCI_OPEN_ELEMENT '%s' !\n", lpstrElementName
);
513 if (strlen(lpstrElementName
) > 0) {
514 MCIMidiDev
[wDevID
].hFile
= mmioOpen32A(lpstrElementName
, NULL
,
515 MMIO_ALLOCBUF
| MMIO_READWRITE
| MMIO_EXCLUSIVE
);
516 if (MCIMidiDev
[wDevID
].hFile
== 0) {
517 WARN(midi
, "can't find file='%s' !\n", lpstrElementName
);
518 return MCIERR_FILE_NOT_FOUND
;
521 MCIMidiDev
[wDevID
].hFile
= 0;
523 TRACE(midi
, "hFile=%u\n", MCIMidiDev
[wDevID
].hFile
);
525 /* should be of same size in all cases */
526 memcpy(&MCIMidiDev
[wDevID
].openParms
, lp
, sizeof(MCI_OPEN_PARMS16
));
528 MCIMidiDev
[wDevID
].wNotifyDeviceID
= dwDeviceID
;
529 MCIMidiDev
[wDevID
].dwStatus
= MCI_MODE_STOP
;
532 if (MCIMidiDev
[wDevID
].hFile
!= 0) {
536 if (mmioDescend(MCIMidiDev
[wDevID
].hFile
, &ckMainRIFF
, NULL
, 0) != 0) {
537 return MCIERR_INTERNAL
;
539 TRACE(midi
,"ParentChunk ckid=%.4s fccType=%.4s cksize=%08lX \n",
540 (LPSTR
)&ckMainRIFF
.ckid
, (LPSTR
)&ckMainRIFF
.fccType
,
543 if (ckMainRIFF
.ckid
== mmioFOURCC('R', 'M', 'I', 'D')) {
544 TRACE(midi
, "is a 'RMID' file \n");
545 dwOffset
= ckMainRIFF
.dwDataOffset
;
546 FIXME(midi
, "Setting #tracks for RMID to 1: is this correct ?\n");
547 MCIMidiDev
[wDevID
].nTracks
= 1;
549 if (MIDI_ReadMThd(wDevID
, dwOffset
) != 0) {
550 WARN(midi
, "can't read 'MThd' header \n");
551 return MCIERR_INTERNAL
;
554 TRACE(midi
, "Chunk Found ckid=%.4s fccType=%.4s cksize=%08lX \n",
555 (LPSTR
)&ckMainRIFF
.ckid
, (LPSTR
)&ckMainRIFF
.fccType
,
559 dwRet
= modMessage(wDevID
, MODM_OPEN
, 0, (DWORD
)&MidiDesc
, CALLBACK_NULL
);
560 /* dwRet = midMessage(wDevID, MIDM_OPEN, 0, (DWORD)&MidiDesc, CALLBACK_NULL);*/
565 static DWORD
MIDI_ConvertPulseToMS(UINT16 wDevID
, DWORD pulse
)
567 DWORD ret
= (DWORD
)((double)pulse
* ((double)MCIMidiDev
[wDevID
].dwTempo
/ 1000) /
568 (double)MCIMidiDev
[wDevID
].nDivision
);
571 TRACE(midi, "pulse=%lu tempo=%lu division=%u => ms=%lu\n",
572 pulse, MCIMidiDev[wDevID].dwTempo, MCIMidiDev[wDevID].nDivision, ret);
577 /**************************************************************************
578 * MIDI_mciStop [internal]
580 static DWORD
MIDI_mciStop(UINT16 wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
582 TRACE(midi
, "(%04X, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
584 if (wDevID
>= MAX_MCIMIDIDRV
|| MCIMidiDev
[wDevID
].nUseCount
== 0) {
585 WARN(midi
, "Invalid wDevID=%u\n", wDevID
);
586 return MCIERR_INVALID_DEVICE_ID
;
589 MCIMidiDev
[wDevID
].dwStatus
= MCI_MODE_STOP
;
590 TRACE(midi
, "MCIMidiDev[wDevID].dwStatus=%d\n", MCIMidiDev
[wDevID
].dwStatus
);
591 if (lpParms
&& (dwFlags
& MCI_NOTIFY
)) {
592 TRACE(midi
, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
593 mciDriverNotify((HWND16
)LOWORD(lpParms
->dwCallback
),
594 MCIMidiDev
[wDevID
].wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
599 /**************************************************************************
600 * MIDI_mciClose [internal]
602 static DWORD
MIDI_mciClose(UINT16 wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
606 TRACE(midi
, "(%04X, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
608 if (wDevID
>= MAX_MCIMIDIDRV
|| MCIMidiDev
[wDevID
].nUseCount
== 0) {
609 WARN(midi
, "Invalid wDevID=%u\n", wDevID
);
610 return MCIERR_INVALID_DEVICE_ID
;
613 if (MCIMidiDev
[wDevID
].dwStatus
!= MCI_MODE_STOP
) {
614 MIDI_mciStop(wDevID
, MCI_WAIT
, lpParms
);
617 MCIMidiDev
[wDevID
].dwStatus
= MCI_MODE_STOP
;
618 MCIMidiDev
[wDevID
].nUseCount
--;
619 if (MCIMidiDev
[wDevID
].nUseCount
== 0) {
620 if (MCIMidiDev
[wDevID
].hFile
!= 0) {
621 mmioClose32(MCIMidiDev
[wDevID
].hFile
, 0);
622 MCIMidiDev
[wDevID
].hFile
= 0;
623 TRACE(midi
, "hFile closed !\n");
625 USER_HEAP_FREE(MCIMidiDev
[wDevID
].hMidiHdr
);
626 free(MCIMidiDev
[wDevID
].tracks
);
627 dwRet
= modMessage(wDevID
, MODM_CLOSE
, 0, 0L, 0L);
628 if (dwRet
!= MMSYSERR_NOERROR
) return MCIERR_INTERNAL
;
630 dwRet = midMessage(wDevID, MIDM_CLOSE, 0, 0L, 0L);
631 if (dwRet != MMSYSERR_NOERROR) return MCIERR_INTERNAL;
634 if (lpParms
&& (dwFlags
& MCI_NOTIFY
)) {
635 TRACE(midi
, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
636 mciDriverNotify((HWND16
)LOWORD(lpParms
->dwCallback
),
637 MCIMidiDev
[wDevID
].wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
642 /**************************************************************************
643 * MIDI_mciPlay [internal]
645 static DWORD
MIDI_mciPlay(UINT16 wDevID
, DWORD dwFlags
, LPMCI_PLAY_PARMS lpParms
)
647 DWORD start
= 0, end
= 0xFFFFFFFFul
;
651 TRACE(midi
, "(%04X, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
653 if (wDevID
>= MAX_MCIMIDIDRV
|| MCIMidiDev
[wDevID
].nUseCount
== 0) {
654 WARN(midi
, "Invalid wDevID=%u\n", wDevID
);
655 return MCIERR_INVALID_DEVICE_ID
;
658 if (MCIMidiDev
[wDevID
].hFile
== 0) {
659 WARN(midi
, "Cannot play : can't find file='%08lx' !\n",
660 (DWORD
)MCIMidiDev
[wDevID
].openParms
.lpstrElementName
);
661 return MCIERR_FILE_NOT_FOUND
;
664 if (MCIMidiDev
[wDevID
].dwStatus
!= MCI_MODE_STOP
) {
665 WARN(midi
, "Cannot play : device is not stopped !\n");
666 return MCIERR_INTERNAL
;
669 if (lpParms
&& (dwFlags
& MCI_FROM
)) {
670 start
= lpParms
->dwFrom
;
671 FIXME(midi
, "MCI_FROM=%lu \n", start
);
673 if (lpParms
&& (dwFlags
& MCI_TO
)) {
675 FIXME(midi
, "MCI_TO=%lu \n", end
);
678 if (!(dwFlags
& MCI_WAIT
)) {
679 /** FIXME: I'm not 100% sure that wNotifyDeviceID is the right value in all cases ??? */
680 return mciSendCommandAsync32(MCIMidiDev
[wDevID
].wNotifyDeviceID
, MCI_PLAY
, dwFlags
, (DWORD
)lpParms
);
684 for (nt
= 0; nt
< MCIMidiDev
[wDevID
].nTracks
; nt
++) {
685 MCI_MIDITRACK
* mmt
= &MCIMidiDev
[wDevID
].tracks
[nt
];
687 mmt
->wStatus
= 1; /* ok, playing */
688 mmt
->dwIndex
= mmt
->dwFirst
;
689 if (MCIMidiDev
[wDevID
].wFormat
== 2 && nt
> 0) {
690 mmt
->dwEventPulse
= MCIMidiDev
[wDevID
].tracks
[nt
- 1].dwLength
;
692 mmt
->dwEventPulse
= 0;
694 MIDI_ReadNextEvent(wDevID
, mmt
); /* FIXME == 0 */
697 MCIMidiDev
[wDevID
].dwPulse
= 0;
698 MCIMidiDev
[wDevID
].dwPositionMS
= 0;
699 MCIMidiDev
[wDevID
].dwStartTicks
= GetTickCount();
700 MCIMidiDev
[wDevID
].dwTempo
= 500000;
701 MCIMidiDev
[wDevID
].dwStatus
= MCI_MODE_PLAY
;
703 while (MCIMidiDev
[wDevID
].dwStatus
!= MCI_MODE_STOP
) {
707 TRACE(midi
, "MCIMidiDev[wDevID].dwStatus=%p %d\n",
708 &MCIMidiDev
[wDevID
].dwStatus
, MCIMidiDev
[wDevID
].dwStatus
);
710 while (MCIMidiDev
[wDevID
].dwStatus
== MCI_MODE_PAUSE
);
712 /* find first event */
713 hiPulse
= 0xFFFFFFFFul
;
715 for (nt
= 0; nt
< MCIMidiDev
[wDevID
].nTracks
; nt
++) {
716 mmt
= &MCIMidiDev
[wDevID
].tracks
[nt
];
718 if (mmt
->wStatus
== 0)
720 if (mmt
->dwEventPulse
< hiPulse
) {
721 hiPulse
= mmt
->dwEventPulse
;
725 if (cnt
== 0xFFFFu
) /* no more event on tracks */
728 mmt
= &MCIMidiDev
[wDevID
].tracks
[cnt
];
729 if (hiPulse
> MCIMidiDev
[wDevID
].dwPulse
) {
730 DWORD togo
= MCIMidiDev
[wDevID
].dwStartTicks
+
731 MIDI_ConvertPulseToMS(wDevID
, hiPulse
);
732 DWORD tc
= GetTickCount();
734 TRACE(midi
, "Pulses hi=0x%08lx <> cur=0x%08lx\n", hiPulse
, MCIMidiDev
[wDevID
].dwPulse
);
735 TRACE(midi
, "Wait til %08lx -> %08lx ms\n",
736 tc
- MCIMidiDev
[wDevID
].dwStartTicks
,
737 togo
- MCIMidiDev
[wDevID
].dwStartTicks
);
738 if (tc
< togo
) Sleep(togo
- tc
);
739 MCIMidiDev
[wDevID
].dwPositionMS
+= MIDI_ConvertPulseToMS(wDevID
, hiPulse
- MCIMidiDev
[wDevID
].dwPulse
);
740 MCIMidiDev
[wDevID
].dwPulse
= hiPulse
;
743 switch (LOBYTE(LOWORD(mmt
->dwEventData
))) {
745 case 0xF7: /* sysex events */
746 FIXME(midi
, "Not handling SysEx events (yet)\n");
749 /* position after meta data header */
750 mmioSeek32(MCIMidiDev
[wDevID
].hFile
, mmt
->dwIndex
+ HIWORD(mmt
->dwEventData
), SEEK_SET
);
751 switch (HIBYTE(LOWORD(mmt
->dwEventData
))) {
752 case 0x00: /* 16-bit sequence number */
753 if (TRACE_ON(midi
)) {
756 MIDI_ReadWord(wDevID
, &twd
); /* == 0 */
757 TRACE(midi
, "Got sequence number %u\n", twd
);
760 case 0x01: /* any text */
761 case 0x02: /* Copyright Message text */
762 case 0x03: /* Sequence/Track Name text */
763 case 0x04: /* Instrument Name text */
764 case 0x05: /* Lyric text */
765 case 0x06: /* Marker text */
766 case 0x07: /* Cue-point text */
767 if (TRACE_ON(midi
)) {
769 WORD len
= mmt
->wEventLength
- HIWORD(mmt
->dwEventData
);
770 static char* info
[8] = {"", "Text", "Copyright", "Seq/Trk name",
771 "Instrument", "Lyric", "Marker", "Cue-point"};
772 WORD idx
= HIBYTE(LOWORD(mmt
->dwEventData
));
774 if (len
>= sizeof(buf
)) {
775 WARN(midi
, "Buffer for text is too small (%d bytes, when %u are needed)\n", sizeof(buf
) - 1, len
);
776 len
= sizeof(buf
) - 1;
778 if (mmioRead32(MCIMidiDev
[wDevID
].hFile
, (HPSTR
)buf
, len
) == len
) {
779 buf
[len
] = 0; /* end string in case */
780 TRACE(midi
, "%s => \"%s\"\n", (idx
< 8 ) ? info
[idx
] : "", buf
);
782 WARN(midi
, "Couldn't read data for %s\n", (idx
< 8 ) ? info
[idx
] : "");
790 if (TRACE_ON(midi
)) {
793 MIDI_ReadByte(wDevID
, &bt
); /* == 0 */
794 FIXME(midi
, "NIY: MIDI channel %u\n", bt
);
797 FIXME(midi
, "NIY: MIDI channel\n");
804 if (TRACE_ON(midi
)) {
807 MIDI_ReadByte(wDevID
, &bt
); /* == 0 */
808 FIXME(midi
, "NIY: MIDI port %u\n", bt
);
810 FIXME(midi
, "NIY: MIDI port\n");
813 case 0x2F: /* end of track */
816 case 0x51:/* set tempo */
817 /* Tempo is expressed in µ-seconds per midi quarter note
818 * for format 1 MIDI files, this can only be present on track #0
820 if (mmt
->wTrackNr
!= 0 && MCIMidiDev
[wDevID
].wFormat
== 1) {
821 WARN(midi
, "For format #1 MIDI files, tempo can only be changed on track #0 (%u)\n", mmt
->wTrackNr
);
825 MIDI_ReadByte(wDevID
, &tbt
); MCIMidiDev
[wDevID
].dwTempo
= ((DWORD
)tbt
) << 16;
826 MIDI_ReadByte(wDevID
, &tbt
); MCIMidiDev
[wDevID
].dwTempo
|= ((DWORD
)tbt
) << 8;
827 MIDI_ReadByte(wDevID
, &tbt
); MCIMidiDev
[wDevID
].dwTempo
|= ((DWORD
)tbt
) << 0;
828 TRACE(midi
, "Setting tempo to %ld (BPM=%ld)\n", MCIMidiDev
[wDevID
].dwTempo
, 60000000l / MCIMidiDev
[wDevID
].dwTempo
);
832 case 0x54: /* (hour) (min) (second) (frame) (fractional-frame) - SMPTE track start */
833 FIXME(midi
, "NIY: SMPTE track start\n");
836 if (TRACE_ON(midi
)) {
837 BYTE num
, den
, cpmc
, _32npqn
;
839 MIDI_ReadByte(wDevID
, &num
);
840 MIDI_ReadByte(wDevID
, &den
); /* to notate e.g. 6/8 */
841 MIDI_ReadByte(wDevID
, &cpmc
); /* number of MIDI clocks per metronome click */
842 MIDI_ReadByte(wDevID
, &_32npqn
); /* number of notated 32nd notes per MIDI quarter note */
844 TRACE(midi
, "%u/%u, clock per metronome click=%u, 32nd notes by 1/4 note=%u\n", num
, 1 << den
, cpmc
, _32npqn
);
848 if (TRACE_ON(midi
)) {
851 MIDI_ReadByte(wDevID
, &sf
); MIDI_ReadByte(wDevID
, &mm
);
853 if (sf
>= 0x80) TRACE(midi
, "%d flats\n", -(char)sf
);
854 else if (sf
> 0) TRACE(midi
, "%d sharps\n", (char)sf
);
855 else TRACE(midi
, "Key of C\n");
856 TRACE(midi
, "Mode: %s\n", (mm
= 0) ? "major" : "minor");
860 WARN(midi
, "Unknown MIDI meta event %02x. Skipping...\n", HIBYTE(LOWORD(mmt
->dwEventData
)));
865 dwRet
= modMessage(wDevID
, MODM_DATA
, 0, mmt
->dwEventData
, 0);
867 mmt
->dwIndex
+= mmt
->wEventLength
;
868 if (mmt
->dwIndex
< mmt
->dwFirst
|| mmt
->dwIndex
>= mmt
->dwLast
) {
872 MIDI_ReadNextEvent(wDevID
, mmt
);
878 modMessage(wDevID
, MODM_DATA
, 0, (MIDI_CTL_CHANGE
<< 8) | 0x78, 0);
880 MCIMidiDev
[wDevID
].dwStatus
= MCI_MODE_STOP
;
881 if (lpParms
&& (dwFlags
& MCI_NOTIFY
)) {
882 TRACE(midi
, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
883 mciDriverNotify((HWND16
)LOWORD(lpParms
->dwCallback
),
884 MCIMidiDev
[wDevID
].wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
889 /**************************************************************************
890 * MIDI_mciRecord [internal]
892 static DWORD
MIDI_mciRecord(UINT16 wDevID
, DWORD dwFlags
, LPMCI_RECORD_PARMS lpParms
)
898 TRACE(midi
, "(%04X, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
900 if (wDevID
>= MAX_MCIMIDIDRV
|| MCIMidiDev
[wDevID
].nUseCount
== 0) {
901 WARN(midi
, "Invalid wDevID=%u\n", wDevID
);
902 return MCIERR_INVALID_DEVICE_ID
;
905 if (MCIMidiDev
[wDevID
].hFile
== 0) {
906 WARN(midi
, "can't find file='%08lx' !\n",
907 (DWORD
)MCIMidiDev
[wDevID
].openParms
.lpstrElementName
);
908 return MCIERR_FILE_NOT_FOUND
;
910 start
= 1; end
= 99999;
911 if (lpParms
&& (dwFlags
& MCI_FROM
)) {
912 start
= lpParms
->dwFrom
;
913 TRACE(midi
, "MCI_FROM=%d \n", start
);
915 if (lpParms
&& (dwFlags
& MCI_TO
)) {
917 TRACE(midi
, "MCI_TO=%d \n", end
);
919 lpMidiHdr
= USER_HEAP_LIN_ADDR(MCIMidiDev
[wDevID
].hMidiHdr
);
920 lpMidiHdr
->lpData
= (LPSTR
) xmalloc(1200);
921 lpMidiHdr
->dwBufferLength
= 1024;
922 lpMidiHdr
->dwUser
= 0L;
923 lpMidiHdr
->dwFlags
= 0L;
924 dwRet
= midMessage(wDevID
, MIDM_PREPARE
, 0, (DWORD
)lpMidiHdr
, sizeof(MIDIHDR
));
925 TRACE(midi
, "after MIDM_PREPARE \n");
926 MCIMidiDev
[wDevID
].dwStatus
= MCI_MODE_RECORD
;
927 while (MCIMidiDev
[wDevID
].dwStatus
!= MCI_MODE_STOP
) {
928 TRACE(midi
, "MCIMidiDev[wDevID].dwStatus=%p %d\n",
929 &MCIMidiDev
[wDevID
].dwStatus
, MCIMidiDev
[wDevID
].dwStatus
);
930 lpMidiHdr
->dwBytesRecorded
= 0;
931 dwRet
= midMessage(wDevID
, MIDM_START
, 0, 0L, 0L);
932 TRACE(midi
, "after MIDM_START lpMidiHdr=%p dwBytesRecorded=%lu\n",
933 lpMidiHdr
, lpMidiHdr
->dwBytesRecorded
);
934 if (lpMidiHdr
->dwBytesRecorded
== 0) break;
936 TRACE(midi
, "before MIDM_UNPREPARE \n");
937 dwRet
= midMessage(wDevID
, MIDM_UNPREPARE
, 0, (DWORD
)lpMidiHdr
, sizeof(MIDIHDR
));
938 TRACE(midi
, "after MIDM_UNPREPARE \n");
939 if (lpMidiHdr
->lpData
!= NULL
) {
940 free(lpMidiHdr
->lpData
);
941 lpMidiHdr
->lpData
= NULL
;
943 MCIMidiDev
[wDevID
].dwStatus
= MCI_MODE_STOP
;
944 if (lpParms
&& (dwFlags
& MCI_NOTIFY
)) {
945 TRACE(midi
, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
946 mciDriverNotify((HWND16
)LOWORD(lpParms
->dwCallback
),
947 MCIMidiDev
[wDevID
].wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
952 /**************************************************************************
953 * MIDI_mciPause [internal]
955 static DWORD
MIDI_mciPause(UINT16 wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
957 TRACE(midi
, "(%04X, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
959 if (wDevID
>= MAX_MCIMIDIDRV
|| MCIMidiDev
[wDevID
].nUseCount
== 0) {
960 WARN(midi
, "Invalid wDevID=%u\n", wDevID
);
961 return MCIERR_INVALID_DEVICE_ID
;
964 if (MCIMidiDev
[wDevID
].dwStatus
== MCI_MODE_PLAY
) {
965 MCIMidiDev
[wDevID
].dwStatus
= MCI_MODE_PAUSE
;
967 if (lpParms
&& (dwFlags
& MCI_NOTIFY
)) {
968 TRACE(midi
, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
969 mciDriverNotify((HWND16
)LOWORD(lpParms
->dwCallback
),
970 MCIMidiDev
[wDevID
].wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
976 /**************************************************************************
977 * MIDI_mciResume [internal]
979 static DWORD
MIDI_mciResume(UINT16 wDevID
, DWORD dwFlags
, LPMCI_GENERIC_PARMS lpParms
)
981 TRACE(midi
, "(%04X, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
983 if (wDevID
>= MAX_MCIMIDIDRV
|| MCIMidiDev
[wDevID
].nUseCount
== 0) {
984 WARN(midi
, "Invalid wDevID=%u\n", wDevID
);
985 return MCIERR_INVALID_DEVICE_ID
;
988 if (MCIMidiDev
[wDevID
].dwStatus
== MCI_MODE_PAUSE
) {
989 MCIMidiDev
[wDevID
].dwStatus
= MCI_MODE_PLAY
;
991 if (lpParms
&& (dwFlags
& MCI_NOTIFY
)) {
992 TRACE(midi
, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
993 mciDriverNotify((HWND16
)LOWORD(lpParms
->dwCallback
),
994 MCIMidiDev
[wDevID
].wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
999 /**************************************************************************
1000 * MIDI_mciSet [internal]
1002 static DWORD
MIDI_mciSet(UINT16 wDevID
, DWORD dwFlags
, LPMCI_SET_PARMS lpParms
)
1004 TRACE(midi
, "(%04X, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
1006 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
1008 if (wDevID
>= MAX_MCIMIDIDRV
|| MCIMidiDev
[wDevID
].nUseCount
== 0) {
1009 WARN(midi
, "Invalid wDevID=%u\n", wDevID
);
1010 return MCIERR_INVALID_DEVICE_ID
;
1013 TRACE(midi
, "dwTimeFormat=%08lX\n", lpParms
->dwTimeFormat
);
1014 TRACE(midi
, "dwAudio=%08lX\n", lpParms
->dwAudio
);
1016 if (dwFlags
& MCI_SET_TIME_FORMAT
) {
1017 switch (lpParms
->dwTimeFormat
) {
1018 case MCI_FORMAT_MILLISECONDS
:
1019 TRACE(midi
, "MCI_FORMAT_MILLISECONDS !\n");
1021 case MCI_FORMAT_BYTES
:
1022 TRACE(midi
, "MCI_FORMAT_BYTES !\n");
1024 case MCI_FORMAT_SAMPLES
:
1025 TRACE(midi
, "MCI_FORMAT_SAMPLES !\n");
1028 WARN(midi
, "bad time format !\n");
1029 return MCIERR_BAD_TIME_FORMAT
;
1032 if (dwFlags
& MCI_SET_VIDEO
) {
1033 TRACE(midi
, "No support for video !\n");
1034 return MCIERR_UNSUPPORTED_FUNCTION
;
1036 if (dwFlags
& MCI_SET_DOOR_OPEN
) {
1037 TRACE(midi
, "No support for door open !\n");
1038 return MCIERR_UNSUPPORTED_FUNCTION
;
1040 if (dwFlags
& MCI_SET_DOOR_CLOSED
) {
1041 TRACE(midi
, "No support for door close !\n");
1042 return MCIERR_UNSUPPORTED_FUNCTION
;
1045 if (dwFlags
&& MCI_SET_ON
) {
1046 TRACE(midi
, "MCI_SET_ON !\n");
1047 if (dwFlags
& MCI_SET_AUDIO
) {
1048 TRACE(midi
, "MCI_SET_AUDIO !\n");
1050 if (dwFlags
&& MCI_SET_AUDIO_LEFT
)
1051 TRACE(midi
, "MCI_SET_AUDIO_LEFT !\n");
1052 if (dwFlags
&& MCI_SET_AUDIO_RIGHT
)
1053 TRACE(midi
, "MCI_SET_AUDIO_RIGHT !\n");
1055 if (dwFlags
& MCI_SET_OFF
) {
1056 TRACE(midi
, "MCI_SET_OFF !\n");
1057 if (dwFlags
& MCI_SET_AUDIO
) {
1058 TRACE(midi
, "MCI_SET_AUDIO !\n");
1060 if (dwFlags
&& MCI_SET_AUDIO_LEFT
)
1061 TRACE(midi
, "MCI_SET_AUDIO_LEFT !\n");
1062 if (dwFlags
&& MCI_SET_AUDIO_RIGHT
)
1063 TRACE(midi
, "MCI_SET_AUDIO_RIGHT !\n");
1065 if (dwFlags
& MCI_SEQ_SET_MASTER
)
1066 TRACE(midi
, "MCI_SEQ_SET_MASTER !\n");
1067 if (dwFlags
& MCI_SEQ_SET_SLAVE
)
1068 TRACE(midi
, "MCI_SEQ_SET_SLAVE !\n");
1069 if (dwFlags
& MCI_SEQ_SET_OFFSET
)
1070 TRACE(midi
, "MCI_SEQ_SET_OFFSET !\n");
1071 if (dwFlags
& MCI_SEQ_SET_PORT
)
1072 TRACE(midi
, "MCI_SEQ_SET_PORT !\n");
1073 if (dwFlags
& MCI_SEQ_SET_TEMPO
)
1074 TRACE(midi
, "MCI_SEQ_SET_TEMPO !\n");
1078 /**************************************************************************
1079 * MIDI_mciStatus [internal]
1081 static DWORD
MIDI_mciStatus(UINT16 wDevID
, DWORD dwFlags
, LPMCI_STATUS_PARMS lpParms
)
1083 TRACE(midi
, "(%04X, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
1085 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
1087 if (wDevID
>= MAX_MCIMIDIDRV
|| MCIMidiDev
[wDevID
].nUseCount
== 0) {
1088 WARN(midi
, "Invalid wDevID=%u\n", wDevID
);
1089 return MCIERR_INVALID_DEVICE_ID
;
1092 if (dwFlags
& MCI_STATUS_ITEM
) {
1093 switch (lpParms
->dwItem
) {
1094 case MCI_STATUS_CURRENT_TRACK
:
1095 TRACE(midi
, "MCI_STATUS_CURRENT_TRACK !\n");
1096 lpParms
->dwReturn
= 1;
1098 case MCI_STATUS_LENGTH
:
1099 TRACE(midi
, "MCI_STATUS_LENGTH !\n");
1104 for (nt
= 0; nt
< MCIMidiDev
[wDevID
].nTracks
; nt
++) {
1105 if (MCIMidiDev
[wDevID
].wFormat
== 2) {
1106 ret
+= MCIMidiDev
[wDevID
].tracks
[nt
].dwLength
;
1108 if (MCIMidiDev
[wDevID
].tracks
[nt
].dwLength
> ret
)
1109 ret
= MCIMidiDev
[wDevID
].tracks
[nt
].dwLength
;
1112 lpParms
->dwReturn
= MIDI_ConvertPulseToMS(wDevID
, ret
);
1115 case MCI_STATUS_MODE
:
1116 TRACE(midi
, "MCI_STATUS_MODE !\n");
1117 lpParms
->dwReturn
= MCIMidiDev
[wDevID
].dwStatus
;
1119 case MCI_STATUS_MEDIA_PRESENT
:
1120 TRACE(midi
, "MCI_STATUS_MEDIA_PRESENT !\n");
1121 lpParms
->dwReturn
= TRUE
;
1123 case MCI_STATUS_NUMBER_OF_TRACKS
:
1124 TRACE(midi
, "MCI_STATUS_NUMBER_OF_TRACKS !\n");
1125 lpParms
->dwReturn
= 1; /* FIXME: except in format 2 */
1127 case MCI_STATUS_POSITION
:
1128 TRACE(midi
, "MCI_STATUS_POSITION !\n");
1129 if (dwFlags
& MCI_STATUS_START
) {
1130 lpParms
->dwReturn
= 0;
1132 lpParms
->dwReturn
= MCIMidiDev
[wDevID
].dwPositionMS
;
1135 case MCI_STATUS_READY
:
1136 TRACE(midi
, "MCI_STATUS_READY !\n");
1137 lpParms
->dwReturn
= TRUE
;
1139 case MCI_STATUS_TIME_FORMAT
:
1140 TRACE(midi
, "MCI_STATUS_TIME_FORMAT !\n");
1141 lpParms
->dwReturn
= MCI_FORMAT_MILLISECONDS
;
1143 case MCI_SEQ_STATUS_DIVTYPE
:
1144 TRACE(midi
, "MCI_SEQ_STATUS_DIVTYPE !\n");
1145 lpParms
->dwReturn
= MCI_SEQ_DIV_PPQN
;
1147 case MCI_SEQ_STATUS_MASTER
:
1148 TRACE(midi
, "MCI_SEQ_STATUS_MASTER !\n");
1149 lpParms
->dwReturn
= 0;
1151 case MCI_SEQ_STATUS_SLAVE
:
1152 TRACE(midi
, "MCI_SEQ_STATUS_SLAVE !\n");
1153 lpParms
->dwReturn
= 0;
1155 case MCI_SEQ_STATUS_OFFSET
:
1156 TRACE(midi
, "MCI_SEQ_STATUS_OFFSET !\n");
1157 lpParms
->dwReturn
= 0;
1159 case MCI_SEQ_STATUS_PORT
:
1160 TRACE(midi
, "MCI_SEQ_STATUS_PORT !\n");
1161 lpParms
->dwReturn
= 0;
1163 case MCI_SEQ_STATUS_TEMPO
:
1164 TRACE(midi
, "MCI_SEQ_STATUS_TEMPO !\n");
1165 lpParms
->dwReturn
= MCIMidiDev
[wDevID
].dwTempo
;
1168 WARN(midi
, "unknowm command %08lX !\n", lpParms
->dwItem
);
1169 return MCIERR_UNRECOGNIZED_COMMAND
;
1172 WARN(midi
, "No Status-Item!\n");
1173 return MCIERR_UNRECOGNIZED_COMMAND
;
1175 if (dwFlags
& MCI_NOTIFY
) {
1176 TRACE(midi
, "MCI_NOTIFY_SUCCESSFUL %08lX !\n", lpParms
->dwCallback
);
1177 mciDriverNotify((HWND16
)LOWORD(lpParms
->dwCallback
),
1178 MCIMidiDev
[wDevID
].wNotifyDeviceID
, MCI_NOTIFY_SUCCESSFUL
);
1183 /**************************************************************************
1184 * MIDI_mciGetDevCaps [internal]
1186 static DWORD
MIDI_mciGetDevCaps(UINT16 wDevID
, DWORD dwFlags
,
1187 LPMCI_GETDEVCAPS_PARMS lpParms
)
1189 TRACE(midi
, "(%04X, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
1191 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
1193 if (wDevID
>= MAX_MCIMIDIDRV
|| MCIMidiDev
[wDevID
].nUseCount
== 0) {
1194 WARN(midi
, "Invalid wDevID=%u\n", wDevID
);
1195 return MCIERR_INVALID_DEVICE_ID
;
1198 if (dwFlags
& MCI_GETDEVCAPS_ITEM
) {
1199 switch (lpParms
->dwItem
) {
1200 case MCI_GETDEVCAPS_CAN_RECORD
:
1201 TRACE(midi
, "MCI_GETDEVCAPS_CAN_RECORD !\n");
1202 lpParms
->dwReturn
= TRUE
;
1204 case MCI_GETDEVCAPS_HAS_AUDIO
:
1205 TRACE(midi
, "MCI_GETDEVCAPS_HAS_AUDIO !\n");
1206 lpParms
->dwReturn
= TRUE
;
1208 case MCI_GETDEVCAPS_HAS_VIDEO
:
1209 TRACE(midi
, "MCI_GETDEVCAPS_HAS_VIDEO !\n");
1210 lpParms
->dwReturn
= FALSE
;
1212 case MCI_GETDEVCAPS_DEVICE_TYPE
:
1213 TRACE(midi
, "MCI_GETDEVCAPS_DEVICE_TYPE !\n");
1214 lpParms
->dwReturn
= MCI_DEVTYPE_SEQUENCER
;
1216 case MCI_GETDEVCAPS_USES_FILES
:
1217 TRACE(midi
, "MCI_GETDEVCAPS_USES_FILES !\n");
1218 lpParms
->dwReturn
= TRUE
;
1220 case MCI_GETDEVCAPS_COMPOUND_DEVICE
:
1221 TRACE(midi
, "MCI_GETDEVCAPS_COMPOUND_DEVICE !\n");
1222 lpParms
->dwReturn
= TRUE
;
1224 case MCI_GETDEVCAPS_CAN_EJECT
:
1225 TRACE(midi
, "MCI_GETDEVCAPS_CAN_EJECT !\n");
1226 lpParms
->dwReturn
= FALSE
;
1228 case MCI_GETDEVCAPS_CAN_PLAY
:
1229 TRACE(midi
, "MCI_GETDEVCAPS_CAN_PLAY !\n");
1230 lpParms
->dwReturn
= TRUE
;
1232 case MCI_GETDEVCAPS_CAN_SAVE
:
1233 TRACE(midi
, "MCI_GETDEVCAPS_CAN_SAVE !\n");
1234 lpParms
->dwReturn
= FALSE
;
1237 TRACE(midi
, "Unknown capability (%08lx) !\n", lpParms
->dwItem
);
1238 return MCIERR_UNRECOGNIZED_COMMAND
;
1241 TRACE(midi
, "No GetDevCaps-Item !\n");
1242 return MCIERR_UNRECOGNIZED_COMMAND
;
1247 /**************************************************************************
1248 * MIDI_mciInfo [internal]
1250 static DWORD
MIDI_mciInfo(UINT16 wDevID
, DWORD dwFlags
, LPMCI_INFO_PARMS16 lpParms
)
1252 TRACE(midi
, "(%04X, %08lX, %p);\n", wDevID
, dwFlags
, lpParms
);
1254 if (lpParms
== NULL
) return MCIERR_INTERNAL
;
1256 if (wDevID
>= MAX_MCIMIDIDRV
|| MCIMidiDev
[wDevID
].nUseCount
== 0) {
1257 WARN(midi
, "Invalid wDevID=%u\n", wDevID
);
1258 return MCIERR_INVALID_DEVICE_ID
;
1261 lpParms
->lpstrReturn
= NULL
;
1264 case MCI_INFO_PRODUCT
:
1265 lpParms
->lpstrReturn
= "Linux Sound System 0.5";
1268 lpParms
->lpstrReturn
= "FileName";
1271 return MCIERR_UNRECOGNIZED_COMMAND
;
1273 lpParms
->dwRetSize
= (lpParms
->lpstrReturn
!= NULL
) ? strlen(lpParms
->lpstrReturn
) : 0;
1277 /*-----------------------------------------------------------------------*/
1280 /**************************************************************************
1281 * midiOpenSeq [internal]
1283 static int midiOpenSeq(void)
1285 if (numOpenMidiSeq
== 0) {
1286 midiSeqFD
= open(MIDI_SEQ
, O_RDWR
, 0);
1287 if (midiSeqFD
== -1) {
1288 ERR(midi
, "can't open '%s' ! (%d)\n", MIDI_SEQ
, errno
);
1291 if (fcntl(midiSeqFD
, F_SETFL
, O_NONBLOCK
) < 0) {
1292 WARN(midi
, "can't set sequencer fd to non blocking (%d)\n", errno
);
1297 ioctl(midiSeqFD
, SNDCTL_SEQ_RESET
);
1303 /**************************************************************************
1304 * midiCloseSeq [internal]
1306 static int midiCloseSeq(void)
1308 if (--numOpenMidiSeq
== 0) {
1315 /* FIXME: this is a bad idea, it's even not static... */
1316 SEQ_DEFINEBUF(1024);
1318 /* FIXME: this is not reentrant, not static - because of global variable
1319 * _seqbuf and al. */
1320 /**************************************************************************
1321 * seqbuf_dump [internal]
1323 void seqbuf_dump(void)
1326 if (write(midiSeqFD
, _seqbuf
, _seqbufptr
) == -1) {
1327 WARN(midi
, "Can't write data to sequencer (%d/%d)!\n",
1331 * in any case buffer is lost so that if many errors occur the buffer
1337 #endif /* HAVE_OSS */
1341 static void midReceiveChar(WORD wDevID
, unsigned char value
, DWORD dwTime
)
1345 TRACE(midi
, "Adding %02xh to %d[%d]\n", value
, wDevID
, MidiInDev
[wDevID
].incLen
);
1347 if (wDevID
>= MAX_MIDIINDRV
) {
1348 WARN(midi
, "bad devID\n");
1351 if (MidiInDev
[wDevID
].state
== 0) {
1352 TRACE(midi
, "input not started, thrown away\n");
1356 if (MidiInDev
[wDevID
].state
& 2) { /* system exclusive */
1357 LPMIDIHDR ptr
= MidiInDev
[wDevID
].lpQueueHdr
;
1361 ((LPSTR
)(ptr
->reserved
))[ptr
->dwBytesRecorded
++] = value
;
1362 if (ptr
->dwBytesRecorded
== ptr
->dwBufferLength
) {
1366 if (value
== 0xF7) { /* then end */
1367 MidiInDev
[wDevID
].state
&= ~2;
1370 if (sbfb
&& ptr
!= NULL
) {
1371 ptr
= MidiInDev
[wDevID
].lpQueueHdr
;
1372 ptr
->dwFlags
&= ~MHDR_INQUEUE
;
1373 ptr
->dwFlags
|= MHDR_DONE
;
1374 MidiInDev
[wDevID
].lpQueueHdr
= (LPMIDIHDR
)ptr
->lpNext
;
1375 if (MIDI_NotifyClient(wDevID
, MIM_LONGDATA
, (DWORD
)ptr
, dwTime
) != MMSYSERR_NOERROR
) {
1376 WARN(midi
, "Couldn't notify client\n");
1382 #define IS_CMD(_x) (((_x) & 0x80) == 0x80)
1383 #define IS_SYS_CMD(_x) (((_x) & 0xF0) == 0xF0)
1385 if (!IS_CMD(value
) && MidiInDev
[wDevID
].incLen
== 0) { /* try to reuse old cmd */
1386 if (IS_CMD(MidiInDev
[wDevID
].incPrev
) && !IS_SYS_CMD(MidiInDev
[wDevID
].incPrev
)) {
1387 MidiInDev
[wDevID
].incoming
[0] = MidiInDev
[wDevID
].incPrev
;
1388 MidiInDev
[wDevID
].incLen
= 1;
1389 TRACE(midi
, "Reusing old command %02xh\n", MidiInDev
[wDevID
].incPrev
);
1391 FIXME(midi
, "error for midi-in, should generate MIM_ERROR notification:"
1392 " prev=%02Xh, incLen=%02Xh\n",
1393 MidiInDev
[wDevID
].incPrev
, MidiInDev
[wDevID
].incLen
);
1397 MidiInDev
[wDevID
].incoming
[(int)(MidiInDev
[wDevID
].incLen
++)] = value
;
1398 if (MidiInDev
[wDevID
].incLen
== 1 && !IS_SYS_CMD(MidiInDev
[wDevID
].incoming
[0])) {
1399 /* store new cmd, just in case */
1400 MidiInDev
[wDevID
].incPrev
= MidiInDev
[wDevID
].incoming
[0];
1404 #undef IS_SYS_CMD(_x)
1406 switch (MidiInDev
[wDevID
].incoming
[0] & 0xF0) {
1409 case MIDI_KEY_PRESSURE
:
1410 case MIDI_CTL_CHANGE
:
1411 case MIDI_PITCH_BEND
:
1412 if (MidiInDev
[wDevID
].incLen
== 3) {
1413 toSend
= (MidiInDev
[wDevID
].incoming
[2] << 16) |
1414 (MidiInDev
[wDevID
].incoming
[1] << 8) |
1415 (MidiInDev
[wDevID
].incoming
[0] << 0);
1418 case MIDI_PGM_CHANGE
:
1419 case MIDI_CHN_PRESSURE
:
1420 if (MidiInDev
[wDevID
].incLen
== 2) {
1421 toSend
= (MidiInDev
[wDevID
].incoming
[1] << 8) |
1422 (MidiInDev
[wDevID
].incoming
[0] << 0);
1425 case MIDI_SYSTEM_PREFIX
:
1426 if (MidiInDev
[wDevID
].incoming
[0] == 0xF0) {
1427 MidiInDev
[wDevID
].state
|= 2;
1428 MidiInDev
[wDevID
].incLen
= 0;
1430 if (MidiInDev
[wDevID
].incLen
== 1) {
1431 toSend
= (MidiInDev
[wDevID
].incoming
[0] << 0);
1436 WARN(midi
, "This shouldn't happen (%02X)\n", MidiInDev
[wDevID
].incoming
[0]);
1439 TRACE(midi
, "Sending event %08lx\n", toSend
);
1440 MidiInDev
[wDevID
].incLen
= 0;
1441 dwTime
-= MidiInDev
[wDevID
].startTime
;
1442 if (MIDI_NotifyClient(wDevID
, MIM_DATA
, toSend
, dwTime
) != MMSYSERR_NOERROR
) {
1443 WARN(midi
, "Couldn't notify client\n");
1448 static VOID WINAPI
midTimeCallback(HWND32 hwnd
, UINT32 msg
, UINT32 id
, DWORD dwTime
)
1450 unsigned char buffer
[256];
1453 TRACE(midi
, "(%04X, %d, %d, %lu)\n", hwnd
, msg
, id
, dwTime
);
1455 len
= read(midiSeqFD
, buffer
, sizeof(buffer
));
1457 if ((len
% 4) != 0) {
1458 WARN(midi
, "bad length %d (%d)\n", len
, errno
);
1462 for (idx
= 0; idx
< len
; ) {
1463 if (buffer
[idx
] & 0x80) {
1465 "reading<8> %02x %02x %02x %02x %02x %02x %02x %02x\n",
1466 buffer
[idx
+ 0], buffer
[idx
+ 1],
1467 buffer
[idx
+ 2], buffer
[idx
+ 3],
1468 buffer
[idx
+ 4], buffer
[idx
+ 5],
1469 buffer
[idx
+ 6], buffer
[idx
+ 7]);
1472 switch (buffer
[idx
+ 0]) {
1477 midReceiveChar(buffer
[idx
+ 2], buffer
[idx
+ 1], dwTime
);
1480 TRACE(midi
, "Unsupported event %d\n", buffer
[idx
+ 0]);
1487 #endif /* HAVE_OSS */
1489 /**************************************************************************
1490 * midGetDevCaps [internal]
1492 static DWORD
midGetDevCaps(WORD wDevID
, LPMIDIINCAPS16 lpCaps
, DWORD dwSize
)
1494 LPMIDIINCAPS16 tmplpCaps
;
1496 TRACE(midi
, "(%04X, %p, %08lX);\n", wDevID
, lpCaps
, dwSize
);
1498 if (wDevID
>= MIDM_NUMDEVS
) {
1499 return MMSYSERR_BADDEVICEID
;
1501 if (lpCaps
== NULL
) {
1502 return MMSYSERR_INVALPARAM
;
1505 tmplpCaps
= midiInDevices
[wDevID
];
1506 lpCaps
->wMid
= tmplpCaps
->wMid
;
1507 lpCaps
->wPid
= tmplpCaps
->wPid
;
1508 lpCaps
->vDriverVersion
= tmplpCaps
->vDriverVersion
;
1509 strcpy(lpCaps
->szPname
, tmplpCaps
->szPname
);
1510 if (dwSize
== sizeof(MIDIINCAPS16
)) {
1511 /* we should run win 95, so make use of dwSupport */
1512 lpCaps
->dwSupport
= tmplpCaps
->dwSupport
;
1513 } else if (dwSize
!= sizeof(MIDIINCAPS16
) - sizeof(DWORD
)) {
1514 TRACE(midi
, "bad size for lpCaps\n");
1515 return MMSYSERR_INVALPARAM
;
1518 return MMSYSERR_NOERROR
;
1521 /**************************************************************************
1522 * midOpen [internal]
1524 static DWORD
midOpen(WORD wDevID
, LPMIDIOPENDESC lpDesc
, DWORD dwFlags
)
1526 TRACE(midi
, "(%04X, %p, %08lX);\n", wDevID
, lpDesc
, dwFlags
);
1528 if (lpDesc
== NULL
) {
1529 WARN(midi
, "Invalid Parameter !\n");
1530 return MMSYSERR_INVALPARAM
;
1533 * how to check that content of lpDesc is correct ?
1535 if (wDevID
>= MAX_MIDIINDRV
) {
1536 WARN(midi
,"wDevID too large (%u) !\n", wDevID
);
1537 return MMSYSERR_BADDEVICEID
;
1539 if (MidiInDev
[wDevID
].midiDesc
!= 0) {
1540 WARN(midi
, "device already open !\n");
1541 return MMSYSERR_ALLOCATED
;
1543 if ((dwFlags
& ~CALLBACK_TYPEMASK
) != 0) {
1544 FIXME(midi
, "No support for MIDI_IO_STATUS in dwFlags\n");
1545 return MMSYSERR_INVALFLAG
;
1549 if (midiOpenSeq() < 0) {
1550 return MMSYSERR_ERROR
;
1553 if (numStartedMidiIn
++ == 0) {
1554 midiInTimerID
= SetTimer32(0, 0, 250, midTimeCallback
);
1555 if (!midiInTimerID
) {
1556 numStartedMidiIn
= 0;
1557 WARN(midi
, "Couldn't start timer for midi-in\n");
1559 return MMSYSERR_ERROR
;
1561 TRACE(midi
, "Starting timer (%u) for midi-in\n", midiInTimerID
);
1563 #else /* HAVE_OSS */
1565 int midi
= open(MIDI_DEV
, O_WRONLY
, 0);
1567 MidiInDev
[wDevID
].unixdev
= 0;
1569 WARN(midi
,"can't open '%s' (%d)!\n", MIDI_DEV
, errno
);
1570 return MMSYSERR_ALLOCATED
;
1572 MidiInDev
[wDevID
].unixdev
= midi
;
1574 #endif /* HAVE_OSS */
1576 MidiInDev
[wDevID
].wFlags
= HIWORD(dwFlags
& CALLBACK_TYPEMASK
);
1577 switch (MidiInDev
[wDevID
].wFlags
) {
1579 TRACE(midi
,"CALLBACK_NULL !\n");
1582 TRACE(midi
, "CALLBACK_WINDOW !\n");
1585 TRACE(midi
, "CALLBACK_TASK !\n");
1588 TRACE(midi
, "CALLBACK_FUNCTION (%08lX)!\n", lpDesc
->dwCallback
);
1591 MidiInDev
[wDevID
].lpQueueHdr
= NULL
;
1592 MidiInDev
[wDevID
].dwTotalPlayed
= 0;
1593 MidiInDev
[wDevID
].bufsize
= 0x3FFF;
1594 MidiInDev
[wDevID
].midiDesc
= lpDesc
;
1595 MidiInDev
[wDevID
].state
= 0;
1597 MidiInDev
[wDevID
].incLen
= 0;
1598 MidiInDev
[wDevID
].startTime
= 0;
1599 #endif /* HAVE_OSS */
1600 if (MIDI_NotifyClient(wDevID
, MIM_OPEN
, 0L, 0L) != MMSYSERR_NOERROR
) {
1601 WARN(midi
,"can't notify client !\n");
1602 return MMSYSERR_INVALPARAM
;
1604 return MMSYSERR_NOERROR
;
1607 /**************************************************************************
1608 * midClose [internal]
1610 static DWORD
midClose(WORD wDevID
)
1612 int ret
= MMSYSERR_NOERROR
;
1614 TRACE(midi
, "(%04X);\n", wDevID
);
1616 if (wDevID
>= MAX_MIDIINDRV
) {
1617 WARN(midi
,"wDevID too bif (%u) !\n", wDevID
);
1618 return MMSYSERR_BADDEVICEID
;
1620 if (MidiInDev
[wDevID
].midiDesc
== 0) {
1621 WARN(midi
, "device not opened !\n");
1622 return MMSYSERR_ERROR
;
1624 if (MidiInDev
[wDevID
].lpQueueHdr
!= 0) {
1625 return MIDIERR_STILLPLAYING
;
1629 if (midiSeqFD
== -1) {
1630 WARN(midi
,"ooops !\n");
1631 return MMSYSERR_ERROR
;
1633 if (--numStartedMidiIn
== 0) {
1634 TRACE(midi
, "Stopping timer for midi-in\n");
1635 if (!KillTimer32(0, midiInTimerID
)) {
1636 WARN(midi
, "Couldn't stop timer for midi-in\n");
1641 #else /* HAVE_OSS */
1642 if (MidiInDev
[wDevID
].unixdev
== 0) {
1643 WARN(midi
,"ooops !\n");
1644 return MMSYSERR_ERROR
;
1646 close(MidiInDev
[wDevID
].unixdev
);
1647 MidiInDev
[wDevID
].unixdev
= 0;
1648 #endif /* HAVE_OSS */
1649 MidiInDev
[wDevID
].bufsize
= 0;
1650 if (MIDI_NotifyClient(wDevID
, MIM_CLOSE
, 0L, 0L) != MMSYSERR_NOERROR
) {
1651 WARN(midi
,"can't notify client !\n");
1652 ret
= MMSYSERR_INVALPARAM
;
1654 MidiInDev
[wDevID
].midiDesc
= 0;
1658 /**************************************************************************
1659 * midAddBuffer [internal]
1661 static DWORD
midAddBuffer(WORD wDevID
, LPMIDIHDR lpMidiHdr
, DWORD dwSize
)
1663 TRACE(midi
, "(%04X, %p, %08lX);\n", wDevID
, lpMidiHdr
, dwSize
);
1665 if (lpMidiHdr
== NULL
) return MMSYSERR_INVALPARAM
;
1666 if (sizeof(MIDIHDR
) != dwSize
) return MMSYSERR_INVALPARAM
;
1667 if (lpMidiHdr
->dwBufferLength
== 0) return MMSYSERR_INVALPARAM
;
1668 if (lpMidiHdr
->dwFlags
& MHDR_INQUEUE
) return MIDIERR_STILLPLAYING
;
1669 if (!(lpMidiHdr
->dwFlags
& MHDR_PREPARED
)) return MIDIERR_UNPREPARED
;
1671 if (MidiInDev
[wDevID
].lpQueueHdr
== 0) {
1672 MidiInDev
[wDevID
].lpQueueHdr
= lpMidiHdr
;
1676 for (ptr
= MidiInDev
[wDevID
].lpQueueHdr
;
1678 ptr
= (LPMIDIHDR
)ptr
->lpNext
);
1679 ptr
->lpNext
= (struct midihdr_tag
*)lpMidiHdr
;
1681 return MMSYSERR_NOERROR
;
1684 /**************************************************************************
1685 * midPrepare [internal]
1687 static DWORD
midPrepare(WORD wDevID
, LPMIDIHDR lpMidiHdr
, DWORD dwSize
)
1689 TRACE(midi
, "(%04X, %p, %08lX);\n", wDevID
, lpMidiHdr
, dwSize
);
1691 if (dwSize
!= sizeof(MIDIHDR
) || lpMidiHdr
== 0 ||
1692 lpMidiHdr
->lpData
== 0 || lpMidiHdr
->dwFlags
!= 0 ||
1693 lpMidiHdr
->dwBufferLength
>= 0x10000ul
)
1694 return MMSYSERR_INVALPARAM
;
1696 lpMidiHdr
->lpNext
= 0;
1697 lpMidiHdr
->dwFlags
|= MHDR_PREPARED
;
1698 lpMidiHdr
->dwBytesRecorded
= 0;
1700 return MMSYSERR_NOERROR
;
1703 /**************************************************************************
1704 * midUnprepare [internal]
1706 static DWORD
midUnprepare(WORD wDevID
, LPMIDIHDR lpMidiHdr
, DWORD dwSize
)
1708 TRACE(midi
, "(%04X, %p, %08lX);\n", wDevID
, lpMidiHdr
, dwSize
);
1710 if (dwSize
!= sizeof(MIDIHDR
) || lpMidiHdr
== 0 ||
1711 lpMidiHdr
->lpData
== 0 || lpMidiHdr
->dwBufferLength
>= 0x10000ul
)
1712 return MMSYSERR_INVALPARAM
;
1714 if (!(lpMidiHdr
->dwFlags
& MHDR_PREPARED
)) return MIDIERR_UNPREPARED
;
1715 if (lpMidiHdr
->dwFlags
& MHDR_INQUEUE
) return MIDIERR_STILLPLAYING
;
1717 lpMidiHdr
->dwFlags
&= ~MHDR_PREPARED
;
1719 return MMSYSERR_NOERROR
;
1722 /**************************************************************************
1723 * midReset [internal]
1725 static DWORD
midReset(WORD wDevID
)
1727 DWORD dwTime
= GetTickCount();
1729 TRACE(midi
, "(%04X);\n", wDevID
);
1731 while (MidiInDev
[wDevID
].lpQueueHdr
) {
1732 MidiInDev
[wDevID
].lpQueueHdr
->dwFlags
&= ~MHDR_INQUEUE
;
1733 MidiInDev
[wDevID
].lpQueueHdr
->dwFlags
|= MHDR_DONE
;
1734 if (MIDI_NotifyClient(wDevID
, MIM_LONGDATA
,
1735 (DWORD
)MidiInDev
[wDevID
].lpQueueHdr
, dwTime
) != MMSYSERR_NOERROR
) {
1736 WARN(midi
, "Couldn't notify client\n");
1738 MidiInDev
[wDevID
].lpQueueHdr
= (LPMIDIHDR
)MidiInDev
[wDevID
].lpQueueHdr
->lpNext
;
1741 return MMSYSERR_NOERROR
;
1745 /**************************************************************************
1746 * midStart [internal]
1748 static DWORD
midStart(WORD wDevID
)
1750 TRACE(midi
, "(%04X);\n", wDevID
);
1752 /* FIXME : should test value of wDevID */
1755 MidiInDev
[wDevID
].state
= 1;
1756 MidiInDev
[wDevID
].startTime
= GetTickCount();
1757 return MMSYSERR_NOERROR
;
1759 return MMSYSERR_NOTENABLED
;
1760 #endif /* HAVE_OSS */
1763 /**************************************************************************
1764 * midStop [internal]
1766 static DWORD
midStop(WORD wDevID
)
1768 TRACE(midi
, "(%04X);\n", wDevID
);
1770 /* FIXME : should test value of wDevID */
1773 MidiInDev
[wDevID
].state
= 0;
1774 return MMSYSERR_NOERROR
;
1775 #else /* HAVE_OSS */
1776 return MMSYSERR_NOTENABLED
;
1777 #endif /* HAVE_OSS */
1780 /**************************************************************************
1781 * midMessage [sample driver]
1783 DWORD WINAPI
midMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
1784 DWORD dwParam1
, DWORD dwParam2
)
1786 TRACE(midi
, "(%04X, %04X, %08lX, %08lX, %08lX);\n",
1787 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
1790 return midOpen(wDevID
,(LPMIDIOPENDESC
)dwParam1
, dwParam2
);
1792 return midClose(wDevID
);
1793 case MIDM_ADDBUFFER
:
1794 return midAddBuffer(wDevID
,(LPMIDIHDR
)dwParam1
, dwParam2
);
1796 return midPrepare(wDevID
,(LPMIDIHDR
)dwParam1
, dwParam2
);
1797 case MIDM_UNPREPARE
:
1798 return midUnprepare(wDevID
,(LPMIDIHDR
)dwParam1
, dwParam2
);
1799 case MIDM_GETDEVCAPS
:
1800 return midGetDevCaps(wDevID
,(LPMIDIINCAPS16
)dwParam1
,dwParam2
);
1801 case MIDM_GETNUMDEVS
:
1802 return MIDM_NUMDEVS
;
1804 return midReset(wDevID
);
1806 return midStart(wDevID
);
1808 return midStop(wDevID
);
1810 TRACE(midi
, "Unsupported message\n");
1812 return MMSYSERR_NOTSUPPORTED
;
1815 /*-----------------------------------------------------------------------*/
1819 typedef struct sVoice
{
1820 int note
; /* 0 means not used */
1822 unsigned cntMark
: 30,
1824 #define sVS_UNUSED 0
1825 #define sVS_PLAYING 1
1826 #define sVS_SUSTAINED 2
1829 typedef struct sChannel
{
1835 int bank
; /* CTL_BANK_SELECT */
1836 int volume
; /* CTL_MAIN_VOLUME */
1837 int balance
; /* CTL_BALANCE */
1838 int expression
; /* CTL_EXPRESSION */
1839 int sustain
; /* CTL_SUSTAIN */
1841 unsigned char nrgPmtMSB
; /* Non register Parameters */
1842 unsigned char nrgPmtLSB
;
1843 unsigned char regPmtMSB
; /* Non register Parameters */
1844 unsigned char regPmtLSB
;
1847 typedef struct sFMextra
{
1850 sChannel channel
[16]; /* MIDI has only 16 channels */
1851 sVoice voice
[1]; /* dyn allocated according to sound card */
1852 /* do not append fields below voice[1] since the size of this structure
1853 * depends on the number of available voices on the FM synth...
1857 extern unsigned char midiFMInstrumentPatches
[16 * 128];
1858 extern unsigned char midiFMDrumsPatches
[16 * 128];
1860 /**************************************************************************
1861 * modFMLoad [internal]
1863 static int modFMLoad(int dev
)
1866 struct sbi_instrument sbi
;
1871 memset(sbi
.operators
+ 16, 0, 16);
1872 for (i
= 0; i
< 128; i
++) {
1874 memcpy(sbi
.operators
, midiFMInstrumentPatches
+ i
* 16, 16);
1876 if (write(midiSeqFD
, (char*)&sbi
, sizeof(sbi
)) == -1) {
1877 WARN(midi
, "Couldn't write patch for instrument %d (%d)!\n", sbi
.channel
, errno
);
1881 for (i
= 0; i
< 128; i
++) {
1882 sbi
.channel
= 128 + i
;
1883 memcpy(sbi
.operators
, midiFMDrumsPatches
+ i
* 16, 16);
1885 if (write(midiSeqFD
, (char*)&sbi
, sizeof(sbi
)) == -1) {
1886 WARN(midi
, "Couldn't write patch for drum %d (%d)!\n", sbi
.channel
, errno
);
1893 /**************************************************************************
1894 * modFMReset [internal]
1896 static void modFMReset(WORD wDevID
)
1898 sFMextra
* extra
= (sFMextra
*)MidiOutDev
[wDevID
].lpExtra
;
1899 sVoice
* voice
= extra
->voice
;
1900 sChannel
* channel
= extra
->channel
;
1903 for (i
= 0; i
< midiOutDevices
[wDevID
]->wVoices
; i
++) {
1904 if (voice
[i
].status
!= sVS_UNUSED
) {
1905 SEQ_STOP_NOTE(wDevID
, i
, voice
[i
].note
, 64);
1907 SEQ_KEY_PRESSURE(wDevID
, i
, 127, 0);
1908 SEQ_CONTROL(wDevID
, i
, SEQ_VOLMODE
, VOL_METHOD_LINEAR
);
1910 voice
[i
].channel
= -1;
1911 voice
[i
].cntMark
= 0;
1912 voice
[i
].status
= sVS_UNUSED
;
1914 for (i
= 0; i
< 16; i
++) {
1915 channel
[i
].program
= 0;
1916 channel
[i
].bender
= 8192;
1917 channel
[i
].benderRange
= 2;
1918 channel
[i
].bank
= 0;
1919 channel
[i
].volume
= 127;
1920 channel
[i
].balance
= 64;
1921 channel
[i
].expression
= 0;
1922 channel
[i
].sustain
= 0;
1925 extra
->drumSetMask
= 1 << 9; /* channel 10 is normally drums, sometimes 16 also */
1929 #define IS_DRUM_CHANNEL(_xtra, _chn) ((_xtra)->drumSetMask & (1 << (_chn)))
1931 #endif /* HAVE_OSS */
1933 /**************************************************************************
1934 * modGetDevCaps [internal]
1936 static DWORD
modGetDevCaps(WORD wDevID
, LPMIDIOUTCAPS16 lpCaps
,
1939 TRACE(midi
, "(%04X, %p, %08lX);\n", wDevID
, lpCaps
, dwSize
);
1940 if (wDevID
== (WORD
) MIDI_MAPPER
) {
1941 lpCaps
->wMid
= 0x00FF; /* Manufac ID */
1942 lpCaps
->wPid
= 0x0001; /* Product ID */
1943 lpCaps
->vDriverVersion
= 0x001; /* Product Version */
1944 strcpy(lpCaps
->szPname
, "MIDI Mapper (not functional yet)");
1945 /* FIXME Does it make any difference ? */
1946 lpCaps
->wTechnology
= MOD_FMSYNTH
;
1947 lpCaps
->wVoices
= 14; /* FIXME */
1948 lpCaps
->wNotes
= 14; /* FIXME */
1949 /* FIXME Does it make any difference ? */
1950 lpCaps
->dwSupport
= MIDICAPS_VOLUME
|MIDICAPS_LRVOLUME
;
1952 LPMIDIOUTCAPS16 tmplpCaps
;
1954 if (wDevID
>= MODM_NUMDEVS
) {
1955 TRACE(midi
, "MAX_MIDIOUTDRV reached !\n");
1956 return MMSYSERR_BADDEVICEID
;
1958 /* FIXME There is a way to do it so easily, but I'm too
1959 * sleepy to think and I want to test
1962 tmplpCaps
= midiOutDevices
[wDevID
];
1963 lpCaps
->wMid
= tmplpCaps
->wMid
;
1964 lpCaps
->wPid
= tmplpCaps
->wPid
;
1965 lpCaps
->vDriverVersion
= tmplpCaps
->vDriverVersion
;
1966 strcpy(lpCaps
->szPname
, tmplpCaps
->szPname
);
1967 lpCaps
->wTechnology
= tmplpCaps
->wTechnology
;
1968 lpCaps
->wVoices
= tmplpCaps
->wVoices
;
1969 lpCaps
->wNotes
= tmplpCaps
->wNotes
;
1970 lpCaps
->dwSupport
= tmplpCaps
->dwSupport
;
1972 return MMSYSERR_NOERROR
;
1975 /**************************************************************************
1976 * modOpen [internal]
1978 static DWORD
modOpen(WORD wDevID
, LPMIDIOPENDESC lpDesc
, DWORD dwFlags
)
1980 TRACE(midi
, "(%04X, %p, %08lX);\n", wDevID
, lpDesc
, dwFlags
);
1981 if (lpDesc
== NULL
) {
1982 WARN(midi
, "Invalid Parameter !\n");
1983 return MMSYSERR_INVALPARAM
;
1985 if (wDevID
>= MAX_MIDIOUTDRV
) {
1986 TRACE(midi
,"MAX_MIDIOUTDRV reached !\n");
1987 return MMSYSERR_BADDEVICEID
;
1989 if (MidiOutDev
[wDevID
].midiDesc
!= 0) {
1990 WARN(midi
, "device already open !\n");
1991 return MMSYSERR_ALLOCATED
;
1993 if ((dwFlags
& ~CALLBACK_TYPEMASK
) != 0) {
1994 WARN(midi
, "bad dwFlags\n");
1995 return MMSYSERR_INVALFLAG
;
1999 MidiOutDev
[wDevID
].lpExtra
= 0;
2001 switch (midiOutDevices
[wDevID
]->wTechnology
) {
2004 void* extra
= xmalloc(sizeof(struct sFMextra
) +
2005 sizeof(struct sVoice
) *
2006 (midiOutDevices
[wDevID
]->wVoices
- 1));
2009 WARN(midi
, "can't alloc extra data !\n");
2010 return MMSYSERR_NOMEM
;
2012 MidiOutDev
[wDevID
].lpExtra
= extra
;
2013 if (midiOpenSeq() < 0) {
2014 MidiOutDev
[wDevID
].lpExtra
= 0;
2016 return MMSYSERR_ERROR
;
2018 if (modFMLoad(wDevID
) < 0) {
2020 MidiOutDev
[wDevID
].lpExtra
= 0;
2022 return MMSYSERR_ERROR
;
2028 if (midiOpenSeq() < 0) {
2029 return MMSYSERR_ALLOCATED
;
2033 WARN(midi
,"Technology not supported (yet) %d !\n",
2034 midiOutDevices
[wDevID
]->wTechnology
);
2035 return MMSYSERR_NOTENABLED
;
2037 #else /* HAVE_OSS */
2039 int midi
= open (MIDI_DEV
, O_WRONLY
, 0);
2040 MidiOutDev
[wDevID
].unixdev
= 0;
2042 WARN(midi
, "can't open !\n");
2043 return MMSYSERR_ALLOCATED
;
2045 MidiOutDev
[wDevID
].unixdev
= midi
;
2047 #endif /* HAVE_OSS */
2049 MidiOutDev
[wDevID
].wFlags
= HIWORD(dwFlags
& CALLBACK_TYPEMASK
);
2050 switch (MidiOutDev
[wDevID
].wFlags
) {
2052 TRACE(midi
,"CALLBACK_NULL !\n");
2055 TRACE(midi
, "CALLBACK_WINDOW !\n");
2058 TRACE(midi
, "CALLBACK_TASK !\n");
2061 TRACE(midi
, "CALLBACK_FUNCTION !\n");
2064 MidiOutDev
[wDevID
].lpQueueHdr
= NULL
;
2065 MidiOutDev
[wDevID
].dwTotalPlayed
= 0;
2066 MidiOutDev
[wDevID
].bufsize
= 0x3FFF;
2067 MidiOutDev
[wDevID
].midiDesc
= lpDesc
;
2069 if (MIDI_NotifyClient(wDevID
, MOM_OPEN
, 0L, 0L) != MMSYSERR_NOERROR
) {
2070 WARN(midi
,"can't notify client !\n");
2071 return MMSYSERR_INVALPARAM
;
2073 TRACE(midi
, "Succesful !\n");
2074 return MMSYSERR_NOERROR
;
2078 /**************************************************************************
2079 * modClose [internal]
2081 static DWORD
modClose(WORD wDevID
)
2083 int ret
= MMSYSERR_NOERROR
;
2085 TRACE(midi
, "(%04X);\n", wDevID
);
2087 if (MidiOutDev
[wDevID
].midiDesc
== 0) {
2088 WARN(midi
, "device not opened !\n");
2089 return MMSYSERR_ERROR
;
2091 /* FIXME: should test that no pending buffer is still in the queue for
2095 if (midiSeqFD
== -1) {
2096 WARN(midi
,"can't close !\n");
2097 return MMSYSERR_ERROR
;
2100 switch (midiOutDevices
[wDevID
]->wTechnology
) {
2106 WARN(midi
,"Technology not supported (yet) %d !\n",
2107 midiOutDevices
[wDevID
]->wTechnology
);
2108 return MMSYSERR_NOTENABLED
;
2111 if (MidiOutDev
[wDevID
].lpExtra
!= 0) {
2112 free(MidiOutDev
[wDevID
].lpExtra
);
2113 MidiOutDev
[wDevID
].lpExtra
= 0;
2116 if (MidiOutDev
[wDevID
].unixdev
== 0) {
2117 WARN(midi
,"can't close !\n");
2118 return MMSYSERR_NOTENABLED
;
2120 close(MidiOutDev
[wDevID
].unixdev
);
2121 MidiOutDev
[wDevID
].unixdev
= 0;
2122 #endif /* HAVE_OSS */
2124 MidiOutDev
[wDevID
].bufsize
= 0;
2125 if (MIDI_NotifyClient(wDevID
, MOM_CLOSE
, 0L, 0L) != MMSYSERR_NOERROR
) {
2126 WARN(midi
,"can't notify client !\n");
2127 ret
= MMSYSERR_INVALPARAM
;
2129 MidiOutDev
[wDevID
].midiDesc
= 0;
2133 /**************************************************************************
2134 * modData [internal]
2136 static DWORD
modData(WORD wDevID
, DWORD dwParam
)
2138 WORD evt
= LOBYTE(LOWORD(dwParam
));
2139 WORD d1
= HIBYTE(LOWORD(dwParam
));
2140 WORD d2
= LOBYTE(HIWORD(dwParam
));
2142 TRACE(midi
, "(%04X, %08lX);\n", wDevID
, dwParam
);
2145 if (midiSeqFD
== -1) {
2146 WARN(midi
,"can't play !\n");
2147 return MIDIERR_NODEVICE
;
2149 switch (midiOutDevices
[wDevID
]->wTechnology
) {
2152 * - chorus depth controller is not used
2155 sFMextra
* extra
= (sFMextra
*)MidiOutDev
[wDevID
].lpExtra
;
2156 sVoice
* voice
= extra
->voice
;
2157 sChannel
* channel
= extra
->channel
;
2158 int chn
= (evt
& 0x0F);
2161 switch (evt
& 0xF0) {
2163 for (i
= 0; i
< midiOutDevices
[wDevID
]->wVoices
; i
++) {
2164 /* don't stop sustained notes */
2165 if (voice
[i
].status
== sVS_PLAYING
&& voice
[i
].channel
== chn
&& voice
[i
].note
== d1
) {
2166 voice
[i
].status
= sVS_UNUSED
;
2167 SEQ_STOP_NOTE(wDevID
, i
, d1
, d2
);
2172 if (d2
== 0) { /* note off if velocity == 0 */
2173 for (i
= 0; i
< midiOutDevices
[wDevID
]->wVoices
; i
++) {
2174 /* don't stop sustained notes */
2175 if (voice
[i
].status
== sVS_PLAYING
&& voice
[i
].channel
== chn
&& voice
[i
].note
== d1
) {
2176 voice
[i
].status
= sVS_UNUSED
;
2177 SEQ_STOP_NOTE(wDevID
, i
, d1
, 64);
2182 /* finding out in this order :
2184 * - if replaying the same note on the same channel
2185 * - the older voice (LRU)
2187 for (i
= nv
= 0; i
< midiOutDevices
[wDevID
]->wVoices
; i
++) {
2188 if (voice
[i
].status
== sVS_UNUSED
||
2189 (voice
[i
].note
== d1
&& voice
[i
].channel
== chn
)) {
2193 if (voice
[i
].cntMark
< voice
[0].cntMark
) {
2198 "playing on voice=%d, pgm=%d, pan=0x%02X, vol=0x%02X, "
2199 "bender=0x%02X, note=0x%02X, vel=0x%02X\n",
2200 nv
, channel
[chn
].program
,
2201 channel
[chn
].balance
,
2202 channel
[chn
].volume
,
2203 channel
[chn
].bender
, d1
, d2
);
2205 SEQ_SET_PATCH(wDevID
, nv
, IS_DRUM_CHANNEL(extra
, chn
) ?
2206 (128 + d1
) : channel
[chn
].program
);
2207 SEQ_BENDER_RANGE(wDevID
, nv
, channel
[chn
].benderRange
* 100);
2208 SEQ_BENDER(wDevID
, nv
, channel
[chn
].bender
);
2209 SEQ_CONTROL(wDevID
, nv
, CTL_PAN
, channel
[chn
].balance
);
2210 SEQ_CONTROL(wDevID
, nv
, CTL_EXPRESSION
, channel
[chn
].expression
);
2212 /* FIXME: does not really seem to work on my SB card and
2213 * screws everything up... so lay it down
2215 SEQ_CONTROL(wDevID
, nv
, CTL_MAIN_VOLUME
, channel
[chn
].volume
);
2217 SEQ_START_NOTE(wDevID
, nv
, d1
, d2
);
2218 voice
[nv
].status
= channel
[chn
].sustain
? sVS_SUSTAINED
: sVS_PLAYING
;
2219 voice
[nv
].note
= d1
;
2220 voice
[nv
].channel
= chn
;
2221 voice
[nv
].cntMark
= extra
->counter
++;
2223 case MIDI_KEY_PRESSURE
:
2224 for (i
= 0; i
< midiOutDevices
[wDevID
]->wVoices
; i
++) {
2225 if (voice
[i
].status
!= sVS_UNUSED
&& voice
[i
].channel
== chn
&& voice
[i
].note
== d1
) {
2226 SEQ_KEY_PRESSURE(wDevID
, i
, d1
, d2
);
2230 case MIDI_CTL_CHANGE
:
2232 case CTL_BANK_SELECT
: channel
[chn
].bank
= d2
; break;
2233 case CTL_MAIN_VOLUME
: channel
[chn
].volume
= d2
; break;
2234 case CTL_PAN
: channel
[chn
].balance
= d2
; break;
2235 case CTL_EXPRESSION
: channel
[chn
].expression
= d2
; break;
2236 case CTL_SUSTAIN
: channel
[chn
].sustain
= d2
;
2238 for (i
= 0; i
< midiOutDevices
[wDevID
]->wVoices
; i
++) {
2239 if (voice
[i
].status
== sVS_PLAYING
&& voice
[i
].channel
== chn
) {
2240 voice
[i
].status
= sVS_SUSTAINED
;
2244 for (i
= 0; i
< midiOutDevices
[wDevID
]->wVoices
; i
++) {
2245 if (voice
[i
].status
== sVS_SUSTAINED
&& voice
[i
].channel
== chn
) {
2246 voice
[i
].status
= sVS_UNUSED
;
2247 SEQ_STOP_NOTE(wDevID
, i
, voice
[i
].note
, 64);
2252 case CTL_NONREG_PARM_NUM_LSB
: channel
[chn
].nrgPmtLSB
= d2
; break;
2253 case CTL_NONREG_PARM_NUM_MSB
: channel
[chn
].nrgPmtMSB
= d2
; break;
2254 case CTL_REGIST_PARM_NUM_LSB
: channel
[chn
].regPmtLSB
= d2
; break;
2255 case CTL_REGIST_PARM_NUM_MSB
: channel
[chn
].regPmtMSB
= d2
; break;
2257 case CTL_DATA_ENTRY
:
2258 switch ((channel
[chn
].regPmtMSB
<< 8) | channel
[chn
].regPmtLSB
) {
2260 if (channel
[chn
].benderRange
!= d2
) {
2261 channel
[chn
].benderRange
= d2
;
2262 for (i
= 0; i
< midiOutDevices
[wDevID
]->wVoices
; i
++) {
2263 if (voice
[i
].channel
== chn
) {
2264 SEQ_BENDER_RANGE(wDevID
, i
, channel
[chn
].benderRange
);
2271 channel
[chn
].benderRange
= 2;
2272 for (i
= 0; i
< midiOutDevices
[wDevID
]->wVoices
; i
++) {
2273 if (voice
[i
].channel
== chn
) {
2274 SEQ_BENDER_RANGE(wDevID
, i
, channel
[chn
].benderRange
);
2279 TRACE(midi
, "Data entry: regPmt=0x%02x%02x, nrgPmt=0x%02x%02x with %x\n",
2280 channel
[chn
].regPmtMSB
, channel
[chn
].regPmtLSB
,
2281 channel
[chn
].nrgPmtMSB
, channel
[chn
].nrgPmtLSB
,
2287 case 0x78: /* all sounds off */
2288 for (i
= 0; i
< midiOutDevices
[wDevID
]->wVoices
; i
++) {
2289 if (voice
[i
].status
!= sVS_UNUSED
&& voice
[i
].channel
== chn
) {
2290 voice
[i
].status
= sVS_UNUSED
;
2291 SEQ_STOP_NOTE(wDevID
, i
, voice
[i
].note
, 0);
2295 case 0x7B: /* all notes off */
2296 for (i
= 0; i
< midiOutDevices
[wDevID
]->wVoices
; i
++) {
2297 if (voice
[i
].status
== sVS_PLAYING
&& voice
[i
].channel
== chn
) {
2298 voice
[i
].status
= sVS_UNUSED
;
2299 SEQ_STOP_NOTE(wDevID
, i
, voice
[i
].note
, 0);
2304 TRACE(midi
, "Dropping MIDI control event 0x%02x(%02x) on channel %d\n",
2309 case MIDI_PGM_CHANGE
:
2310 channel
[chn
].program
= d1
;
2312 case MIDI_CHN_PRESSURE
:
2313 for (i
= 0; i
< midiOutDevices
[wDevID
]->wVoices
; i
++) {
2314 if (voice
[i
].status
!= sVS_UNUSED
&& voice
[i
].channel
== chn
) {
2315 SEQ_KEY_PRESSURE(wDevID
, i
, voice
[i
].note
, d1
);
2319 case MIDI_PITCH_BEND
:
2320 channel
[chn
].bender
= (d2
<< 7) + d1
;
2321 for (i
= 0; i
< midiOutDevices
[wDevID
]->wVoices
; i
++) {
2322 if (voice
[i
].channel
== chn
) {
2323 SEQ_BENDER(wDevID
, i
, channel
[chn
].bender
);
2327 case MIDI_SYSTEM_PREFIX
:
2328 switch (evt
& 0x0F) {
2329 case 0x0F: /* Reset */
2334 "Unsupported (yet) system event %02x\n",
2339 WARN(midi
, "Internal error, shouldn't happen (event=%08x)\n", evt
& 0xF0);
2340 return MMSYSERR_NOTENABLED
;
2346 int dev
= wDevID
- MODM_NUMFMSYNTHDEVS
;
2348 WARN(midi
, "Internal error on devID (%u) !\n", wDevID
);
2349 return MIDIERR_NODEVICE
;
2352 switch (evt
& 0xF0) {
2355 case MIDI_KEY_PRESSURE
:
2356 case MIDI_CTL_CHANGE
:
2357 case MIDI_PITCH_BEND
:
2358 SEQ_MIDIOUT(dev
, evt
);
2359 SEQ_MIDIOUT(dev
, d1
);
2360 SEQ_MIDIOUT(dev
, d2
);
2362 case MIDI_PGM_CHANGE
:
2363 case MIDI_CHN_PRESSURE
:
2364 SEQ_MIDIOUT(dev
, evt
);
2365 SEQ_MIDIOUT(dev
, d1
);
2367 case MIDI_SYSTEM_PREFIX
:
2368 switch (evt
& 0x0F) {
2369 case 0x00: /* System Exclusive, don't do it on modData,
2370 * should require modLongData*/
2371 case 0x01: /* Undefined */
2372 case 0x04: /* Undefined. */
2373 case 0x05: /* Undefined. */
2374 case 0x07: /* End of Exclusive. */
2375 case 0x09: /* Undefined. */
2376 case 0x0D: /* Undefined. */
2378 case 0x06: /* Tune Request */
2379 case 0x08: /* Timing Clock. */
2380 case 0x0A: /* Start. */
2381 case 0x0B: /* Continue */
2382 case 0x0C: /* Stop */
2383 case 0x0E: /* Active Sensing. */
2384 SEQ_MIDIOUT(dev
, evt
);
2386 case 0x0F: /* Reset */
2387 /* SEQ_MIDIOUT(dev, evt);
2388 this other way may be better */
2389 SEQ_MIDIOUT(dev
, MIDI_SYSTEM_PREFIX
);
2390 SEQ_MIDIOUT(dev
, 0x7e);
2391 SEQ_MIDIOUT(dev
, 0x7f);
2392 SEQ_MIDIOUT(dev
, 0x09);
2393 SEQ_MIDIOUT(dev
, 0x01);
2394 SEQ_MIDIOUT(dev
, 0xf7);
2396 case 0x03: /* Song Select. */
2397 SEQ_MIDIOUT(dev
, evt
);
2398 SEQ_MIDIOUT(dev
, d1
);
2399 case 0x02: /* Song Position Pointer. */
2400 SEQ_MIDIOUT(dev
, evt
);
2401 SEQ_MIDIOUT(dev
, d1
);
2402 SEQ_MIDIOUT(dev
, d2
);
2409 WARN(midi
, "Technology not supported (yet) %d !\n",
2410 midiOutDevices
[wDevID
]->wTechnology
);
2411 return MMSYSERR_NOTENABLED
;
2416 if (MidiOutDev
[wDevID
].unixdev
== 0) {
2417 WARN(midi
,"can't play !\n");
2418 return MIDIERR_NODEVICE
;
2421 WORD event
= LOWORD(dwParam
);
2422 if (write (MidiOutDev
[wDevID
].unixdev
,
2423 &event
, sizeof(event
)) != sizeof(WORD
)) {
2424 WARN(midi
, "error writting unixdev !\n");
2427 #endif /* HAVE_OSS */
2428 return MMSYSERR_NOERROR
;
2431 /**************************************************************************
2432 * modLongData [internal]
2434 static DWORD
modLongData(WORD wDevID
, LPMIDIHDR lpMidiHdr
, DWORD dwSize
)
2438 TRACE(midi
, "(%04X, %p, %08lX);\n", wDevID
, lpMidiHdr
, dwSize
);
2441 if (midiSeqFD
== -1) {
2442 WARN(midi
,"can't play !\n");
2443 return MIDIERR_NODEVICE
;
2445 #else /* HAVE_OSS */
2446 if (MidiOutDev
[wDevID
].unixdev
== 0) {
2447 WARN(midi
,"can't play !\n");
2448 return MIDIERR_NODEVICE
;
2450 #endif /* HAVE_OSS */
2452 if (lpMidiHdr
->lpData
== NULL
)
2453 return MIDIERR_UNPREPARED
;
2454 if (!(lpMidiHdr
->dwFlags
& MHDR_PREPARED
))
2455 return MIDIERR_UNPREPARED
;
2456 if (lpMidiHdr
->dwFlags
& MHDR_INQUEUE
)
2457 return MIDIERR_STILLPLAYING
;
2458 lpMidiHdr
->dwFlags
&= ~MHDR_DONE
;
2459 lpMidiHdr
->dwFlags
|= MHDR_INQUEUE
;
2461 TRACE(midi
, "dwBytesRecorded %lu !\n", lpMidiHdr
->dwBytesRecorded
);
2462 TRACE(midi
, " %02X %02X %02X %02X\n",
2463 ((LPBYTE
)(lpMidiHdr
->reserved
))[0],
2464 ((LPBYTE
)(lpMidiHdr
->reserved
))[1],
2465 ((LPBYTE
)(lpMidiHdr
->reserved
))[2],
2466 ((LPBYTE
)(lpMidiHdr
->reserved
))[3]);
2468 switch (midiOutDevices
[wDevID
]->wTechnology
) {
2470 /* FIXME: I don't think there is much to do here */
2473 if (((LPBYTE
)lpMidiHdr
->reserved
)[0] != 0xF0) {
2474 /* Send end of System Exclusive */
2475 SEQ_MIDIOUT(wDevID
- MODM_NUMFMSYNTHDEVS
, 0xF0);
2476 TRACE(midi
, "Adding missing 0xF0 marker at the begining of "
2477 "system exclusive byte stream\n");
2479 for (count
= 0; count
< lpMidiHdr
->dwBytesRecorded
; count
++) {
2480 SEQ_MIDIOUT(wDevID
- MODM_NUMFMSYNTHDEVS
,
2481 ((LPBYTE
)lpMidiHdr
->reserved
)[count
]);
2483 if (((LPBYTE
)lpMidiHdr
->reserved
)[count
- 1] != 0xF7) {
2484 /* Send end of System Exclusive */
2485 SEQ_MIDIOUT(wDevID
- MODM_NUMFMSYNTHDEVS
, 0xF7);
2486 TRACE(midi
, "Adding missing 0xF7 marker at the end of "
2487 "system exclusive byte stream\n");
2492 WARN(midi
, "Technology not supported (yet) %d !\n",
2493 midiOutDevices
[wDevID
]->wTechnology
);
2494 return MMSYSERR_NOTENABLED
;
2496 #else /* HAVE_OSS */
2498 LPWORD ptr
= (LPWORD
)lpMidiHdr
->reserved
;
2501 for (count
= 0; count
< lpMidiHdr
->dwBytesRecorded
; count
++) {
2502 if (write(MidiOutDev
[wDevID
].unixdev
,
2503 ptr
, sizeof(WORD
)) != sizeof(WORD
))
2509 TRACE(midi
, "after write count = %d\n",count
);
2510 if (count
!= lpMidiHdr
->dwBytesRecorded
) {
2511 WARN(midi
, "error writting unixdev #%d ! (%d != %ld)\n",
2512 MidiOutDev
[wDevID
].unixdev
, count
,
2513 lpMidiHdr
->dwBytesRecorded
);
2514 TRACE(midi
, "\terrno = %d error = %s\n",en
,strerror(en
));
2515 return MMSYSERR_NOTENABLED
;
2518 #endif /* HAVE_OSS */
2520 lpMidiHdr
->dwFlags
&= ~MHDR_INQUEUE
;
2521 lpMidiHdr
->dwFlags
|= MHDR_DONE
;
2522 if (MIDI_NotifyClient(wDevID
, MOM_DONE
, (DWORD
)lpMidiHdr
, 0L) != MMSYSERR_NOERROR
) {
2523 WARN(midi
,"can't notify client !\n");
2524 return MMSYSERR_INVALPARAM
;
2526 return MMSYSERR_NOERROR
;
2529 /**************************************************************************
2530 * modPrepare [internal]
2532 static DWORD
modPrepare(WORD wDevID
, LPMIDIHDR lpMidiHdr
, DWORD dwSize
)
2534 TRACE(midi
, "(%04X, %p, %08lX);\n", wDevID
, lpMidiHdr
, dwSize
);
2537 if (midiSeqFD
== -1) {
2538 WARN(midi
,"can't prepare !\n");
2539 return MMSYSERR_NOTENABLED
;
2541 #else /* HAVE_OSS */
2542 if (MidiOutDev
[wDevID
].unixdev
== 0) {
2543 WARN(midi
,"can't prepare !\n");
2544 return MMSYSERR_NOTENABLED
;
2546 #endif /* HAVE_OSS */
2547 if (dwSize
!= sizeof(MIDIHDR
) || lpMidiHdr
== 0 ||
2548 lpMidiHdr
->lpData
== 0 || lpMidiHdr
->dwFlags
!= 0 ||
2549 lpMidiHdr
->dwBufferLength
>= 0x10000ul
)
2550 return MMSYSERR_INVALPARAM
;
2552 lpMidiHdr
->lpNext
= 0;
2553 lpMidiHdr
->dwFlags
|= MHDR_PREPARED
;
2554 lpMidiHdr
->dwFlags
&= ~MHDR_DONE
;
2555 return MMSYSERR_NOERROR
;
2558 /**************************************************************************
2559 * modUnprepare [internal]
2561 static DWORD
modUnprepare(WORD wDevID
, LPMIDIHDR lpMidiHdr
, DWORD dwSize
)
2563 TRACE(midi
, "(%04X, %p, %08lX);\n", wDevID
, lpMidiHdr
, dwSize
);
2566 if (midiSeqFD
== -1) {
2567 WARN(midi
,"can't unprepare !\n");
2568 return MMSYSERR_NOTENABLED
;
2570 #else /* HAVE_OSS */
2571 if (MidiOutDev
[wDevID
].unixdev
== 0) {
2572 WARN(midi
,"can't unprepare !\n");
2573 return MMSYSERR_NOTENABLED
;
2575 #endif /* HAVE_OSS */
2576 if (dwSize
!= sizeof(MIDIHDR
) || lpMidiHdr
== 0)
2577 return MMSYSERR_INVALPARAM
;
2578 if (lpMidiHdr
->dwFlags
& MHDR_INQUEUE
)
2579 return MIDIERR_STILLPLAYING
;
2580 lpMidiHdr
->dwFlags
&= ~MHDR_PREPARED
;
2581 return MMSYSERR_NOERROR
;
2584 /**************************************************************************
2585 * modReset [internal]
2587 static DWORD
modReset(WORD wDevID
)
2589 TRACE(midi
, "(%04X);\n", wDevID
);
2590 /* FIXME: this function should :
2591 * turn off every note, remove sustain on all channels
2592 * remove any pending buffers
2594 return MMSYSERR_NOTENABLED
;
2597 /**************************************************************************
2598 * modMessage [sample driver]
2600 DWORD WINAPI
modMessage(WORD wDevID
, WORD wMsg
, DWORD dwUser
,
2601 DWORD dwParam1
, DWORD dwParam2
)
2603 TRACE(midi
, "(%04X, %04X, %08lX, %08lX, %08lX);\n",
2604 wDevID
, wMsg
, dwUser
, dwParam1
, dwParam2
);
2608 return modOpen(wDevID
, (LPMIDIOPENDESC
)dwParam1
, dwParam2
);
2610 return modClose(wDevID
);
2612 return modData(wDevID
, dwParam1
);
2614 return modLongData(wDevID
, (LPMIDIHDR
)dwParam1
, dwParam2
);
2616 return modPrepare(wDevID
, (LPMIDIHDR
)dwParam1
, dwParam2
);
2617 case MODM_UNPREPARE
:
2618 return modUnprepare(wDevID
, (LPMIDIHDR
)dwParam1
, dwParam2
);
2619 case MODM_GETDEVCAPS
:
2620 return modGetDevCaps(wDevID
,(LPMIDIOUTCAPS16
)dwParam1
,dwParam2
);
2621 case MODM_GETNUMDEVS
:
2622 return MODM_NUMDEVS
;
2623 case MODM_GETVOLUME
:
2625 case MODM_SETVOLUME
:
2628 return modReset(wDevID
);
2630 TRACE(midi
, "Unsupported message\n");
2632 return MMSYSERR_NOTSUPPORTED
;
2635 /**************************************************************************
2636 * MIDI_DriverProc16 [sample driver]
2638 LONG
MIDI_DriverProc16(DWORD dwDevID
, HDRVR16 hDriv
, WORD wMsg
,
2639 DWORD dwParam1
, DWORD dwParam2
)
2642 case DRV_LOAD
: return 1;
2643 case DRV_FREE
: return 1;
2644 case DRV_OPEN
: return 1;
2645 case DRV_CLOSE
: return 1;
2646 case DRV_ENABLE
: return 1;
2647 case DRV_DISABLE
: return 1;
2648 case DRV_QUERYCONFIGURE
: return 1;
2649 case DRV_CONFIGURE
: MessageBox16(0, "Sample Midi Linux Driver !", "MMLinux Driver", MB_OK
); return 1;
2650 case DRV_INSTALL
: return DRVCNF_RESTART
;
2651 case DRV_REMOVE
: return DRVCNF_RESTART
;
2652 case MCI_OPEN_DRIVER
:
2653 case MCI_OPEN
: return MIDI_mciOpen(dwDevID
, dwParam1
, PTR_SEG_TO_LIN(dwParam2
), FALSE
);
2654 case MCI_CLOSE_DRIVER
:
2655 case MCI_CLOSE
: return MIDI_mciClose(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
2656 case MCI_PLAY
: return MIDI_mciPlay(dwDevID
, dwParam1
, (LPMCI_PLAY_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
2657 case MCI_RECORD
: return MIDI_mciRecord(dwDevID
, dwParam1
, (LPMCI_RECORD_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
2658 case MCI_STOP
: return MIDI_mciStop(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
2659 case MCI_SET
: return MIDI_mciSet(dwDevID
, dwParam1
, (LPMCI_SET_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
2660 case MCI_PAUSE
: return MIDI_mciPause(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
2661 case MCI_RESUME
: return MIDI_mciResume(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
2662 case MCI_STATUS
: return MIDI_mciStatus(dwDevID
, dwParam1
, (LPMCI_STATUS_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
2663 case MCI_GETDEVCAPS
: return MIDI_mciGetDevCaps(dwDevID
, dwParam1
, (LPMCI_GETDEVCAPS_PARMS
)PTR_SEG_TO_LIN(dwParam2
));
2664 case MCI_INFO
: return MIDI_mciInfo(dwDevID
, dwParam1
, (LPMCI_INFO_PARMS16
)PTR_SEG_TO_LIN(dwParam2
));
2665 default: return DefDriverProc16(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
2669 /**************************************************************************
2670 * MIDI_DriverProc32 [sample driver]
2672 LONG
MIDI_DriverProc32(DWORD dwDevID
, HDRVR16 hDriv
, DWORD wMsg
,
2673 DWORD dwParam1
, DWORD dwParam2
)
2676 case DRV_LOAD
: return 1;
2677 case DRV_FREE
: return 1;
2678 case DRV_OPEN
: return 1;
2679 case DRV_CLOSE
: return 1;
2680 case DRV_ENABLE
: return 1;
2681 case DRV_DISABLE
: return 1;
2682 case DRV_QUERYCONFIGURE
: return 1;
2683 case DRV_CONFIGURE
: MessageBox16(0, "Sample Midi Linux Driver !", "MMLinux Driver", MB_OK
); return 1;
2684 case DRV_INSTALL
: return DRVCNF_RESTART
;
2685 case DRV_REMOVE
: return DRVCNF_RESTART
;
2686 case MCI_OPEN_DRIVER
:
2687 case MCI_OPEN
: return MIDI_mciOpen(dwDevID
, dwParam1
, (void*)dwParam2
, TRUE
);
2688 case MCI_CLOSE_DRIVER
:
2689 case MCI_CLOSE
: return MIDI_mciClose(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)dwParam2
);
2690 case MCI_PLAY
: return MIDI_mciPlay(dwDevID
, dwParam1
, (LPMCI_PLAY_PARMS
)dwParam2
);
2691 case MCI_RECORD
: return MIDI_mciRecord(dwDevID
, dwParam1
, (LPMCI_RECORD_PARMS
)dwParam2
);
2692 case MCI_STOP
: return MIDI_mciStop(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)dwParam2
);
2693 case MCI_SET
: return MIDI_mciSet(dwDevID
, dwParam1
, (LPMCI_SET_PARMS
)dwParam2
);
2694 case MCI_PAUSE
: return MIDI_mciPause(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)dwParam2
);
2695 case MCI_RESUME
: return MIDI_mciResume(dwDevID
, dwParam1
, (LPMCI_GENERIC_PARMS
)dwParam2
);
2696 case MCI_STATUS
: return MIDI_mciStatus(dwDevID
, dwParam1
, (LPMCI_STATUS_PARMS
)dwParam2
);
2697 case MCI_GETDEVCAPS
: return MIDI_mciGetDevCaps(dwDevID
, dwParam1
, (LPMCI_GETDEVCAPS_PARMS
)dwParam2
);
2698 case MCI_INFO
: return MIDI_mciInfo(dwDevID
, dwParam1
, (LPMCI_INFO_PARMS16
)dwParam2
);
2699 default: return DefDriverProc32(dwDevID
, hDriv
, wMsg
, dwParam1
, dwParam2
);
2702 /*-----------------------------------------------------------------------*/