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
18 // MIDI device instance information
20 #define LOCAL_DATA_SIZE 20
21 typedef struct _LOCALMIDIHDR
{
24 struct _LOCALMIDIHDR
*lpNext
;
27 // MIDI_DD_INPUT_DATA MidiData;
28 BYTE ExtraData
[LOCAL_DATA_SIZE
- sizeof(ULONG
)];
30 } LOCALMIDIHDR
, *PLOCALMIDIHDR
;
32 #define LOCAL_MIDI_BUFFERS 8
48 PLOCALMIDIHDR DeviceQueue
;
51 Bufs
[LOCAL_MIDI_BUFFERS
];
54 } LOCALMIDIDATA
, *PLOCALMIDIDATA
;
57 typedef struct tag_MIDIALLOC
{
58 struct tag_MIDIALLOC
*Next
; // Chain of devices
59 UINT DeviceNumber
; // Number of device
60 UINT DeviceType
; // MidiInput or MidiOutput
61 DWORD dwCallback
; // client's callback
62 DWORD dwInstance
; // client's instance data
63 HMIDI hMidi
; // handle for stream
64 HANDLE DeviceHandle
; // Midi device handle
65 LPMIDIHDR lpMIQueue
; // Buffers sent to device
66 // This is only required so that
67 // CLOSE knows when things have
69 // notify. This is only accessed
70 // on the device thread and its
71 // apcs so does not need any
72 // synchronized access.
73 HANDLE Event
; // Event for driver syncrhonization
74 // and notification of auxiliary
75 // task operation completion.
76 // MIDITHREADFUNCTION AuxFunction; // Function for thread to perform
78 LPMIDIHDR pHdr
; // Buffer to pass in aux task
79 ULONG State
; // State to set
81 ULONG Function
; // IOCTL to use
82 PBYTE pData
; // Data to set or get
83 ULONG DataLen
; // Length of data
87 // 0 means terminate task.
88 HANDLE ThreadHandle
; // Handle for termination ONLY
89 HANDLE AuxEvent1
; // Aux thread waits on this
90 HANDLE AuxEvent2
; // Aux thread caller waits on this
91 DWORD AuxReturnCode
; // Return code from Aux task
92 DWORD dwFlags
; // Open flags
93 PLOCALMIDIDATA Mid
; // Extra midi input structures
94 int l
; // Helper global for modMidiLength
96 } MIDIALLOC
, *PMIDIALLOC
;
98 PMIDIALLOC MidiHandleList
; // Our chain of wave handles
102 static DWORD
OpenMidiDevice(UINT DeviceType
, DWORD ID
, DWORD User
, DWORD Param1
, DWORD Param2
)
104 PMIDIALLOC pClient
= NULL
;
105 MMRESULT Result
= MMSYSERR_NOERROR
;
108 DPRINT("OpenMidiDevice()\n");
113 pClient
= (PMIDIALLOC
) HeapAlloc(Heap
, 0, sizeof(MIDIALLOC
));
114 if ( pClient
) memset(pClient
, 0, sizeof(MIDIALLOC
));
118 pClient
= (PMIDIALLOC
) HeapAlloc(Heap
, 0, sizeof(MIDIALLOC
) + sizeof(LOCALMIDIDATA
));
119 if ( pClient
) memset(pClient
, 0, sizeof(MIDIALLOC
) + sizeof(LOCALMIDIDATA
));
124 return MMSYSERR_NOMEM
;
126 if (DeviceType
== MidiInDevice
)
129 pClient
->Mid
= (PLOCALMIDIDATA
)(pClient
+ 1);
130 for (i
= 0 ;i
< LOCAL_MIDI_BUFFERS
; i
++)
132 pClient
->Mid
->Bufs
[i
].pClient
= pClient
;
136 pClient
->DeviceType
= DeviceType
;
137 pClient
->dwCallback
= ((LPMIDIOPENDESC
)Param1
)->dwCallback
;
138 pClient
->dwInstance
= ((LPMIDIOPENDESC
)Param1
)->dwInstance
;
139 pClient
->hMidi
= ((LPMIDIOPENDESC
)Param1
)->hMidi
;
140 pClient
->dwFlags
= Param2
;
142 Result
= OpenDevice(DeviceType
, ID
, &pClient
->DeviceHandle
, (GENERIC_READ
| GENERIC_WRITE
));
144 if ( Result
!= MMSYSERR_NOERROR
)
150 pClient
->Event
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
152 if ( !pClient
->Event
)
155 return MMSYSERR_NOMEM
;
158 if (DeviceType
== MidiInDevice
)
161 pClient
->AuxEvent1
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
162 if (pClient
->AuxEvent1
== NULL
)
165 return MMSYSERR_NOMEM
;
168 pClient
->AuxEvent2
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
);
169 if (pClient
->AuxEvent2
== NULL
)
172 return MMSYSERR_NOMEM
;
179 WaitForSingleObject(pClient
->AuxEvent2
, INFINITE
);
182 PMIDIALLOC
*pUserHandle
;
183 pUserHandle
= (PMIDIALLOC
*) User
;
184 *pUserHandle
= pClient
;
188 return MMSYSERR_NOERROR
;
193 static DWORD
WriteMidi(PBYTE pData
, ULONG Length
, PMIDIALLOC pClient
)
197 DPRINT("IOCTL_MIDI_PLAY == %d [%x]\n", IOCTL_MIDI_PLAY
, IOCTL_MIDI_PLAY
);
199 if ( !DeviceIoControl(pClient
->DeviceHandle
, IOCTL_MIDI_PLAY
, (PVOID
)pData
,
200 Length
, NULL
, 0, &BytesReturned
, NULL
))
201 return TranslateStatus();
203 return MMSYSERR_NOERROR
;
207 static int GetMidiLength(PMIDIALLOC pClient
, BYTE b
)
211 // Realtime message - leave running status
212 return 1; // Write one byte
217 case 0xF0: case 0xF4: case 0xF5: case 0xF6: case 0xF7:
221 case 0xF1: case 0xF3:
232 case 0x80: case 0x90: case 0xA0: case 0xB0: case 0xE0:
236 case 0xC0: case 0xD0:
241 return (pClient
->l
- 1); // uses previous value if data byte (running status)
246 /* ----------------------------------------------------------------------------
248 ----------------------------------------------------------------------------- */
250 APIENTRY DWORD
midMessage(DWORD dwId
, DWORD dwMessage
, DWORD dwUser
, DWORD dwParam1
, DWORD dwParam2
)
252 DPRINT("midMessage\n");
253 return MMSYSERR_NOERROR
;
256 case MIDM_GETNUMDEVS
:
257 DPRINT("MIDM_GETNUMDEVS");
258 return GetDeviceCount(MidiInDevice
);
260 case MIDM_GETDEVCAPS
:
261 DPRINT("MIDM_GETDEVCAPS");
262 return GetDeviceCapabilities(dwId
, MidiInDevice
, (LPBYTE
)dwParam1
, (DWORD
)dwParam2
);
266 return MMSYSERR_NOERROR
;
269 DPRINT("MIDM_CLOSE");
270 return MMSYSERR_NOERROR
;
273 DPRINT("MIDM_ADDBUFFER");
274 return MMSYSERR_NOERROR
;
277 DPRINT("MIDM_PAUSE");
278 return MMSYSERR_NOERROR
;
281 DPRINT("MIDM_RESTART");
282 return MMSYSERR_NOERROR
;
285 DPRINT("MIDM_RESET");
286 return MMSYSERR_NOERROR
;
289 return MMSYSERR_NOTSUPPORTED
;
292 // the function should never get to this point
293 //FIXME: Would it be wise to assert here?
294 return MMSYSERR_NOTSUPPORTED
;
297 APIENTRY DWORD
modMessage(DWORD ID
, DWORD Message
, DWORD User
, DWORD Param1
, DWORD Param2
)
299 DPRINT("modMessage\n");
303 case MODM_GETNUMDEVS
:
304 DPRINT("MODM_GETNUMDEVS == %d\n", (int)GetDeviceCount(MidiOutDevice
));
305 return GetDeviceCount(MidiOutDevice
);
307 case MODM_GETDEVCAPS
:
308 DPRINT("MODM_GETDEVCAPS");
309 return GetDeviceCapabilities(ID
, MidiOutDevice
, (LPBYTE
)Param1
, (DWORD
)Param2
);
312 return OpenMidiDevice(MidiOutDevice
, ID
, User
, Param1
, Param2
);
315 DPRINT("MODM_CLOSE");
316 return MMSYSERR_NOTSUPPORTED
;
323 for (i
= 0; i
< 4; i
++) {
324 b
[i
] = (BYTE
)(Param1
% 256);
327 return WriteMidi(b
, GetMidiLength((PMIDIALLOC
)User
, b
[0]),
331 DPRINT("MODM_LONGDATA");
332 return MMSYSERR_NOTSUPPORTED
;
335 DPRINT("MODM_RESET");
336 return MMSYSERR_NOTSUPPORTED
;
339 DPRINT("MODM_SETVOLUME");
340 return MMSYSERR_NOTSUPPORTED
;
343 DPRINT("MODM_GETVOLUME");
344 return MMSYSERR_NOTSUPPORTED
;
346 case MODM_CACHEPATCHES
:
347 DPRINT("MODM_CACHEPATCHES");
348 return MMSYSERR_NOTSUPPORTED
;
350 case MODM_CACHEDRUMPATCHES
:
351 DPRINT("MODM_CACHEDRUMPATCHES");
352 return MMSYSERR_NOTSUPPORTED
;
356 return MMSYSERR_NOTSUPPORTED
;