update for HEAD-2003091401
[reactos.git] / lib / winmm / midiout.c
1 /*
2  *  WinMM (midiout.c) : MIDI output related functions
3  *
4  *  [8-18-2003] AG: Started adding stubs and implemented a few functions
5 */
6
7 #include <windows.h>
8 typedef UINT *LPUINT;
9 #include <mmsystem.h>
10 #include "winmm.h"
11
12 #define NDEBUG
13 #include <debug.h>
14
15
16 #define IsValidMidiOutHandle(hmo) \
17     (((LPMidiOutHandleInfo*)hmo < mo_HandleInfo) || \
18      ((LPMidiOutHandleInfo*)hmo >= mo_HandleInfo + (mo_HandleCount * sizeof(MidiOutHandleInfo))))
19
20
21 LPMidiOutDeviceInfo *mo_DeviceInfo = NULL;
22 UINT mo_DeviceCount = 0;
23 LPMidiOutHandleInfo *mo_HandleInfo = NULL;
24 UINT mo_HandleCount = 0;
25
26
27 /* ------------------------------------------------------------------------- */
28
29 MMRESULT WINAPI midiOutOpen(
30     LPHMIDIOUT lphmo,
31     UINT uDeviceID,
32     DWORD dwCallback,
33     DWORD dwCallbackInstance,
34     DWORD dwFlags)
35 {
36     // TODO: Add device open checking and return MMSYSERR_ALLOCATED, but what
37     // happens for multi-client drivers?
38     // Also, MIDI_MAPPER needs to be implemented somehow...
39
40     MidiOutHandleInfo *Info = NULL;
41     int i;
42     
43     if (! lphmo)
44         return MMSYSERR_INVALPARAM;
45
46     if ((uDeviceID >= mo_DeviceCount) && (uDeviceID != MIDI_MAPPER))
47         return MMSYSERR_BADDEVICEID;
48
49     // Make sure we have a callback address if a callback is desired
50     if ((! dwCallback) && (dwFlags != CALLBACK_NULL))
51         return MMSYSERR_INVALPARAM;
52
53
54     // Check existing handles to see if one is free
55     for (i = 0; i < mo_HandleCount; i ++)
56         if (! mo_HandleInfo[i]->IsOpen)
57         {
58             Info = mo_HandleInfo[i];
59             break;
60         }
61
62     // Allocate a new handle info structure
63     if (! Info)
64     {
65         mo_HandleCount ++;
66         
67         LPMidiOutHandleInfo *Old = mo_HandleInfo;
68
69         // This was before I added file mapping stuff
70 //        if (! mo_HandleInfo)
71 //            mo_HandleInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(MidiOutHandleInfo) * mo_HandleCount);
72 //        else
73 //            mo_HandleInfo = HeapReAlloc(GetProcessHeap(), 0, mo_HandleInfo, sizeof(MidiOutHandleInfo) * mo_HandleCount);
74             
75         if (! mo_HandleInfo)
76         {
77             mo_HandleCount --;
78             mo_HandleInfo = Old;
79             return MMSYSERR_NOMEM;  // Correct?
80         }
81         
82         Info = mo_HandleInfo[mo_HandleCount - 1];
83     }
84
85     Info->DeviceID = uDeviceID;
86
87     // Pretend we opened OK (really need to query device driver)
88     Info->IsOpen = TRUE;
89     
90     if (Info->IsOpen)
91     {
92         LPMIDICALLBACK mo_Proc = (LPMIDICALLBACK) dwCallback;
93
94         switch(dwFlags)
95         {
96             case CALLBACK_FUNCTION :
97                 mo_Proc((HMIDIOUT) Info, MM_MOM_OPEN, dwCallbackInstance, 0, 0);
98                 break;
99
100             case CALLBACK_EVENT :
101                 // Do something
102                 break;
103
104             case CALLBACK_THREAD :
105                 // Do something
106                 break;
107
108             case CALLBACK_WINDOW :
109                 // Do something
110                 break;
111         }
112     }
113     
114     else
115         return MMSYSERR_ERROR;  // Correct if can't be opened?
116
117     // Copy the handle (really a pointer to Info):
118     *lphmo = (HMIDIOUT) Info;
119
120     return MMSYSERR_NOERROR;
121 }
122
123
124 MMRESULT WINAPI midiOutClose(HMIDIOUT hmo)
125 {
126     LPMidiOutHandleInfo Info = NULL;
127
128     if (IsValidMidiOutHandle(hmo))
129         return MMSYSERR_INVALHANDLE;
130     
131     // Check if buffers still queued and return MIDIERR_STILLPLAYING if so...
132     // TODO
133     
134     Info = (LPMidiOutHandleInfo) hmo;
135     Info->IsOpen = FALSE;
136     
137     return MMSYSERR_NOERROR;
138 }
139
140
141 MMRESULT WINAPI midiOutGetDevCaps(
142     UINT uDeviceID,
143     LPMIDIOUTCAPS lpMidiOutCaps,
144     UINT cbMidiOutCaps)
145 {
146     UNIMPLEMENTED;
147     return MMSYSERR_NOERROR;
148 }
149
150
151 MMRESULT WINAPI midiOutGetErrorText(
152     MMRESULT mmrError,
153     LPSTR lpText,
154     UINT cchText)
155 {
156     if (! cchText)
157         return MMSYSERR_NOERROR;
158
159     if (! lpText)
160         return MMSYSERR_INVALPARAM;
161
162     if (((mmrError >= MMSYSERR_BASE) && (mmrError <= MMSYSERR_LASTERROR)) ||
163         ((mmrError >= MIDIERR_BASE) && (mmrError <= MIDIERR_LASTERROR)))
164     {
165 //        LoadString(GetModuleHandle(NULL), mmrError, lpText, cchText);  // bytes/chars?
166         return MMSYSERR_NOERROR;
167     }
168     else
169         return MMSYSERR_BADERRNUM;
170 }
171
172
173 MMRESULT WINAPI midiOutGetID(
174     HMIDIOUT hmo,
175     LPUINT puDeviceID)
176 {
177     // What triggers MMSYSERR_NODRIVER and MMSYSERR_NOMEM error codes?
178
179     LPMidiOutHandleInfo Info = NULL;
180     
181     if (! puDeviceID)
182         return MMSYSERR_INVALPARAM;
183
184     if (IsValidMidiOutHandle(hmo))
185         return MMSYSERR_INVALHANDLE;
186     
187     Info = (LPMidiOutHandleInfo) hmo;
188     *puDeviceID = Info->DeviceID;
189
190     return MMSYSERR_NOERROR;
191 }
192
193
194 UINT WINAPI midiOutGetNumDevs(VOID)
195 {
196     // +1 for MIDI_MAPPER :
197     return mo_DeviceCount ? mo_DeviceCount + 1 : 0;
198 }
199
200
201 MMRESULT WINAPI midiOutSetVolume(
202     HMIDIOUT hmo,
203     DWORD dwVolume)
204 {
205     if (IsValidMidiOutHandle(hmo))
206         return MMSYSERR_INVALHANDLE;
207
208     UNIMPLEMENTED;
209     return MMSYSERR_NOERROR;
210 }
211
212
213 MMRESULT WINAPI midiOutGetVolume(
214     HMIDIOUT hmo,
215     LPDWORD lpdwVolume)
216 {
217     if (IsValidMidiOutHandle(hmo))
218         return MMSYSERR_INVALHANDLE;
219
220     UNIMPLEMENTED;
221     return MMSYSERR_NOERROR;
222 }
223
224
225 MMRESULT WINAPI midiOutLongMsg(
226     HMIDIOUT hmo,
227     LPMIDIHDR lpMidiOutHdr,
228     UINT cbMidiOutHdr)
229 {
230     if (IsValidMidiOutHandle(hmo))
231         return MMSYSERR_INVALHANDLE;
232
233     UNIMPLEMENTED;
234     return MMSYSERR_NOERROR;
235 }
236
237
238 // This is *supposed* to return a DWORD:
239 MMRESULT WINAPI midiOutMessage(
240     HMIDIOUT hmo,
241     UINT msg,
242     DWORD dw1,
243     DWORD dw2)
244 {
245     if (IsValidMidiOutHandle(hmo))
246         return MMSYSERR_INVALHANDLE;
247
248     UNIMPLEMENTED;
249     return 0;
250 }
251
252
253 MMRESULT WINAPI midiOutPrepareHeader(
254     HMIDIOUT hmo,
255     LPMIDIHDR lpMidiOutHdr,
256     UINT cbMidiOutHdr)
257 {
258     if (IsValidMidiOutHandle(hmo))
259         return MMSYSERR_INVALHANDLE;
260
261     if (! lpMidiOutHdr)
262         return MMSYSERR_INVALPARAM;
263         
264     if (! lpMidiOutHdr->lpData)
265         return MMSYSERR_INVALPARAM;
266
267     // Yup, we're prepared! dwFlags must be 0 to begin with, so no | needed:
268     lpMidiOutHdr->dwFlags = MHDR_PREPARED;
269
270     return MMSYSERR_NOERROR;
271 }
272
273
274 MMRESULT WINAPI midiOutUnprepareHeader(
275     HMIDIOUT hmo,
276     LPMIDIHDR lpMidiOutHdr,
277     UINT cbMidiOutHdr)
278 {
279     if (IsValidMidiOutHandle(hmo))
280         return MMSYSERR_INVALHANDLE;
281
282     if (! lpMidiOutHdr)
283         return MMSYSERR_INVALPARAM;
284         
285     if (! lpMidiOutHdr->lpData)
286         return MMSYSERR_INVALPARAM;
287
288     // We're unprepared! Clear the MHDR_PREPARED flag:
289     lpMidiOutHdr->dwFlags &= ! MHDR_PREPARED;
290
291     return MMSYSERR_NOERROR;
292 }
293
294
295 MMRESULT WINAPI midiOutReset(HMIDIOUT hmo)
296 {
297     if (IsValidMidiOutHandle(hmo))
298         return MMSYSERR_INVALHANDLE;
299
300     UNIMPLEMENTED;
301     return MMSYSERR_NOERROR;
302 }
303
304
305 MMRESULT WINAPI midiOutShortMsg(
306     HMIDIOUT hmo,
307     DWORD dwMsg)
308 {
309     if (IsValidMidiOutHandle(hmo))
310         return MMSYSERR_INVALHANDLE;
311
312     UNIMPLEMENTED;
313     return MMSYSERR_NOERROR;
314 }
315
316
317 MMRESULT WINAPI midiOutCacheDrumPatches(
318     HMIDIOUT hmo,
319     UINT wPatch,
320     WORD* lpKeyArray,
321     UINT wFlags)
322 {
323     UNIMPLEMENTED;
324     return MMSYSERR_NOERROR;
325 }
326
327
328 MMRESULT WINAPI midiOutCachePatches(
329     HMIDIOUT hmo,
330     UINT wBank,
331     WORD* lpPatchArray,
332     UINT wFlags)
333 {
334     UNIMPLEMENTED;
335     return MMSYSERR_NOERROR;
336 }
337
338
339 /* ------------------------------------------------------------------------- */
340
341 void mo_Init()
342 {
343     // Internal routine for initializing MIDI-Out related stuff
344
345     BOOL First;
346     HANDLE modi_fm, mohi_fm;
347     
348 //    modi_fm = CreateFileMapping((HANDLE)0xFFFFFFFF, (LPSECURITY_ATTRIBUTES)NULL,
349 //                            PAGE_READWRITE, 0, 64 * 1024, FM_MIDI_OUT_DEV_INFO);
350
351     First = ! GetLastError();
352
353 //    mo_DeviceInfo = MapViewOfFile(modi_fm, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(SomeStruct)
354     
355     if (First)
356     {
357         mo_DeviceInfo = MapViewOfFile(modi_fm, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(MidiOutDeviceInfo));
358
359         // Just set up a fake device for now
360         mo_DeviceCount ++;  // need mapping for this
361 //        mo_DeviceInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(MidiOutDeviceInfo) * mo_DeviceCount);
362         // Set info now
363         
364         UnmapViewOfFile(mo_DeviceInfo);
365     }
366
367 //    mohi_fm = CreateFileMapping((HANDLE)0xFFFFFFFF, (LPSECURITY_ATTRIBUTES)NULL,
368 //                           PAGE_READWRITE, 0, 64 * 1024, FM_MIDI_OUT_HANDLE_INFO);
369 }