dinput: BuildActionMap and SetActionMap stubs for generic joystick.
[wine] / dlls / winmm / waveform.c
1 /*
2  * Copyright 1993      Martin Ayotte
3  *           1998-2002 Eric Pouech
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <string.h>
23
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26 #include "windef.h"
27 #include "winbase.h"
28 #include "mmsystem.h"
29 #include "winuser.h"
30 #include "winnls.h"
31 #include "winternl.h"
32 #include "winemm.h"
33
34 #include "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(winmm);
37
38 static UINT WAVE_Open(HANDLE* lphndl, UINT uDeviceID, UINT uType,
39                       LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
40                       DWORD_PTR dwInstance, DWORD dwFlags)
41 {
42     HANDLE              handle;
43     LPWINE_MLD          wmld;
44     DWORD               dwRet;
45     WAVEOPENDESC        wod;
46
47     TRACE("(%p, %d, %s, %p, %08lX, %08lX, %08X);\n",
48           lphndl, (int)uDeviceID, (uType==MMDRV_WAVEOUT)?"Out":"In", lpFormat, dwCallback,
49           dwInstance, dwFlags);
50
51     if (dwFlags & WAVE_FORMAT_QUERY)
52         TRACE("WAVE_FORMAT_QUERY requested !\n");
53
54     dwRet = WINMM_CheckCallback(dwCallback, dwFlags, FALSE);
55     if (dwRet != MMSYSERR_NOERROR)
56         return dwRet;
57
58     if (lpFormat == NULL) {
59         WARN("bad format\n");
60         return WAVERR_BADFORMAT;
61     }
62
63     if ((dwFlags & WAVE_MAPPED) && (uDeviceID == (UINT)-1)) {
64         WARN("invalid parameter\n");
65         return MMSYSERR_INVALPARAM;
66     }
67
68     /* may have a PCMWAVEFORMAT rather than a WAVEFORMATEX so don't read cbSize */
69     TRACE("wFormatTag=%u, nChannels=%u, nSamplesPerSec=%u, nAvgBytesPerSec=%u, nBlockAlign=%u, wBitsPerSample=%u\n",
70           lpFormat->wFormatTag, lpFormat->nChannels, lpFormat->nSamplesPerSec,
71           lpFormat->nAvgBytesPerSec, lpFormat->nBlockAlign, lpFormat->wBitsPerSample);
72
73     if ((wmld = MMDRV_Alloc(sizeof(WINE_WAVE), uType, &handle,
74                             &dwFlags, &dwCallback, &dwInstance)) == NULL) {
75         return MMSYSERR_NOMEM;
76     }
77
78     wod.hWave = handle;
79     wod.lpFormat = (LPWAVEFORMATEX)lpFormat;  /* should the struct be copied iso pointer? */
80     wod.dwCallback = dwCallback;
81     wod.dwInstance = dwInstance;
82     wod.dnDevNode = 0L;
83
84     TRACE("cb=%08lx\n", wod.dwCallback);
85
86     for (;;) {
87         if (dwFlags & WAVE_MAPPED) {
88             wod.uMappedDeviceID = uDeviceID;
89             uDeviceID = WAVE_MAPPER;
90         } else {
91             wod.uMappedDeviceID = -1;
92         }
93         wmld->uDeviceID = uDeviceID;
94     
95         dwRet = MMDRV_Open(wmld, (uType == MMDRV_WAVEOUT) ? WODM_OPEN : WIDM_OPEN,
96                            (DWORD_PTR)&wod, dwFlags);
97
98         TRACE("dwRet = %s\n", WINMM_ErrorToString(dwRet));
99         if (dwRet != WAVERR_BADFORMAT ||
100             ((dwFlags & (WAVE_MAPPED|WAVE_FORMAT_DIRECT)) != 0) || (uDeviceID == WAVE_MAPPER)) break;
101         /* if we ask for a format which isn't supported by the physical driver, 
102          * let's try to map it through the wave mapper (except, if we already tried
103          * or user didn't allow us to use acm codecs or the device is already the mapper)
104          */
105         dwFlags |= WAVE_MAPPED;
106         /* we shall loop only one */
107     }
108
109     if ((dwFlags & WAVE_FORMAT_QUERY) || dwRet != MMSYSERR_NOERROR) {
110         MMDRV_Free(handle, wmld);
111         handle = 0;
112     }
113
114     if (lphndl != NULL) *lphndl = handle;
115     TRACE("=> %s hWave=%p\n", WINMM_ErrorToString(dwRet), handle);
116
117     return dwRet;
118 }
119
120 /**************************************************************************
121  *                              waveOutGetNumDevs               [WINMM.@]
122  */
123 UINT WINAPI waveOutGetNumDevs(void)
124 {
125     return MMDRV_GetNum(MMDRV_WAVEOUT);
126 }
127
128 /**************************************************************************
129  *                              waveOutGetDevCapsA              [WINMM.@]
130  */
131 UINT WINAPI waveOutGetDevCapsA(UINT_PTR uDeviceID, LPWAVEOUTCAPSA lpCaps,
132                                UINT uSize)
133 {
134     WAVEOUTCAPSW        wocW;
135     UINT                ret;
136
137     if (lpCaps == NULL)        return MMSYSERR_INVALPARAM;
138
139     ret = waveOutGetDevCapsW(uDeviceID, &wocW, sizeof(wocW));
140
141     if (ret == MMSYSERR_NOERROR) {
142         WAVEOUTCAPSA wocA;
143         wocA.wMid           = wocW.wMid;
144         wocA.wPid           = wocW.wPid;
145         wocA.vDriverVersion = wocW.vDriverVersion;
146         WideCharToMultiByte( CP_ACP, 0, wocW.szPname, -1, wocA.szPname,
147                              sizeof(wocA.szPname), NULL, NULL );
148         wocA.dwFormats      = wocW.dwFormats;
149         wocA.wChannels      = wocW.wChannels;
150         wocA.dwSupport      = wocW.dwSupport;
151         memcpy(lpCaps, &wocA, min(uSize, sizeof(wocA)));
152     }
153     return ret;
154 }
155
156 /**************************************************************************
157  *                              waveOutGetDevCapsW              [WINMM.@]
158  */
159 UINT WINAPI waveOutGetDevCapsW(UINT_PTR uDeviceID, LPWAVEOUTCAPSW lpCaps,
160                                UINT uSize)
161 {
162     LPWINE_MLD          wmld;
163
164     TRACE("(%lu %p %u)!\n", uDeviceID, lpCaps, uSize);
165
166     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
167
168     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEOUT, TRUE)) == NULL)
169         return MMSYSERR_BADDEVICEID;
170
171     return MMDRV_Message(wmld, WODM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize);
172 }
173
174 /**************************************************************************
175  *                              waveOutGetErrorTextA    [WINMM.@]
176  *                              waveInGetErrorTextA     [WINMM.@]
177  */
178 UINT WINAPI waveOutGetErrorTextA(UINT uError, LPSTR lpText, UINT uSize)
179 {
180     UINT        ret;
181
182     if (lpText == NULL) ret = MMSYSERR_INVALPARAM;
183     else if (uSize == 0) ret = MMSYSERR_NOERROR;
184     else
185     {
186         LPWSTR  xstr = HeapAlloc(GetProcessHeap(), 0, uSize * sizeof(WCHAR));
187         if (!xstr) ret = MMSYSERR_NOMEM;
188         else
189         {
190             ret = waveOutGetErrorTextW(uError, xstr, uSize);
191             if (ret == MMSYSERR_NOERROR)
192                 WideCharToMultiByte(CP_ACP, 0, xstr, -1, lpText, uSize, NULL, NULL);
193             HeapFree(GetProcessHeap(), 0, xstr);
194         }
195     }
196     return ret;
197 }
198
199 /**************************************************************************
200  *                              waveOutGetErrorTextW    [WINMM.@]
201  *                              waveInGetErrorTextW     [WINMM.@]
202  */
203 UINT WINAPI waveOutGetErrorTextW(UINT uError, LPWSTR lpText, UINT uSize)
204 {
205     UINT        ret = MMSYSERR_BADERRNUM;
206
207     if (lpText == NULL) ret = MMSYSERR_INVALPARAM;
208     else if (uSize == 0) ret = MMSYSERR_NOERROR;
209     else if (
210                /* test has been removed because MMSYSERR_BASE is 0, and gcc did emit
211                 * a warning for the test was always true */
212                (/*uError >= MMSYSERR_BASE && */ uError <= MMSYSERR_LASTERROR) ||
213                (uError >= WAVERR_BASE  && uError <= WAVERR_LASTERROR)) {
214         if (LoadStringW(hWinMM32Instance,
215                         uError, lpText, uSize) > 0) {
216             ret = MMSYSERR_NOERROR;
217         }
218     }
219     return ret;
220 }
221
222 /**************************************************************************
223  *                      waveOutOpen                     [WINMM.@]
224  * All the args/structs have the same layout as the win16 equivalents
225  */
226 MMRESULT WINAPI waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID,
227                        LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
228                        DWORD_PTR dwInstance, DWORD dwFlags)
229 {
230     return WAVE_Open((HANDLE*)lphWaveOut, uDeviceID, MMDRV_WAVEOUT, lpFormat,
231                      dwCallback, dwInstance, dwFlags);
232 }
233
234 /**************************************************************************
235  *                              waveOutClose            [WINMM.@]
236  */
237 UINT WINAPI waveOutClose(HWAVEOUT hWaveOut)
238 {
239     LPWINE_MLD          wmld;
240     DWORD               dwRet;
241
242     TRACE("(%p)\n", hWaveOut);
243
244     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
245         return MMSYSERR_INVALHANDLE;
246
247     dwRet = MMDRV_Close(wmld, WODM_CLOSE);
248     if (dwRet != WAVERR_STILLPLAYING)
249         MMDRV_Free(hWaveOut, wmld);
250
251     return dwRet;
252 }
253
254 /**************************************************************************
255  *                              waveOutPrepareHeader    [WINMM.@]
256  */
257 UINT WINAPI waveOutPrepareHeader(HWAVEOUT hWaveOut,
258                                  WAVEHDR* lpWaveOutHdr, UINT uSize)
259 {
260     LPWINE_MLD          wmld;
261     UINT                result;
262
263     TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
264
265     if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR))
266         return MMSYSERR_INVALPARAM;
267
268     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
269         return MMSYSERR_INVALHANDLE;
270
271     if ((result = MMDRV_Message(wmld, WODM_PREPARE, (DWORD_PTR)lpWaveOutHdr,
272                                 uSize)) != MMSYSERR_NOTSUPPORTED)
273         return result;
274
275     if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE)
276         return WAVERR_STILLPLAYING;
277
278     lpWaveOutHdr->dwFlags |= WHDR_PREPARED;
279     lpWaveOutHdr->dwFlags &= ~WHDR_DONE;
280
281     return MMSYSERR_NOERROR;
282 }
283
284 /**************************************************************************
285  *                              waveOutUnprepareHeader  [WINMM.@]
286  */
287 UINT WINAPI waveOutUnprepareHeader(HWAVEOUT hWaveOut,
288                                    LPWAVEHDR lpWaveOutHdr, UINT uSize)
289 {
290     LPWINE_MLD          wmld;
291     UINT                result;
292
293     TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
294
295     if (lpWaveOutHdr == NULL || uSize < sizeof (WAVEHDR))
296         return MMSYSERR_INVALPARAM;
297     
298     if (!(lpWaveOutHdr->dwFlags & WHDR_PREPARED)) {
299         return MMSYSERR_NOERROR;
300     }
301
302     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
303         return MMSYSERR_INVALHANDLE;
304
305     if ((result = MMDRV_Message(wmld, WODM_UNPREPARE, (DWORD_PTR)lpWaveOutHdr,
306                                 uSize)) != MMSYSERR_NOTSUPPORTED)
307         return result;
308
309     if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE)
310         return WAVERR_STILLPLAYING;
311
312     lpWaveOutHdr->dwFlags &= ~WHDR_PREPARED;
313     lpWaveOutHdr->dwFlags |= WHDR_DONE;
314
315     return MMSYSERR_NOERROR;
316 }
317
318 /**************************************************************************
319  *                              waveOutWrite            [WINMM.@]
320  */
321 UINT WINAPI waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr,
322                          UINT uSize)
323 {
324     LPWINE_MLD          wmld;
325
326     TRACE("(%p, %p, %u);\n", hWaveOut, lpWaveOutHdr, uSize);
327
328     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
329         return MMSYSERR_INVALHANDLE;
330
331     return MMDRV_Message(wmld, WODM_WRITE, (DWORD_PTR)lpWaveOutHdr, uSize);
332 }
333
334 /**************************************************************************
335  *                              waveOutBreakLoop        [WINMM.@]
336  */
337 UINT WINAPI waveOutBreakLoop(HWAVEOUT hWaveOut)
338 {
339     LPWINE_MLD          wmld;
340
341     TRACE("(%p);\n", hWaveOut);
342
343     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
344         return MMSYSERR_INVALHANDLE;
345     return MMDRV_Message(wmld, WODM_BREAKLOOP, 0L, 0L);
346 }
347
348 /**************************************************************************
349  *                              waveOutPause            [WINMM.@]
350  */
351 UINT WINAPI waveOutPause(HWAVEOUT hWaveOut)
352 {
353     LPWINE_MLD          wmld;
354
355     TRACE("(%p);\n", hWaveOut);
356
357     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
358         return MMSYSERR_INVALHANDLE;
359     return MMDRV_Message(wmld, WODM_PAUSE, 0L, 0L);
360 }
361
362 /**************************************************************************
363  *                              waveOutReset            [WINMM.@]
364  */
365 UINT WINAPI waveOutReset(HWAVEOUT hWaveOut)
366 {
367     LPWINE_MLD          wmld;
368
369     TRACE("(%p);\n", hWaveOut);
370
371     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
372         return MMSYSERR_INVALHANDLE;
373     return MMDRV_Message(wmld, WODM_RESET, 0L, 0L);
374 }
375
376 /**************************************************************************
377  *                              waveOutRestart          [WINMM.@]
378  */
379 UINT WINAPI waveOutRestart(HWAVEOUT hWaveOut)
380 {
381     LPWINE_MLD          wmld;
382
383     TRACE("(%p);\n", hWaveOut);
384
385     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
386         return MMSYSERR_INVALHANDLE;
387     return MMDRV_Message(wmld, WODM_RESTART, 0L, 0L);
388 }
389
390 /**************************************************************************
391  *                              waveOutGetPosition      [WINMM.@]
392  */
393 UINT WINAPI waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpTime,
394                                UINT uSize)
395 {
396     LPWINE_MLD          wmld;
397
398     TRACE("(%p, %p, %u);\n", hWaveOut, lpTime, uSize);
399
400     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
401         return MMSYSERR_INVALHANDLE;
402
403     return MMDRV_Message(wmld, WODM_GETPOS, (DWORD_PTR)lpTime, uSize);
404 }
405
406 /**************************************************************************
407  *                              waveOutGetPitch         [WINMM.@]
408  */
409 UINT WINAPI waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdw)
410 {
411     LPWINE_MLD          wmld;
412
413     TRACE("(%p, %p);\n", hWaveOut, lpdw);
414
415     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
416         return MMSYSERR_INVALHANDLE;
417     return MMDRV_Message(wmld, WODM_GETPITCH, (DWORD_PTR)lpdw, 0L);
418 }
419
420 /**************************************************************************
421  *                              waveOutSetPitch         [WINMM.@]
422  */
423 UINT WINAPI waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dw)
424 {
425     LPWINE_MLD          wmld;
426
427     TRACE("(%p, %08x);\n", hWaveOut, dw);
428
429     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
430         return MMSYSERR_INVALHANDLE;
431     return MMDRV_Message(wmld, WODM_SETPITCH, dw, 0L);
432 }
433
434 /**************************************************************************
435  *                              waveOutGetPlaybackRate  [WINMM.@]
436  */
437 UINT WINAPI waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdw)
438 {
439     LPWINE_MLD          wmld;
440
441     TRACE("(%p, %p);\n", hWaveOut, lpdw);
442
443     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
444         return MMSYSERR_INVALHANDLE;
445     return MMDRV_Message(wmld, WODM_GETPLAYBACKRATE, (DWORD_PTR)lpdw, 0L);
446 }
447
448 /**************************************************************************
449  *                              waveOutSetPlaybackRate  [WINMM.@]
450  */
451 UINT WINAPI waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dw)
452 {
453     LPWINE_MLD          wmld;
454
455     TRACE("(%p, %08x);\n", hWaveOut, dw);
456
457     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
458         return MMSYSERR_INVALHANDLE;
459     return MMDRV_Message(wmld, WODM_SETPLAYBACKRATE, dw, 0L);
460 }
461
462 /**************************************************************************
463  *                              waveOutGetVolume        [WINMM.@]
464  */
465 UINT WINAPI waveOutGetVolume(HWAVEOUT hWaveOut, LPDWORD lpdw)
466 {
467     LPWINE_MLD          wmld;
468
469     TRACE("(%p, %p);\n", hWaveOut, lpdw);
470
471     if (lpdw == NULL) {
472         WARN("invalid parameter\n");
473         return MMSYSERR_INVALPARAM;
474     }
475
476     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
477         return MMSYSERR_INVALHANDLE;
478
479     return MMDRV_Message(wmld, WODM_GETVOLUME, (DWORD_PTR)lpdw, 0L);
480 }
481
482 /**************************************************************************
483  *                              waveOutSetVolume        [WINMM.@]
484  */
485 UINT WINAPI waveOutSetVolume(HWAVEOUT hWaveOut, DWORD dw)
486 {
487     LPWINE_MLD          wmld;
488
489     TRACE("(%p, %08x);\n", hWaveOut, dw);
490
491      if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) == NULL)
492         return MMSYSERR_INVALHANDLE;
493
494     return MMDRV_Message(wmld, WODM_SETVOLUME, dw, 0L);
495 }
496
497 /**************************************************************************
498  *                              waveOutGetID            [WINMM.@]
499  */
500 UINT WINAPI waveOutGetID(HWAVEOUT hWaveOut, UINT* lpuDeviceID)
501 {
502     LPWINE_MLD          wmld;
503
504     TRACE("(%p, %p);\n", hWaveOut, lpuDeviceID);
505
506     if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
507
508     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL)
509         return MMSYSERR_INVALHANDLE;
510
511     *lpuDeviceID = wmld->uDeviceID;
512     return 0;
513 }
514
515 /**************************************************************************
516  *                              waveOutMessage          [WINMM.@]
517  */
518 UINT WINAPI waveOutMessage(HWAVEOUT hWaveOut, UINT uMessage,
519                            DWORD_PTR dwParam1, DWORD_PTR dwParam2)
520 {
521     LPWINE_MLD          wmld;
522
523     TRACE("(%p, %u, %ld, %ld)\n", hWaveOut, uMessage, dwParam1, dwParam2);
524
525     if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, FALSE)) == NULL) {
526         if ((wmld = MMDRV_Get(hWaveOut, MMDRV_WAVEOUT, TRUE)) != NULL) {
527             return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
528         }
529         WARN("invalid handle\n");
530         return MMSYSERR_INVALHANDLE;
531     }
532
533     /* from M$ KB */
534     if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER)) {
535         WARN("invalid parameter\n");
536         return MMSYSERR_INVALPARAM;
537     }
538
539     return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2);
540 }
541
542 /**************************************************************************
543  *                              waveInGetNumDevs                [WINMM.@]
544  */
545 UINT WINAPI waveInGetNumDevs(void)
546 {
547     return MMDRV_GetNum(MMDRV_WAVEIN);
548 }
549
550 /**************************************************************************
551  *                              waveInGetDevCapsW               [WINMM.@]
552  */
553 UINT WINAPI waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSize)
554 {
555     LPWINE_MLD          wmld;
556
557     TRACE("(%lu %p %u)!\n", uDeviceID, lpCaps, uSize);
558
559     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
560
561     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_WAVEIN, TRUE)) == NULL)
562         return MMSYSERR_BADDEVICEID;
563
564     return MMDRV_Message(wmld, WIDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize);
565 }
566
567 /**************************************************************************
568  *                              waveInGetDevCapsA               [WINMM.@]
569  */
570 UINT WINAPI waveInGetDevCapsA(UINT_PTR uDeviceID, LPWAVEINCAPSA lpCaps, UINT uSize)
571 {
572     WAVEINCAPSW         wicW;
573     UINT                ret;
574
575     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
576
577     ret = waveInGetDevCapsW(uDeviceID, &wicW, sizeof(wicW));
578
579     if (ret == MMSYSERR_NOERROR) {
580         WAVEINCAPSA wicA;
581         wicA.wMid           = wicW.wMid;
582         wicA.wPid           = wicW.wPid;
583         wicA.vDriverVersion = wicW.vDriverVersion;
584         WideCharToMultiByte( CP_ACP, 0, wicW.szPname, -1, wicA.szPname,
585                              sizeof(wicA.szPname), NULL, NULL );
586         wicA.dwFormats      = wicW.dwFormats;
587         wicA.wChannels      = wicW.wChannels;
588         memcpy(lpCaps, &wicA, min(uSize, sizeof(wicA)));
589     }
590     return ret;
591 }
592
593 /**************************************************************************
594  *                              waveInOpen                      [WINMM.@]
595  */
596 MMRESULT WINAPI waveInOpen(HWAVEIN* lphWaveIn, UINT uDeviceID,
597                            LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
598                            DWORD_PTR dwInstance, DWORD dwFlags)
599 {
600     return WAVE_Open((HANDLE*)lphWaveIn, uDeviceID, MMDRV_WAVEIN, lpFormat,
601                      dwCallback, dwInstance, dwFlags);
602 }
603
604 /**************************************************************************
605  *                              waveInClose                     [WINMM.@]
606  */
607 UINT WINAPI waveInClose(HWAVEIN hWaveIn)
608 {
609     LPWINE_MLD          wmld;
610     DWORD               dwRet;
611
612     TRACE("(%p)\n", hWaveIn);
613
614     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
615         return MMSYSERR_INVALHANDLE;
616
617     dwRet = MMDRV_Message(wmld, WIDM_CLOSE, 0L, 0L);
618     if (dwRet != WAVERR_STILLPLAYING)
619         MMDRV_Free(hWaveIn, wmld);
620     return dwRet;
621 }
622
623 /**************************************************************************
624  *                              waveInPrepareHeader             [WINMM.@]
625  */
626 UINT WINAPI waveInPrepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
627                                 UINT uSize)
628 {
629     LPWINE_MLD          wmld;
630     UINT                result;
631
632     TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
633
634     if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR))
635         return MMSYSERR_INVALPARAM;
636
637     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
638         return MMSYSERR_INVALHANDLE;
639
640     if ((result = MMDRV_Message(wmld, WIDM_PREPARE, (DWORD_PTR)lpWaveInHdr,
641                                 uSize)) != MMSYSERR_NOTSUPPORTED)
642         return result;
643
644     if (lpWaveInHdr->dwFlags & WHDR_INQUEUE)
645         return WAVERR_STILLPLAYING;
646
647     lpWaveInHdr->dwFlags |= WHDR_PREPARED;
648     lpWaveInHdr->dwFlags &= ~WHDR_DONE;
649     lpWaveInHdr->dwBytesRecorded = 0;
650
651     return MMSYSERR_NOERROR;
652 }
653
654 /**************************************************************************
655  *                              waveInUnprepareHeader   [WINMM.@]
656  */
657 UINT WINAPI waveInUnprepareHeader(HWAVEIN hWaveIn, WAVEHDR* lpWaveInHdr,
658                                   UINT uSize)
659 {
660     LPWINE_MLD          wmld;
661     UINT                result;
662
663     TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
664
665     if (lpWaveInHdr == NULL || uSize < sizeof (WAVEHDR))
666         return MMSYSERR_INVALPARAM;
667
668     if (!(lpWaveInHdr->dwFlags & WHDR_PREPARED))
669         return MMSYSERR_NOERROR;
670
671     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
672         return MMSYSERR_INVALHANDLE;
673
674     if ((result = MMDRV_Message(wmld, WIDM_UNPREPARE, (DWORD_PTR)lpWaveInHdr,
675                                 uSize)) != MMSYSERR_NOTSUPPORTED)
676         return result;
677
678     if (lpWaveInHdr->dwFlags & WHDR_INQUEUE)
679         return WAVERR_STILLPLAYING;
680
681     lpWaveInHdr->dwFlags &= ~WHDR_PREPARED;
682     lpWaveInHdr->dwFlags |= WHDR_DONE;
683
684     return MMSYSERR_NOERROR;
685 }
686
687 /**************************************************************************
688  *                              waveInAddBuffer         [WINMM.@]
689  */
690 UINT WINAPI waveInAddBuffer(HWAVEIN hWaveIn,
691                             WAVEHDR* lpWaveInHdr, UINT uSize)
692 {
693     LPWINE_MLD          wmld;
694
695     TRACE("(%p, %p, %u);\n", hWaveIn, lpWaveInHdr, uSize);
696
697     if (lpWaveInHdr == NULL) return MMSYSERR_INVALPARAM;
698     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
699         return MMSYSERR_INVALHANDLE;
700
701     return MMDRV_Message(wmld, WIDM_ADDBUFFER, (DWORD_PTR)lpWaveInHdr, uSize);
702 }
703
704 /**************************************************************************
705  *                              waveInReset             [WINMM.@]
706  */
707 UINT WINAPI waveInReset(HWAVEIN hWaveIn)
708 {
709     LPWINE_MLD          wmld;
710
711     TRACE("(%p);\n", hWaveIn);
712
713     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
714         return MMSYSERR_INVALHANDLE;
715
716     return MMDRV_Message(wmld, WIDM_RESET, 0L, 0L);
717 }
718
719 /**************************************************************************
720  *                              waveInStart             [WINMM.@]
721  */
722 UINT WINAPI waveInStart(HWAVEIN hWaveIn)
723 {
724     LPWINE_MLD          wmld;
725
726     TRACE("(%p);\n", hWaveIn);
727
728     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
729         return MMSYSERR_INVALHANDLE;
730
731     return MMDRV_Message(wmld, WIDM_START, 0L, 0L);
732 }
733
734 /**************************************************************************
735  *                              waveInStop              [WINMM.@]
736  */
737 UINT WINAPI waveInStop(HWAVEIN hWaveIn)
738 {
739     LPWINE_MLD          wmld;
740
741     TRACE("(%p);\n", hWaveIn);
742
743     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
744         return MMSYSERR_INVALHANDLE;
745
746     return MMDRV_Message(wmld,WIDM_STOP, 0L, 0L);
747 }
748
749 /**************************************************************************
750  *                              waveInGetPosition       [WINMM.@]
751  */
752 UINT WINAPI waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpTime,
753                               UINT uSize)
754 {
755     LPWINE_MLD          wmld;
756
757     TRACE("(%p, %p, %u);\n", hWaveIn, lpTime, uSize);
758
759     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
760         return MMSYSERR_INVALHANDLE;
761
762     return MMDRV_Message(wmld, WIDM_GETPOS, (DWORD_PTR)lpTime, uSize);
763 }
764
765 /**************************************************************************
766  *                              waveInGetID                     [WINMM.@]
767  */
768 UINT WINAPI waveInGetID(HWAVEIN hWaveIn, UINT* lpuDeviceID)
769 {
770     LPWINE_MLD          wmld;
771
772     TRACE("(%p, %p);\n", hWaveIn, lpuDeviceID);
773
774     if (lpuDeviceID == NULL) return MMSYSERR_INVALHANDLE;
775
776     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL)
777         return MMSYSERR_INVALHANDLE;
778
779     *lpuDeviceID = wmld->uDeviceID;
780     return MMSYSERR_NOERROR;
781 }
782
783 /**************************************************************************
784  *                              waveInMessage           [WINMM.@]
785  */
786 UINT WINAPI waveInMessage(HWAVEIN hWaveIn, UINT uMessage,
787                           DWORD_PTR dwParam1, DWORD_PTR dwParam2)
788 {
789     LPWINE_MLD          wmld;
790
791     TRACE("(%p, %u, %ld, %ld)\n", hWaveIn, uMessage, dwParam1, dwParam2);
792
793     if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, FALSE)) == NULL) {
794         if ((wmld = MMDRV_Get(hWaveIn, MMDRV_WAVEIN, TRUE)) != NULL) {
795             return MMDRV_PhysicalFeatures(wmld, uMessage, dwParam1, dwParam2);
796         }
797         return MMSYSERR_INVALHANDLE;
798     }
799
800     /* from M$ KB */
801     if (uMessage < DRVM_IOCTL || (uMessage >= DRVM_IOCTL_LAST && uMessage < DRVM_MAPPER))
802         return MMSYSERR_INVALPARAM;
803
804
805     return MMDRV_Message(wmld, uMessage, dwParam1, dwParam2);
806 }
807
808 /**************************************************************************
809  * find out the real mixer ID depending on hmix (depends on dwFlags)
810  */
811 static UINT MIXER_GetDev(HMIXEROBJ hmix, DWORD dwFlags, LPWINE_MIXER * lplpwm)
812 {
813     LPWINE_MIXER        lpwm = NULL;
814     UINT                uRet = MMSYSERR_NOERROR;
815
816     switch (dwFlags & 0xF0000000ul) {
817     case MIXER_OBJECTF_MIXER:
818         lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, TRUE);
819         break;
820     case MIXER_OBJECTF_HMIXER:
821         lpwm = (LPWINE_MIXER)MMDRV_Get(hmix, MMDRV_MIXER, FALSE);
822         break;
823     case MIXER_OBJECTF_WAVEOUT:
824         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, TRUE,  MMDRV_MIXER);
825         break;
826     case MIXER_OBJECTF_HWAVEOUT:
827         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEOUT, FALSE, MMDRV_MIXER);
828         break;
829     case MIXER_OBJECTF_WAVEIN:
830         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN,  TRUE,  MMDRV_MIXER);
831         break;
832     case MIXER_OBJECTF_HWAVEIN:
833         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_WAVEIN,  FALSE, MMDRV_MIXER);
834         break;
835     case MIXER_OBJECTF_MIDIOUT:
836         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, TRUE,  MMDRV_MIXER);
837         break;
838     case MIXER_OBJECTF_HMIDIOUT:
839         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIOUT, FALSE, MMDRV_MIXER);
840         break;
841     case MIXER_OBJECTF_MIDIIN:
842         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN,  TRUE,  MMDRV_MIXER);
843         break;
844     case MIXER_OBJECTF_HMIDIIN:
845         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_MIDIIN,  FALSE, MMDRV_MIXER);
846         break;
847     case MIXER_OBJECTF_AUX:
848         lpwm = (LPWINE_MIXER)MMDRV_GetRelated(hmix, MMDRV_AUX,     TRUE,  MMDRV_MIXER);
849         break;
850     default:
851         WARN("Unsupported flag (%08lx)\n", dwFlags & 0xF0000000ul);
852         lpwm = 0;
853         uRet = MMSYSERR_INVALFLAG;
854         break;
855     }
856     *lplpwm = lpwm;
857     if (lpwm == 0 && uRet == MMSYSERR_NOERROR)
858         uRet = MMSYSERR_INVALPARAM;
859     return uRet;
860 }
861
862 /**************************************************************************
863  *                              mixerGetNumDevs                 [WINMM.@]
864  */
865 UINT WINAPI mixerGetNumDevs(void)
866 {
867     return MMDRV_GetNum(MMDRV_MIXER);
868 }
869
870 /**************************************************************************
871  *                              mixerGetDevCapsA                [WINMM.@]
872  */
873 UINT WINAPI mixerGetDevCapsA(UINT_PTR uDeviceID, LPMIXERCAPSA lpCaps, UINT uSize)
874 {
875     MIXERCAPSW micW;
876     UINT       ret;
877
878     if (lpCaps == NULL) return MMSYSERR_INVALPARAM;
879
880     ret = mixerGetDevCapsW(uDeviceID, &micW, sizeof(micW));
881
882     if (ret == MMSYSERR_NOERROR) {
883         MIXERCAPSA micA;
884         micA.wMid           = micW.wMid;
885         micA.wPid           = micW.wPid;
886         micA.vDriverVersion = micW.vDriverVersion;
887         WideCharToMultiByte( CP_ACP, 0, micW.szPname, -1, micA.szPname,
888                              sizeof(micA.szPname), NULL, NULL );
889         micA.fdwSupport     = micW.fdwSupport;
890         micA.cDestinations  = micW.cDestinations;
891         memcpy(lpCaps, &micA, min(uSize, sizeof(micA)));
892     }
893     return ret;
894 }
895
896 /**************************************************************************
897  *                              mixerGetDevCapsW                [WINMM.@]
898  */
899 UINT WINAPI mixerGetDevCapsW(UINT_PTR uDeviceID, LPMIXERCAPSW lpCaps, UINT uSize)
900 {
901     LPWINE_MLD wmld;
902
903     if (lpCaps == NULL)        return MMSYSERR_INVALPARAM;
904
905     if ((wmld = MMDRV_Get((HANDLE)uDeviceID, MMDRV_MIXER, TRUE)) == NULL)
906         return MMSYSERR_BADDEVICEID;
907
908     return MMDRV_Message(wmld, MXDM_GETDEVCAPS, (DWORD_PTR)lpCaps, uSize);
909 }
910
911 static void CALLBACK MIXER_WCallback(HMIXEROBJ hmx, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam, DWORD_PTR param2)
912 {
913     HWND hWnd = (HWND)dwInstance;
914
915     if (!dwInstance)
916         return;
917
918     PostMessageW(hWnd, uMsg, (WPARAM)hmx, (LPARAM)dwParam);
919 }
920
921 /**************************************************************************
922  *                              mixerOpen                       [WINMM.@]
923  */
924 UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback,
925                       DWORD_PTR dwInstance, DWORD fdwOpen)
926 {
927     HANDLE              hMix;
928     LPWINE_MLD          wmld;
929     DWORD               dwRet;
930     MIXEROPENDESC       mod;
931
932     TRACE("(%p, %d, %08lx, %08lx, %08x)\n",
933           lphMix, uDeviceID, dwCallback, dwInstance, fdwOpen);
934
935     dwRet = WINMM_CheckCallback(dwCallback, fdwOpen, TRUE);
936     if (dwRet != MMSYSERR_NOERROR)
937         return dwRet;
938
939     mod.dwCallback = (DWORD_PTR)MIXER_WCallback;
940     if ((fdwOpen & CALLBACK_TYPEMASK) == CALLBACK_WINDOW)
941         mod.dwInstance = dwCallback;
942     else
943         mod.dwInstance = 0;
944
945     /* We're remapping to CALLBACK_FUNCTION because that's what old winmm is
946      * documented to do when opening the mixer driver.
947      * FIXME: Native supports CALLBACK_EVENT + CALLBACK_THREAD flags since w2k.
948      * FIXME: The non ALSA drivers ignore callback requests - bug.
949      */
950
951     wmld = MMDRV_Alloc(sizeof(WINE_MIXER), MMDRV_MIXER, &hMix, &fdwOpen,
952                        &dwCallback, &dwInstance);
953     wmld->uDeviceID = uDeviceID;
954     mod.hmx = hMix;
955
956     dwRet = MMDRV_Open(wmld, MXDM_OPEN, (DWORD_PTR)&mod, CALLBACK_FUNCTION);
957
958     if (dwRet != MMSYSERR_NOERROR) {
959         MMDRV_Free(hMix, wmld);
960         hMix = 0;
961     }
962     if (lphMix) *lphMix = hMix;
963     TRACE("=> %d hMixer=%p\n", dwRet, hMix);
964
965     return dwRet;
966 }
967
968 /**************************************************************************
969  *                              mixerClose                      [WINMM.@]
970  */
971 UINT WINAPI mixerClose(HMIXER hMix)
972 {
973     LPWINE_MLD          wmld;
974     DWORD               dwRet;
975
976     TRACE("(%p)\n", hMix);
977
978     if ((wmld = MMDRV_Get(hMix, MMDRV_MIXER, FALSE)) == NULL) return MMSYSERR_INVALHANDLE;
979
980     dwRet = MMDRV_Close(wmld, MXDM_CLOSE);
981     MMDRV_Free(hMix, wmld);
982
983     return dwRet;
984 }
985
986 /**************************************************************************
987  *                              mixerGetID                      [WINMM.@]
988  */
989 UINT WINAPI mixerGetID(HMIXEROBJ hmix, LPUINT lpid, DWORD fdwID)
990 {
991     LPWINE_MIXER        lpwm;
992     UINT                uRet = MMSYSERR_NOERROR;
993
994     TRACE("(%p %p %08x)\n", hmix, lpid, fdwID);
995
996     if ((uRet = MIXER_GetDev(hmix, fdwID, &lpwm)) != MMSYSERR_NOERROR)
997         return uRet;
998
999     if (lpid)
1000       *lpid = lpwm->mld.uDeviceID;
1001
1002     return uRet;
1003 }
1004
1005 /**************************************************************************
1006  *                              mixerGetControlDetailsW         [WINMM.@]
1007  */
1008 UINT WINAPI mixerGetControlDetailsW(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdW,
1009                                     DWORD fdwDetails)
1010 {
1011     LPWINE_MIXER        lpwm;
1012     UINT                uRet = MMSYSERR_NOERROR;
1013
1014     TRACE("(%p, %p, %08x)\n", hmix, lpmcdW, fdwDetails);
1015
1016     if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR)
1017         return uRet;
1018
1019     if (lpmcdW == NULL || lpmcdW->cbStruct != sizeof(*lpmcdW))
1020         return MMSYSERR_INVALPARAM;
1021
1022     return MMDRV_Message(&lpwm->mld, MXDM_GETCONTROLDETAILS, (DWORD_PTR)lpmcdW,
1023                          fdwDetails);
1024 }
1025
1026 /**************************************************************************
1027  *                              mixerGetControlDetailsA [WINMM.@]
1028  */
1029 UINT WINAPI mixerGetControlDetailsA(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcdA,
1030                                     DWORD fdwDetails)
1031 {
1032     DWORD                       ret = MMSYSERR_NOTENABLED;
1033
1034     TRACE("(%p, %p, %08x)\n", hmix, lpmcdA, fdwDetails);
1035
1036     if (lpmcdA == NULL || lpmcdA->cbStruct != sizeof(*lpmcdA))
1037         return MMSYSERR_INVALPARAM;
1038
1039     switch (fdwDetails & MIXER_GETCONTROLDETAILSF_QUERYMASK) {
1040     case MIXER_GETCONTROLDETAILSF_VALUE:
1041         /* can safely use A structure as it is, no string inside */
1042         ret = mixerGetControlDetailsW(hmix, lpmcdA, fdwDetails);
1043         break;
1044     case MIXER_GETCONTROLDETAILSF_LISTTEXT:
1045         {
1046             MIXERCONTROLDETAILS_LISTTEXTA *pDetailsA = lpmcdA->paDetails;
1047             MIXERCONTROLDETAILS_LISTTEXTW *pDetailsW;
1048             int size = max(1, lpmcdA->cChannels) * sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
1049             unsigned int i;
1050
1051             if (lpmcdA->u.cMultipleItems != 0) {
1052                 size *= lpmcdA->u.cMultipleItems;
1053             }
1054             pDetailsW = HeapAlloc(GetProcessHeap(), 0, size);
1055             lpmcdA->paDetails = pDetailsW;
1056             lpmcdA->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
1057             /* set up lpmcd->paDetails */
1058             ret = mixerGetControlDetailsW(hmix, lpmcdA, fdwDetails);
1059             /* copy from lpmcd->paDetails back to paDetailsW; */
1060             if (ret == MMSYSERR_NOERROR) {
1061                 for (i = 0; i < lpmcdA->u.cMultipleItems * lpmcdA->cChannels; i++) {
1062                     pDetailsA->dwParam1 = pDetailsW->dwParam1;
1063                     pDetailsA->dwParam2 = pDetailsW->dwParam2;
1064                     WideCharToMultiByte( CP_ACP, 0, pDetailsW->szName, -1,
1065                                          pDetailsA->szName,
1066                                          sizeof(pDetailsA->szName), NULL, NULL );
1067                     pDetailsA++;
1068                     pDetailsW++;
1069                 }
1070                 pDetailsA -= lpmcdA->u.cMultipleItems * lpmcdA->cChannels;
1071                 pDetailsW -= lpmcdA->u.cMultipleItems * lpmcdA->cChannels;
1072             }
1073             HeapFree(GetProcessHeap(), 0, pDetailsW);
1074             lpmcdA->paDetails = pDetailsA;
1075             lpmcdA->cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTA);
1076         }
1077         break;
1078     default:
1079         ERR("Unsupported fdwDetails=0x%08x\n", fdwDetails);
1080     }
1081
1082     return ret;
1083 }
1084
1085 /**************************************************************************
1086  *                              mixerGetLineControlsA   [WINMM.@]
1087  */
1088 UINT WINAPI mixerGetLineControlsA(HMIXEROBJ hmix, LPMIXERLINECONTROLSA lpmlcA,
1089                                   DWORD fdwControls)
1090 {
1091     MIXERLINECONTROLSW  mlcW;
1092     DWORD               ret;
1093     unsigned int        i;
1094
1095     TRACE("(%p, %p, %08x)\n", hmix, lpmlcA, fdwControls);
1096
1097     if (lpmlcA == NULL || lpmlcA->cbStruct != sizeof(*lpmlcA) ||
1098         lpmlcA->cbmxctrl != sizeof(MIXERCONTROLA))
1099         return MMSYSERR_INVALPARAM;
1100
1101     mlcW.cbStruct = sizeof(mlcW);
1102     mlcW.dwLineID = lpmlcA->dwLineID;
1103     mlcW.u.dwControlID = lpmlcA->u.dwControlID;
1104     mlcW.u.dwControlType = lpmlcA->u.dwControlType;
1105
1106     /* Debugging on Windows shows for MIXER_GETLINECONTROLSF_ONEBYTYPE only,
1107        the control count is assumed to be 1 - This is relied upon by a game,
1108        "Dynomite Deluze"                                                    */
1109     if (MIXER_GETLINECONTROLSF_ONEBYTYPE == (fdwControls & MIXER_GETLINECONTROLSF_QUERYMASK)) {
1110         mlcW.cControls = 1;
1111     } else {
1112         mlcW.cControls = lpmlcA->cControls;
1113     }
1114     mlcW.cbmxctrl = sizeof(MIXERCONTROLW);
1115     mlcW.pamxctrl = HeapAlloc(GetProcessHeap(), 0,
1116                               mlcW.cControls * mlcW.cbmxctrl);
1117
1118     ret = mixerGetLineControlsW(hmix, &mlcW, fdwControls);
1119
1120     if (ret == MMSYSERR_NOERROR) {
1121         lpmlcA->dwLineID = mlcW.dwLineID;
1122         lpmlcA->u.dwControlID = mlcW.u.dwControlID;
1123         lpmlcA->u.dwControlType = mlcW.u.dwControlType;
1124
1125         for (i = 0; i < mlcW.cControls; i++) {
1126             lpmlcA->pamxctrl[i].cbStruct = sizeof(MIXERCONTROLA);
1127             lpmlcA->pamxctrl[i].dwControlID = mlcW.pamxctrl[i].dwControlID;
1128             lpmlcA->pamxctrl[i].dwControlType = mlcW.pamxctrl[i].dwControlType;
1129             lpmlcA->pamxctrl[i].fdwControl = mlcW.pamxctrl[i].fdwControl;
1130             lpmlcA->pamxctrl[i].cMultipleItems = mlcW.pamxctrl[i].cMultipleItems;
1131             WideCharToMultiByte( CP_ACP, 0, mlcW.pamxctrl[i].szShortName, -1,
1132                                  lpmlcA->pamxctrl[i].szShortName,
1133                                  sizeof(lpmlcA->pamxctrl[i].szShortName), NULL, NULL );
1134             WideCharToMultiByte( CP_ACP, 0, mlcW.pamxctrl[i].szName, -1,
1135                                  lpmlcA->pamxctrl[i].szName,
1136                                  sizeof(lpmlcA->pamxctrl[i].szName), NULL, NULL );
1137             /* sizeof(lpmlcA->pamxctrl[i].Bounds) ==
1138              * sizeof(mlcW.pamxctrl[i].Bounds) */
1139             memcpy(&lpmlcA->pamxctrl[i].Bounds, &mlcW.pamxctrl[i].Bounds,
1140                    sizeof(mlcW.pamxctrl[i].Bounds));
1141             /* sizeof(lpmlcA->pamxctrl[i].Metrics) ==
1142              * sizeof(mlcW.pamxctrl[i].Metrics) */
1143             memcpy(&lpmlcA->pamxctrl[i].Metrics, &mlcW.pamxctrl[i].Metrics,
1144                    sizeof(mlcW.pamxctrl[i].Metrics));
1145         }
1146     }
1147
1148     HeapFree(GetProcessHeap(), 0, mlcW.pamxctrl);
1149
1150     return ret;
1151 }
1152
1153 /**************************************************************************
1154  *                              mixerGetLineControlsW           [WINMM.@]
1155  */
1156 UINT WINAPI mixerGetLineControlsW(HMIXEROBJ hmix, LPMIXERLINECONTROLSW lpmlcW,
1157                                   DWORD fdwControls)
1158 {
1159     LPWINE_MIXER        lpwm;
1160     UINT                uRet = MMSYSERR_NOERROR;
1161
1162     TRACE("(%p, %p, %08x)\n", hmix, lpmlcW, fdwControls);
1163
1164     if ((uRet = MIXER_GetDev(hmix, fdwControls, &lpwm)) != MMSYSERR_NOERROR)
1165         return uRet;
1166
1167     if (lpmlcW == NULL || lpmlcW->cbStruct != sizeof(*lpmlcW))
1168         return MMSYSERR_INVALPARAM;
1169
1170     return MMDRV_Message(&lpwm->mld, MXDM_GETLINECONTROLS, (DWORD_PTR)lpmlcW,
1171                          fdwControls);
1172 }
1173
1174 /**************************************************************************
1175  *                              mixerGetLineInfoW               [WINMM.@]
1176  */
1177 UINT WINAPI mixerGetLineInfoW(HMIXEROBJ hmix, LPMIXERLINEW lpmliW, DWORD fdwInfo)
1178 {
1179     LPWINE_MIXER        lpwm;
1180     UINT                uRet = MMSYSERR_NOERROR;
1181
1182     TRACE("(%p, %p, %08x)\n", hmix, lpmliW, fdwInfo);
1183
1184     if ((uRet = MIXER_GetDev(hmix, fdwInfo, &lpwm)) != MMSYSERR_NOERROR)
1185         return uRet;
1186
1187     return MMDRV_Message(&lpwm->mld, MXDM_GETLINEINFO, (DWORD_PTR)lpmliW,
1188                          fdwInfo);
1189 }
1190
1191 /**************************************************************************
1192  *                              mixerGetLineInfoA               [WINMM.@]
1193  */
1194 UINT WINAPI mixerGetLineInfoA(HMIXEROBJ hmix, LPMIXERLINEA lpmliA,
1195                               DWORD fdwInfo)
1196 {
1197     MIXERLINEW          mliW;
1198     UINT                ret;
1199
1200     TRACE("(%p, %p, %08x)\n", hmix, lpmliA, fdwInfo);
1201
1202     if (lpmliA == NULL || lpmliA->cbStruct != sizeof(*lpmliA))
1203         return MMSYSERR_INVALPARAM;
1204
1205     mliW.cbStruct = sizeof(mliW);
1206     switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
1207     case MIXER_GETLINEINFOF_COMPONENTTYPE:
1208         mliW.dwComponentType = lpmliA->dwComponentType;
1209         break;
1210     case MIXER_GETLINEINFOF_DESTINATION:
1211         mliW.dwDestination = lpmliA->dwDestination;
1212         break;
1213     case MIXER_GETLINEINFOF_LINEID:
1214         mliW.dwLineID = lpmliA->dwLineID;
1215         break;
1216     case MIXER_GETLINEINFOF_SOURCE:
1217         mliW.dwDestination = lpmliA->dwDestination;
1218         mliW.dwSource = lpmliA->dwSource;
1219         break;
1220     case MIXER_GETLINEINFOF_TARGETTYPE:
1221         mliW.Target.dwType = lpmliA->Target.dwType;
1222         mliW.Target.wMid = lpmliA->Target.wMid;
1223         mliW.Target.wPid = lpmliA->Target.wPid;
1224         mliW.Target.vDriverVersion = lpmliA->Target.vDriverVersion;
1225         MultiByteToWideChar( CP_ACP, 0, lpmliA->Target.szPname, -1, mliW.Target.szPname, sizeof(mliW.Target.szPname)/sizeof(WCHAR));
1226         break;
1227     default:
1228         WARN("Unsupported fdwControls=0x%08x\n", fdwInfo);
1229         return MMSYSERR_INVALFLAG;
1230     }
1231
1232     ret = mixerGetLineInfoW(hmix, &mliW, fdwInfo);
1233
1234     if(ret == MMSYSERR_NOERROR)
1235     {
1236         lpmliA->dwDestination = mliW.dwDestination;
1237         lpmliA->dwSource = mliW.dwSource;
1238         lpmliA->dwLineID = mliW.dwLineID;
1239         lpmliA->fdwLine = mliW.fdwLine;
1240         lpmliA->dwUser = mliW.dwUser;
1241         lpmliA->dwComponentType = mliW.dwComponentType;
1242         lpmliA->cChannels = mliW.cChannels;
1243         lpmliA->cConnections = mliW.cConnections;
1244         lpmliA->cControls = mliW.cControls;
1245         WideCharToMultiByte( CP_ACP, 0, mliW.szShortName, -1, lpmliA->szShortName,
1246                              sizeof(lpmliA->szShortName), NULL, NULL);
1247         WideCharToMultiByte( CP_ACP, 0, mliW.szName, -1, lpmliA->szName,
1248                              sizeof(lpmliA->szName), NULL, NULL );
1249         lpmliA->Target.dwType = mliW.Target.dwType;
1250         lpmliA->Target.dwDeviceID = mliW.Target.dwDeviceID;
1251         lpmliA->Target.wMid = mliW.Target.wMid;
1252         lpmliA->Target.wPid = mliW.Target.wPid;
1253         lpmliA->Target.vDriverVersion = mliW.Target.vDriverVersion;
1254         WideCharToMultiByte( CP_ACP, 0, mliW.Target.szPname, -1, lpmliA->Target.szPname,
1255                              sizeof(lpmliA->Target.szPname), NULL, NULL );
1256     }
1257     return ret;
1258 }
1259
1260 /**************************************************************************
1261  *                              mixerSetControlDetails  [WINMM.@]
1262  */
1263 UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd,
1264                                    DWORD fdwDetails)
1265 {
1266     LPWINE_MIXER        lpwm;
1267     UINT                uRet = MMSYSERR_NOERROR;
1268
1269     TRACE("(%p, %p, %08x)\n", hmix, lpmcd, fdwDetails);
1270
1271     if ((uRet = MIXER_GetDev(hmix, fdwDetails, &lpwm)) != MMSYSERR_NOERROR)
1272         return uRet;
1273
1274     return MMDRV_Message(&lpwm->mld, MXDM_SETCONTROLDETAILS, (DWORD_PTR)lpmcd,
1275                          fdwDetails);
1276 }
1277
1278 /**************************************************************************
1279  *                              mixerMessage            [WINMM.@]
1280  */
1281 DWORD WINAPI mixerMessage(HMIXER hmix, UINT uMsg, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
1282 {
1283     LPWINE_MLD          wmld;
1284
1285     TRACE("(%p, %d, %08lx, %08lx): semi-stub?\n",
1286           hmix, uMsg, dwParam1, dwParam2);
1287
1288     if ((wmld = MMDRV_Get(hmix, MMDRV_MIXER, FALSE)) == NULL)
1289         return MMSYSERR_INVALHANDLE;
1290
1291     return MMDRV_Message(wmld, uMsg, dwParam1, dwParam2);
1292 }