3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS Multimedia
5 * FILE: lib/mmdrv/midi.c
6 * PURPOSE: Multimedia User Mode Driver
7 * PROGRAMMER: Andrew Greenwood
9 * Jan 30, 2004: Imported into ReactOS tree
19 // MIDI device instance information
21 #define LOCAL_DATA_SIZE 20
22 typedef struct _LOCALMIDIHDR
{
25 struct _LOCALMIDIHDR
*lpNext
;
28 // MIDI_DD_INPUT_DATA MidiData;
29 BYTE ExtraData
[LOCAL_DATA_SIZE
- sizeof(ULONG
)];
31 } LOCALMIDIHDR
, *PLOCALMIDIHDR
;
33 #define LOCAL_MIDI_BUFFERS 8
49 PLOCALMIDIHDR DeviceQueue
;
52 Bufs
[LOCAL_MIDI_BUFFERS
];
55 } LOCALMIDIDATA
, *PLOCALMIDIDATA
;
58 typedef struct tag_MIDIALLOC
{
59 struct tag_MIDIALLOC
*Next
; // Chain of devices
60 UINT DeviceNumber
; // Number of device
61 UINT DeviceType
; // MidiInput or MidiOutput
62 DWORD dwCallback
; // client's callback
63 DWORD dwInstance
; // client's instance data
64 HMIDI hMidi
; // handle for stream
65 HANDLE DeviceHandle
; // Midi device handle
66 LPMIDIHDR lpMIQueue
; // Buffers sent to device
67 // This is only required so that
68 // CLOSE knows when things have
70 // notify. This is only accessed
71 // on the device thread and its
72 // apcs so does not need any
73 // synchronized access.
74 HANDLE Event
; // Event for driver syncrhonization
75 // and notification of auxiliary
76 // task operation completion.
77 // MIDITHREADFUNCTION AuxFunction; // Function for thread to perform
79 LPMIDIHDR pHdr
; // Buffer to pass in aux task
80 ULONG State
; // State to set
82 ULONG Function
; // IOCTL to use
83 PBYTE pData
; // Data to set or get
84 ULONG DataLen
; // Length of data
88 // 0 means terminate task.
89 HANDLE ThreadHandle
; // Handle for termination ONLY
90 HANDLE AuxEvent1
; // Aux thread waits on this
91 HANDLE AuxEvent2
; // Aux thread caller waits on this
92 DWORD AuxReturnCode
; // Return code from Aux task
93 DWORD dwFlags
; // Open flags
94 PLOCALMIDIDATA Mid
; // Extra midi input structures
95 int l
; // Helper global for modMidiLength
97 } MIDIALLOC
, *PMIDIALLOC
;
99 PMIDIALLOC MidiHandleList
; // Our chain of wave handles
103 static DWORD
OpenMidiDevice(UINT DeviceType
, DWORD ID
, DWORD User
, DWORD Param1
, DWORD Param2
)
105 PMIDIALLOC pClient
= NULL
;
106 MMRESULT Result
= MMSYSERR_NOERROR
;
109 DPRINT("OpenMidiDevice()\n");
114 pClient
= (PMIDIALLOC
) HeapAlloc(Heap
, 0, sizeof(MIDIALLOC
));
115 if ( pClient
) memset(pClient
, 0, sizeof(MIDIALLOC
));
119 pClient
= (PMIDIALLOC
) HeapAlloc(Heap
, 0, sizeof(MIDIALLOC
) + sizeof(LOCALMIDIDATA
));
120 if ( pClient
) memset(pClient
, 0, sizeof(MIDIALLOC
) + sizeof(LOCALMIDIDATA
));
125 return MMSYSERR_NOMEM
;
127 if (DeviceType
== MidiInDevice
)
130 pClient
->Mid
= (PLOCALMIDIDATA
)(pClient
+ 1);
131 for (i
= 0 ;i
< LOCAL_MIDI_BUFFERS
; i
++)
133 pClient
->Mid
->Bufs
[i
].pClient
= pClient
;
137 pClient
->DeviceType
= DeviceType
;
138 pClient
->dwCallback
= ((LPMIDIOPENDESC
)Param1
)->dwCallback
;
139 pClient
->dwInstance
= ((LPMIDIOPENDESC
)Param1
)->dwInstance
;
140 pClient
->hMidi
= ((LPMIDIOPENDESC
)Param1
)->hMidi
;
141 pClient
->dwFlags
= Param2
;
143 Result
= OpenDevice(DeviceType
, ID
, &pClient
->DeviceHandle
, (GENERIC_READ
| GENERIC_WRITE
));
145 if ( Result
!= MMSYSERR_NOERROR
)
151 pClient
->Event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
153 if ( !pClient
->Event
)
156 return MMSYSERR_NOMEM
;
159 if (DeviceType
== MidiInDevice
)
162 pClient
->AuxEvent1
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
163 if (pClient
->AuxEvent1
== NULL
)
166 return MMSYSERR_NOMEM
;
169 pClient
->AuxEvent2
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
170 if (pClient
->AuxEvent2
== NULL
)
173 return MMSYSERR_NOMEM
;
180 WaitForSingleObject(pClient
->AuxEvent2
, INFINITE
);
183 PMIDIALLOC
*pUserHandle
;
184 pUserHandle
= (PMIDIALLOC
*) User
;
185 *pUserHandle
= pClient
;
189 return MMSYSERR_NOERROR
;
194 static DWORD
WriteMidi(PBYTE pData
, ULONG Length
, PMIDIALLOC pClient
)
198 DPRINT("IOCTL_MIDI_PLAY == %d [%x]\n", IOCTL_MIDI_PLAY
, IOCTL_MIDI_PLAY
);
200 if ( !DeviceIoControl(pClient
->DeviceHandle
, IOCTL_MIDI_PLAY
, (PVOID
)pData
,
201 Length
, NULL
, 0, &BytesReturned
, NULL
))
202 return TranslateStatus();
204 return MMSYSERR_NOERROR
;
208 static int GetMidiLength(PMIDIALLOC pClient
, BYTE b
)
212 // Realtime message - leave running status
213 return 1; // Write one byte
218 case 0xF0: case 0xF4: case 0xF5: case 0xF6: case 0xF7:
222 case 0xF1: case 0xF3:
233 case 0x80: case 0x90: case 0xA0: case 0xB0: case 0xE0:
237 case 0xC0: case 0xD0:
242 return (pClient
->l
- 1); // uses previous value if data byte (running status)
247 /* ----------------------------------------------------------------------------
249 ----------------------------------------------------------------------------- */
251 APIENTRY DWORD
midMessage(DWORD dwId
, DWORD dwMessage
, DWORD dwUser
, DWORD dwParam1
, DWORD dwParam2
)
253 DPRINT("midMessage\n");
254 return MMSYSERR_NOERROR
;
257 case MIDM_GETNUMDEVS
:
258 DPRINT("MIDM_GETNUMDEVS");
259 return GetDeviceCount(MidiInDevice
);
261 case MIDM_GETDEVCAPS
:
262 DPRINT("MIDM_GETDEVCAPS");
263 return GetDeviceCapabilities(dwId
, MidiInDevice
, (LPBYTE
)dwParam1
, (DWORD
)dwParam2
);
267 return MMSYSERR_NOERROR
;
270 DPRINT("MIDM_CLOSE");
271 return MMSYSERR_NOERROR
;
274 DPRINT("MIDM_ADDBUFFER");
275 return MMSYSERR_NOERROR
;
278 DPRINT("MIDM_PAUSE");
279 return MMSYSERR_NOERROR
;
282 DPRINT("MIDM_RESTART");
283 return MMSYSERR_NOERROR
;
286 DPRINT("MIDM_RESET");
287 return MMSYSERR_NOERROR
;
290 return MMSYSERR_NOTSUPPORTED
;
293 // the function should never get to this point
294 //FIXME: Would it be wise to assert here?
295 return MMSYSERR_NOTSUPPORTED
;
298 APIENTRY DWORD
modMessage(DWORD ID
, DWORD Message
, DWORD User
, DWORD Param1
, DWORD Param2
)
300 DPRINT("modMessage\n");
304 case MODM_GETNUMDEVS
:
305 DPRINT("MODM_GETNUMDEVS == %d\n", (int)GetDeviceCount(MidiOutDevice
));
306 return GetDeviceCount(MidiOutDevice
);
308 case MODM_GETDEVCAPS
:
309 DPRINT("MODM_GETDEVCAPS");
310 return GetDeviceCapabilities(ID
, MidiOutDevice
, (LPBYTE
)Param1
, (DWORD
)Param2
);
313 return OpenMidiDevice(MidiOutDevice
, ID
, User
, Param1
, Param2
);
316 DPRINT("MODM_CLOSE");
317 return MMSYSERR_NOTSUPPORTED
;
324 for (i
= 0; i
< 4; i
++) {
325 b
[i
] = (BYTE
)(Param1
% 256);
328 return WriteMidi(b
, GetMidiLength((PMIDIALLOC
)User
, b
[0]),
332 DPRINT("MODM_LONGDATA");
333 return MMSYSERR_NOTSUPPORTED
;
336 DPRINT("MODM_RESET");
337 return MMSYSERR_NOTSUPPORTED
;
340 DPRINT("MODM_SETVOLUME");
341 return MMSYSERR_NOTSUPPORTED
;
344 DPRINT("MODM_GETVOLUME");
345 return MMSYSERR_NOTSUPPORTED
;
347 case MODM_CACHEPATCHES
:
348 DPRINT("MODM_CACHEPATCHES");
349 return MMSYSERR_NOTSUPPORTED
;
351 case MODM_CACHEDRUMPATCHES
:
352 DPRINT("MODM_CACHEDRUMPATCHES");
353 return MMSYSERR_NOTSUPPORTED
;
357 return MMSYSERR_NOTSUPPORTED
;